em-http-request 1.0.0.beta.3 → 1.0.0.beta.4
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of em-http-request might be problematic. Click here for more details.
- data/.gemtest +0 -0
- data/Gemfile +12 -1
- data/README.md +2 -2
- data/Rakefile +2 -1
- data/benchmarks/clients.rb +156 -0
- data/benchmarks/em-excon.rb +87 -0
- data/benchmarks/em-profile.gif +0 -0
- data/benchmarks/em-profile.txt +65 -0
- data/benchmarks/server.rb +48 -0
- data/em-http-request.gemspec +2 -1
- data/examples/.gitignore +1 -0
- data/examples/fibered-http.rb +10 -6
- data/examples/oauth-tweet.rb +22 -37
- data/lib/em-http.rb +3 -2
- data/lib/em-http/client.rb +52 -37
- data/lib/em-http/decoders.rb +1 -1
- data/lib/em-http/http_client_options.rb +56 -0
- data/lib/em-http/http_connection.rb +97 -41
- data/lib/em-http/http_connection_options.rb +23 -0
- data/lib/em-http/http_encoding.rb +1 -1
- data/lib/em-http/middleware/cookie_jar.rb +38 -0
- data/lib/em-http/middleware/json_response.rb +15 -0
- data/lib/em-http/middleware/oauth.rb +21 -0
- data/lib/em-http/multi.rb +18 -18
- data/lib/em-http/request.rb +7 -29
- data/lib/em-http/version.rb +1 -1
- data/spec/client_spec.rb +39 -0
- data/spec/external_spec.rb +17 -1
- data/spec/helper.rb +12 -0
- data/spec/middleware_spec.rb +85 -7
- data/spec/multi_spec.rb +77 -22
- data/spec/pipelining_spec.rb +1 -1
- data/spec/redirect_spec.rb +86 -0
- data/spec/socksify_proxy_spec.rb +14 -14
- data/spec/stallion.rb +33 -2
- metadata +28 -6
- data/lib/em-http/http_options.rb +0 -53
data/examples/oauth-tweet.rb
CHANGED
@@ -1,50 +1,35 @@
|
|
1
|
-
|
2
|
-
# http://gist.github.com/265261
|
3
|
-
#
|
4
|
-
|
5
|
-
require 'rubygems'
|
1
|
+
$: << 'lib' << '../lib'
|
6
2
|
|
7
3
|
require 'em-http'
|
8
|
-
require 'oauth'
|
9
|
-
|
10
|
-
# At a minimum, require 'oauth/request_proxy/em_http_request'
|
11
|
-
# for this example, we'll use Net::HTTP like support.
|
12
|
-
require 'oauth/client/em_http'
|
4
|
+
require 'em-http/middleware/oauth'
|
5
|
+
require 'em-http/middleware/json_response'
|
13
6
|
|
14
|
-
|
15
|
-
# You need to generate an access token, I suggest looking elsewhere how to do that or wait for a full tutorial.
|
16
|
-
# For a consumer key / consumer secret, signup for an app at:
|
17
|
-
# http://twitter.com/apps/new
|
7
|
+
require 'pp'
|
18
8
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def twitter_oauth_consumer
|
26
|
-
@twitter_oauth_consumer ||= OAuth::Consumer.new(CONSUMER_KEY, CONSUMER_SECRET, :site => "http://twitter.com")
|
27
|
-
end
|
28
|
-
|
29
|
-
def twitter_oauth_access_token
|
30
|
-
@twitter_oauth_access_token ||= OAuth::AccessToken.new(twitter_oauth_consumer, ACCESS_TOKEN, ACCESS_TOKEN_SECRET)
|
31
|
-
end
|
9
|
+
OAuthConfig = {
|
10
|
+
:consumer_key => '',
|
11
|
+
:consumer_secret => '',
|
12
|
+
:access_token => '',
|
13
|
+
:access_token_secret => ''
|
14
|
+
}
|
32
15
|
|
33
16
|
EM.run do
|
17
|
+
# automatically parse the JSON response into a Ruby object
|
18
|
+
EventMachine::HttpRequest.use EventMachine::Middleware::JSONResponse
|
34
19
|
|
35
|
-
request
|
36
|
-
|
37
|
-
|
38
|
-
end
|
20
|
+
# sign the request with OAuth credentials
|
21
|
+
conn = EventMachine::HttpRequest.new('http://api.twitter.com/1/statuses/home_timeline.json')
|
22
|
+
conn.use EventMachine::Middleware::OAuth, OAuthConfig
|
39
23
|
|
24
|
+
http = conn.get
|
40
25
|
http.callback do
|
41
|
-
|
42
|
-
EM.
|
26
|
+
pp http.response
|
27
|
+
EM.stop
|
43
28
|
end
|
44
29
|
|
45
30
|
http.errback do
|
46
|
-
puts "Failed
|
47
|
-
|
31
|
+
puts "Failed retrieving user stream."
|
32
|
+
pp http.response
|
33
|
+
EM.stop
|
48
34
|
end
|
49
|
-
|
50
|
-
end
|
35
|
+
end
|
data/lib/em-http.rb
CHANGED
@@ -10,8 +10,9 @@ require 'em-http/core_ext/bytesize'
|
|
10
10
|
require 'em-http/http_connection'
|
11
11
|
require 'em-http/http_header'
|
12
12
|
require 'em-http/http_encoding'
|
13
|
-
require 'em-http/
|
13
|
+
require 'em-http/http_client_options'
|
14
|
+
require 'em-http/http_connection_options'
|
14
15
|
require 'em-http/client'
|
15
16
|
require 'em-http/multi'
|
16
17
|
require 'em-http/request'
|
17
|
-
require 'em-http/decoders'
|
18
|
+
require 'em-http/decoders'
|
data/lib/em-http/client.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
module EventMachine
|
2
|
+
|
2
3
|
class HttpClient
|
3
4
|
include Deferrable
|
4
5
|
include HttpEncoding
|
@@ -17,17 +18,15 @@ module EventMachine
|
|
17
18
|
CRLF="\r\n"
|
18
19
|
|
19
20
|
attr_accessor :state, :response
|
20
|
-
attr_reader :response_header, :error, :content_charset, :req
|
21
|
+
attr_reader :response_header, :error, :content_charset, :req, :cookies
|
21
22
|
|
22
|
-
def initialize(conn,
|
23
|
+
def initialize(conn, options)
|
23
24
|
@conn = conn
|
24
|
-
|
25
|
-
@req = req
|
26
|
-
@method = req.method
|
27
|
-
@options = options
|
25
|
+
@req = options
|
28
26
|
|
29
27
|
@stream = nil
|
30
28
|
@headers = nil
|
29
|
+
@cookies = []
|
31
30
|
|
32
31
|
reset!
|
33
32
|
end
|
@@ -43,14 +42,15 @@ module EventMachine
|
|
43
42
|
end
|
44
43
|
|
45
44
|
def last_effective_url; @req.uri; end
|
46
|
-
def redirects; @req.
|
45
|
+
def redirects; @req.followed; end
|
46
|
+
def peer; @conn.peer; end
|
47
47
|
|
48
48
|
def connection_completed
|
49
49
|
@state = :response_header
|
50
50
|
|
51
|
-
head, body = build_request, @
|
51
|
+
head, body = build_request, @req.body
|
52
52
|
@conn.middleware.each do |m|
|
53
|
-
head, body = m.request(head, body) if m.respond_to?(:request)
|
53
|
+
head, body = m.request(self, head, body) if m.respond_to?(:request)
|
54
54
|
end
|
55
55
|
|
56
56
|
send_request(head, body)
|
@@ -66,6 +66,10 @@ module EventMachine
|
|
66
66
|
unbind
|
67
67
|
end
|
68
68
|
|
69
|
+
def continue?
|
70
|
+
@response_header.status == 100 && (@req.method == 'POST' || @req.method == 'PUT')
|
71
|
+
end
|
72
|
+
|
69
73
|
def finished?
|
70
74
|
@state == :finished || (@state == :body && @response_header.content_length.nil?)
|
71
75
|
end
|
@@ -77,8 +81,26 @@ module EventMachine
|
|
77
81
|
def unbind
|
78
82
|
if finished?
|
79
83
|
if redirect?
|
80
|
-
|
81
|
-
|
84
|
+
|
85
|
+
begin
|
86
|
+
@conn.middleware.each do |m|
|
87
|
+
m.response(self) if m.respond_to?(:response)
|
88
|
+
end
|
89
|
+
|
90
|
+
# one of the injected middlewares could have changed
|
91
|
+
# our redirect settings, check if we still want to
|
92
|
+
# follow the location header
|
93
|
+
if redirect?
|
94
|
+
@req.followed += 1
|
95
|
+
@req.set_uri(@response_header.location)
|
96
|
+
@conn.redirect(self)
|
97
|
+
else
|
98
|
+
succeed(self)
|
99
|
+
end
|
100
|
+
|
101
|
+
rescue Exception => e
|
102
|
+
on_error(e.message)
|
103
|
+
end
|
82
104
|
else
|
83
105
|
succeed(self)
|
84
106
|
end
|
@@ -101,32 +123,22 @@ module EventMachine
|
|
101
123
|
body.is_a?(Hash) ? form_encode_body(body) : body
|
102
124
|
end
|
103
125
|
|
104
|
-
def proxy?; !@options[:proxy].nil?; end
|
105
|
-
def http_proxy?; proxy? && [nil, :http].include?(@options[:proxy][:type]); end
|
106
|
-
|
107
|
-
def ssl?; @req.uri.scheme == "https" || @req.uri.port == 443; end
|
108
|
-
|
109
|
-
def continue?
|
110
|
-
@response_header.status == 100 && (@method == 'POST' || @method == 'PUT')
|
111
|
-
end
|
112
|
-
|
113
126
|
def build_request
|
114
|
-
head = @
|
115
|
-
proxy = @
|
127
|
+
head = @req.headers ? munge_header_keys(@req.headers) : {}
|
128
|
+
proxy = @req.proxy
|
116
129
|
|
117
|
-
if http_proxy?
|
118
|
-
|
119
|
-
head = proxy[:head] ? munge_header_keys(proxy[:head]) : {}
|
120
|
-
head['proxy-authorization'] = proxy[:authorization] if proxy[:authorization]
|
130
|
+
if @req.http_proxy?
|
131
|
+
head['proxy-authorization'] = @req.proxy[:authorization] if @req.proxy[:authorization]
|
121
132
|
end
|
122
133
|
|
123
134
|
# Set the cookie header if provided
|
124
|
-
if cookie = head
|
125
|
-
|
135
|
+
if cookie = head['cookie']
|
136
|
+
@cookies << encode_cookie(cookie) if cookie
|
126
137
|
end
|
138
|
+
head['cookie'] = @cookies.compact.uniq.join("; ").squeeze(";") unless @cookies.empty?
|
127
139
|
|
128
140
|
# Set connection close unless keepalive
|
129
|
-
|
141
|
+
if !@req.keepalive
|
130
142
|
head['connection'] = 'close'
|
131
143
|
end
|
132
144
|
|
@@ -141,8 +153,8 @@ module EventMachine
|
|
141
153
|
|
142
154
|
def send_request(head, body)
|
143
155
|
body = normalize_body(body)
|
144
|
-
file = @
|
145
|
-
query = @
|
156
|
+
file = @req.file
|
157
|
+
query = @req.query
|
146
158
|
|
147
159
|
# Set the Content-Length if file is given
|
148
160
|
head['content-length'] = File.size(file) if file
|
@@ -151,19 +163,19 @@ module EventMachine
|
|
151
163
|
head['content-length'] = body.bytesize if body
|
152
164
|
|
153
165
|
# Set content-type header if missing and body is a Ruby hash
|
154
|
-
if not head['content-type'] and @
|
166
|
+
if not head['content-type'] and @req.body.is_a? Hash
|
155
167
|
head['content-type'] = 'application/x-www-form-urlencoded'
|
156
168
|
end
|
157
169
|
|
158
|
-
request_header ||= encode_request(@method, @req.uri, query, @conn.
|
170
|
+
request_header ||= encode_request(@req.method, @req.uri, query, @conn.connopts.proxy)
|
159
171
|
request_header << encode_headers(head)
|
160
172
|
request_header << CRLF
|
161
173
|
@conn.send_data request_header
|
162
174
|
|
163
175
|
if body
|
164
176
|
@conn.send_data body
|
165
|
-
elsif @
|
166
|
-
@conn.stream_file_data @
|
177
|
+
elsif @req.file
|
178
|
+
@conn.stream_file_data @req.file, :http_chunks => false
|
167
179
|
end
|
168
180
|
end
|
169
181
|
|
@@ -207,6 +219,9 @@ module EventMachine
|
|
207
219
|
return
|
208
220
|
end
|
209
221
|
|
222
|
+
# add set-cookie's to cookie list
|
223
|
+
@cookies << @response_header.cookie if @response_header.cookie && @req.pass_cookies
|
224
|
+
|
210
225
|
# correct location header - some servers will incorrectly give a relative URI
|
211
226
|
if @response_header.location
|
212
227
|
begin
|
@@ -229,7 +244,7 @@ module EventMachine
|
|
229
244
|
# Fire callbacks immediately after recieving header requests
|
230
245
|
# if the request method is HEAD. In case of a redirect, terminate
|
231
246
|
# current connection and reinitialize the process.
|
232
|
-
if @method == "HEAD"
|
247
|
+
if @req.method == "HEAD"
|
233
248
|
@state = :finished
|
234
249
|
return
|
235
250
|
end
|
@@ -242,7 +257,7 @@ module EventMachine
|
|
242
257
|
@state = :body
|
243
258
|
end
|
244
259
|
|
245
|
-
if decoder_class = HttpDecoders.decoder_for_encoding(response_header[CONTENT_ENCODING])
|
260
|
+
if @req.decoding && decoder_class = HttpDecoders.decoder_for_encoding(response_header[CONTENT_ENCODING])
|
246
261
|
begin
|
247
262
|
@content_decoder = decoder_class.new do |s| on_decoded_body_data(s) end
|
248
263
|
rescue HttpDecoders::DecoderError
|
data/lib/em-http/decoders.rb
CHANGED
@@ -71,7 +71,7 @@ module EventMachine::HttpDecoders
|
|
71
71
|
class Deflate < Base
|
72
72
|
def decompress(compressed)
|
73
73
|
begin
|
74
|
-
@zstream ||= Zlib::Inflate.new(
|
74
|
+
@zstream ||= Zlib::Inflate.new(-Zlib::MAX_WBITS)
|
75
75
|
@zstream.inflate(compressed)
|
76
76
|
rescue Zlib::Error
|
77
77
|
raise DecoderError
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class HttpClientOptions
|
2
|
+
attr_reader :uri, :method, :host, :port, :proxy
|
3
|
+
attr_reader :headers, :file, :body, :query, :path
|
4
|
+
attr_reader :keepalive, :pass_cookies, :decoding
|
5
|
+
|
6
|
+
attr_accessor :followed, :redirects
|
7
|
+
|
8
|
+
def initialize(uri, options, method)
|
9
|
+
@keepalive = options[:keepalive] || false # default to single request per connection
|
10
|
+
@redirects = options[:redirects] ||= 0 # default number of redirects to follow
|
11
|
+
@followed = options[:followed] ||= 0 # keep track of number of followed requests
|
12
|
+
|
13
|
+
@method = method.to_s.upcase
|
14
|
+
@headers = options[:head] || {}
|
15
|
+
@proxy = options[:proxy] || {}
|
16
|
+
@query = options[:query]
|
17
|
+
@path = options[:path]
|
18
|
+
|
19
|
+
@file = options[:file]
|
20
|
+
@body = options[:body]
|
21
|
+
|
22
|
+
@pass_cookies = options.fetch(:pass_cookies, true) # pass cookies between redirects
|
23
|
+
@decoding = options.fetch(:decoding, true) # auto-decode compressed response
|
24
|
+
|
25
|
+
set_uri(uri)
|
26
|
+
end
|
27
|
+
|
28
|
+
def follow_redirect?; @followed < @redirects; end
|
29
|
+
def http_proxy?; @proxy && [nil, :http].include?(@proxy[:type]); end
|
30
|
+
def ssl?; @uri.scheme == "https" || @uri.port == 443; end
|
31
|
+
|
32
|
+
def set_uri(uri)
|
33
|
+
uri = uri.kind_of?(Addressable::URI) ? uri : Addressable::URI::parse(uri.to_s)
|
34
|
+
uri.path = '/' if uri.path.empty?
|
35
|
+
uri.path = @path if @path
|
36
|
+
|
37
|
+
@uri = uri
|
38
|
+
|
39
|
+
# Make sure the ports are set as Addressable::URI doesn't
|
40
|
+
# set the port if it isn't there
|
41
|
+
if @uri.scheme == "https"
|
42
|
+
@uri.port ||= 443
|
43
|
+
else
|
44
|
+
@uri.port ||= 80
|
45
|
+
end
|
46
|
+
|
47
|
+
if !@proxy.empty?
|
48
|
+
@host = @proxy[:host]
|
49
|
+
@port = @proxy[:port]
|
50
|
+
else
|
51
|
+
@host = @uri.host
|
52
|
+
@port = @uri.port
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
end
|
@@ -8,40 +8,90 @@ module EventMachine
|
|
8
8
|
def post options = {}, &blk; setup_request(:post, options, &blk); end
|
9
9
|
end
|
10
10
|
|
11
|
-
class
|
12
|
-
include HTTPMethods
|
11
|
+
class HttpStubConnection < Connection
|
13
12
|
include Deferrable
|
13
|
+
attr_reader :parent
|
14
14
|
|
15
|
-
|
15
|
+
def parent=(p)
|
16
|
+
@parent = p
|
17
|
+
@parent.conn = self
|
18
|
+
end
|
16
19
|
|
17
|
-
def
|
18
|
-
@
|
20
|
+
def receive_data(data)
|
21
|
+
@parent.receive_data data
|
19
22
|
end
|
20
23
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
def connection_completed
|
25
|
+
@parent.connection_completed
|
26
|
+
end
|
27
|
+
|
28
|
+
def unbind
|
29
|
+
@parent.unbind
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
28
|
-
class HttpConnection
|
33
|
+
class HttpConnection
|
29
34
|
include HTTPMethods
|
30
|
-
include Deferrable
|
31
35
|
include Socksify
|
32
36
|
|
33
|
-
|
37
|
+
attr_reader :deferred
|
38
|
+
attr_accessor :error, :connopts, :uri, :conn
|
34
39
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
40
|
+
def initialize
|
41
|
+
@deferred = true
|
42
|
+
@middleware = []
|
43
|
+
end
|
44
|
+
|
45
|
+
def conn=(c)
|
46
|
+
@conn = c
|
47
|
+
@deferred = false
|
48
|
+
end
|
49
|
+
|
50
|
+
def activate_connection(client)
|
51
|
+
begin
|
52
|
+
EventMachine.connect(@connopts.host, @connopts.port, HttpStubConnection) do |conn|
|
53
|
+
post_init
|
54
|
+
|
55
|
+
@deferred = false
|
56
|
+
@conn = conn
|
57
|
+
|
58
|
+
conn.parent = self
|
59
|
+
conn.pending_connect_timeout = @connopts.connect_timeout
|
60
|
+
conn.comm_inactivity_timeout = @connopts.inactivity_timeout
|
61
|
+
end
|
62
|
+
|
63
|
+
finalize_request(client)
|
64
|
+
rescue EventMachine::ConnectionError => e
|
65
|
+
#
|
66
|
+
# Currently, this can only fire on initial connection setup
|
67
|
+
# since #connect is a synchronous method. Hence, rescue the
|
68
|
+
# exception, and return a failed deferred which will immediately
|
69
|
+
# fail any client request.
|
70
|
+
#
|
71
|
+
# Once there is async-DNS, then we'll iterate over the outstanding
|
72
|
+
# client requests and fail them in order.
|
73
|
+
#
|
74
|
+
# Net outcome: failed connection will invoke the same ConnectionError
|
75
|
+
# message on the connection deferred, and on the client deferred.
|
76
|
+
#
|
77
|
+
client.close(e.message)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def setup_request(method, options = {}, c = nil)
|
82
|
+
c ||= HttpClient.new(self, HttpClientOptions.new(@uri, options, method))
|
83
|
+
@deferred ? activate_connection(c) : finalize_request(c)
|
84
|
+
c
|
85
|
+
end
|
86
|
+
|
87
|
+
def finalize_request(c)
|
88
|
+
@conn.callback { c.connection_completed }
|
38
89
|
|
39
90
|
middleware.each do |m|
|
40
91
|
c.callback &m.method(:response) if m.respond_to?(:response)
|
41
92
|
end
|
42
93
|
|
43
94
|
@clients.push c
|
44
|
-
c
|
45
95
|
end
|
46
96
|
|
47
97
|
def middleware
|
@@ -52,19 +102,17 @@ module EventMachine
|
|
52
102
|
@clients = []
|
53
103
|
@pending = []
|
54
104
|
|
55
|
-
@middleware = []
|
56
|
-
|
57
105
|
@p = Http::Parser.new
|
58
106
|
@p.on_headers_complete = proc do |h|
|
59
|
-
|
107
|
+
client.parse_response_header(h, @p.http_version, @p.status_code)
|
60
108
|
end
|
61
109
|
|
62
110
|
@p.on_body = proc do |b|
|
63
|
-
|
111
|
+
client.on_body_data(b)
|
64
112
|
end
|
65
113
|
|
66
114
|
@p.on_message_complete = proc do
|
67
|
-
if not
|
115
|
+
if not client.continue?
|
68
116
|
c = @clients.shift
|
69
117
|
c.state = :finished
|
70
118
|
c.on_request_complete
|
@@ -72,8 +120,12 @@ module EventMachine
|
|
72
120
|
end
|
73
121
|
end
|
74
122
|
|
75
|
-
def use(klass)
|
76
|
-
@middleware << klass
|
123
|
+
def use(klass, *args, &block)
|
124
|
+
@middleware << klass.new(*args, &block)
|
125
|
+
end
|
126
|
+
|
127
|
+
def peer
|
128
|
+
Socket.unpack_sockaddr_in(@peer)[1] rescue nil
|
77
129
|
end
|
78
130
|
|
79
131
|
def receive_data(data)
|
@@ -81,35 +133,31 @@ module EventMachine
|
|
81
133
|
@p << data
|
82
134
|
rescue HTTP::Parser::Error => e
|
83
135
|
c = @clients.shift
|
84
|
-
c.on_error(e.message)
|
136
|
+
c.nil? ? unbind : c.on_error(e.message)
|
85
137
|
end
|
86
138
|
end
|
87
139
|
|
88
140
|
def connection_completed
|
89
|
-
|
90
|
-
socksify(client.req.uri.host, client.req.uri.port, *@opts.proxy[:authorization]) { start }
|
141
|
+
@peer = @conn.get_peername
|
91
142
|
|
143
|
+
if @connopts.proxy && @connopts.proxy[:type] == :socks5
|
144
|
+
socksify(client.req.uri.host, client.req.uri.port, *@connopts.proxy[:authorization]) { start }
|
92
145
|
else
|
93
146
|
start
|
94
147
|
end
|
95
148
|
end
|
96
149
|
|
97
150
|
def start
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
succeed
|
151
|
+
@conn.start_tls(@connopts.tls) if client && client.req.ssl?
|
152
|
+
@conn.succeed
|
102
153
|
end
|
103
154
|
|
104
|
-
def redirect(client
|
105
|
-
client.req.set_uri(location)
|
155
|
+
def redirect(client)
|
106
156
|
@pending.push client
|
107
|
-
rescue Exception => e
|
108
|
-
client.on_error(e.message)
|
109
157
|
end
|
110
158
|
|
111
159
|
def unbind
|
112
|
-
@clients.map {|c| c.unbind }
|
160
|
+
@clients.map { |c| c.unbind }
|
113
161
|
|
114
162
|
if r = @pending.shift
|
115
163
|
@clients.push r
|
@@ -118,19 +166,27 @@ module EventMachine
|
|
118
166
|
@p.reset!
|
119
167
|
|
120
168
|
begin
|
121
|
-
set_deferred_status :unknown
|
122
|
-
reconnect(r.req.host, r.req.port)
|
123
|
-
callback { r.connection_completed }
|
169
|
+
@conn.set_deferred_status :unknown
|
170
|
+
@conn.reconnect(r.req.host, r.req.port)
|
171
|
+
@conn.callback { r.connection_completed }
|
124
172
|
rescue EventMachine::ConnectionError => e
|
125
173
|
@clients.pop.close(e.message)
|
126
174
|
end
|
127
175
|
end
|
128
176
|
end
|
129
177
|
|
178
|
+
def send_data(data)
|
179
|
+
@conn.send_data data
|
180
|
+
end
|
181
|
+
|
182
|
+
def stream_file_data(filename, args = {})
|
183
|
+
@conn.stream_file_data filename, args
|
184
|
+
end
|
185
|
+
|
130
186
|
private
|
131
187
|
|
132
|
-
|
133
|
-
|
134
|
-
|
188
|
+
def client
|
189
|
+
@clients.first
|
190
|
+
end
|
135
191
|
end
|
136
192
|
end
|