em-http-request 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of em-http-request might be problematic. Click here for more details.

@@ -12,7 +12,6 @@ class HttpClientOptions
12
12
 
13
13
  @method = method.to_s.upcase
14
14
  @headers = options[:head] || {}
15
- @proxy = options[:proxy] || {}
16
15
  @query = options[:query]
17
16
  @path = options[:path]
18
17
 
@@ -45,13 +44,8 @@ class HttpClientOptions
45
44
  @uri.port ||= 80
46
45
  end
47
46
 
48
- if !@proxy.empty?
49
- @host = @proxy[:host]
50
- @port = @proxy[:port]
51
- else
52
- @host = @uri.host
53
- @port = @uri.port
54
- end
47
+ @host = @uri.host
48
+ @port = @uri.port
55
49
 
56
50
  end
57
- end
51
+ end
@@ -1,199 +1,205 @@
1
- module EventMachine
2
-
3
- module HTTPMethods
4
- def get options = {}, &blk; setup_request(:get, options, &blk); end
5
- def head options = {}, &blk; setup_request(:head, options, &blk); end
6
- def delete options = {}, &blk; setup_request(:delete,options, &blk); end
7
- def put options = {}, &blk; setup_request(:put, options, &blk); end
8
- def post options = {}, &blk; setup_request(:post, options, &blk); end
9
- end
10
-
11
- class HttpStubConnection < Connection
12
- include Deferrable
13
- attr_reader :parent
14
-
15
- def parent=(p)
16
- @parent = p
17
- @parent.conn = self
18
- end
19
-
20
- def receive_data(data)
21
- @parent.receive_data data
22
- end
23
-
24
- def connection_completed
25
- @parent.connection_completed
26
- end
27
-
28
- def unbind(reason=nil)
29
- @parent.unbind(reason)
30
- end
31
- end
32
-
33
- class HttpConnection
34
- include HTTPMethods
35
- include Socksify
36
-
37
- attr_reader :deferred
38
- attr_accessor :error, :connopts, :uri, :conn
39
-
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.bind_connect(@connopts.bind, @connopts.bind_port, @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 exception,
68
- # and return a failed deferred which fail any client request at next
69
- # tick. We fail at next tick to keep a consistent API when the newly
70
- # created HttpClient is failed. This approach has the advantage to
71
- # remove a state check of @deferred_status after creating a new
72
- # HttpRequest. The drawback is that users may setup a callback which we
73
- # know won't be used.
74
- #
75
- # Once there is async-DNS, then we'll iterate over the outstanding
76
- # client requests and fail them in order.
77
- #
78
- # Net outcome: failed connection will invoke the same ConnectionError
79
- # message on the connection deferred, and on the client deferred.
80
- #
81
- EM.next_tick{client.close(e.message)}
82
- end
83
- end
84
-
85
- def setup_request(method, options = {}, c = nil)
86
- c ||= HttpClient.new(self, HttpClientOptions.new(@uri, options, method))
87
- @deferred ? activate_connection(c) : finalize_request(c)
88
- c
89
- end
90
-
91
- def finalize_request(c)
92
- @conn.callback { c.connection_completed }
93
-
94
- middleware.each do |m|
95
- c.callback &m.method(:response) if m.respond_to?(:response)
96
- end
97
-
98
- @clients.push c
99
- end
100
-
101
- def middleware
102
- [HttpRequest.middleware, @middleware].flatten
103
- end
104
-
105
- def post_init
106
- @clients = []
107
- @pending = []
108
-
109
- @p = Http::Parser.new
110
- @p.header_value_type = :mixed
111
- @p.on_headers_complete = proc do |h|
112
- client.parse_response_header(h, @p.http_version, @p.status_code)
113
- :reset if client.req.no_body?
114
- end
115
-
116
- @p.on_body = proc do |b|
117
- client.on_body_data(b)
118
- end
119
-
120
- @p.on_message_complete = proc do
121
- if not client.continue?
122
- c = @clients.shift
123
- c.state = :finished
124
- c.on_request_complete
125
- end
126
- end
127
- end
128
-
129
- def use(klass, *args, &block)
130
- @middleware << klass.new(*args, &block)
131
- end
132
-
133
- def peer
134
- Socket.unpack_sockaddr_in(@peer)[1] rescue nil
135
- end
136
-
137
- def receive_data(data)
138
- begin
139
- @p << data
140
- rescue HTTP::Parser::Error => e
141
- c = @clients.shift
142
- c.nil? ? unbind(e.message) : c.on_error(e.message)
143
- end
144
- end
145
-
146
- def connection_completed
147
- @peer = @conn.get_peername
148
-
149
- if @connopts.proxy && @connopts.proxy[:type] == :socks5
150
- socksify(client.req.uri.host, client.req.uri.port, *@connopts.proxy[:authorization]) { start }
151
- else
152
- start
153
- end
154
- end
155
-
156
- def start
157
- @conn.start_tls(@connopts.tls) if client && client.req.ssl?
158
- @conn.succeed
159
- end
160
-
161
- def redirect(client)
162
- @pending.push client
163
- end
164
-
165
- def unbind(reason)
166
- @clients.map { |c| c.unbind(reason) }
167
-
168
- if r = @pending.shift
169
- @clients.push r
170
-
171
- r.reset!
172
- @p.reset!
173
-
174
- begin
175
- @conn.set_deferred_status :unknown
176
- @conn.reconnect(r.req.host, r.req.port)
177
- @conn.callback { r.connection_completed }
178
- rescue EventMachine::ConnectionError => e
179
- @clients.pop.close(e.message)
180
- end
181
- end
182
- end
183
- alias :close :unbind
184
-
185
- def send_data(data)
186
- @conn.send_data data
187
- end
188
-
189
- def stream_file_data(filename, args = {})
190
- @conn.stream_file_data filename, args
191
- end
192
-
193
- private
194
-
195
- def client
196
- @clients.first
197
- end
198
- end
199
- end
1
+ module EventMachine
2
+
3
+ module HTTPMethods
4
+ def get options = {}, &blk; setup_request(:get, options, &blk); end
5
+ def head options = {}, &blk; setup_request(:head, options, &blk); end
6
+ def delete options = {}, &blk; setup_request(:delete,options, &blk); end
7
+ def put options = {}, &blk; setup_request(:put, options, &blk); end
8
+ def post options = {}, &blk; setup_request(:post, options, &blk); end
9
+ end
10
+
11
+ class HttpStubConnection < Connection
12
+ include Deferrable
13
+ attr_reader :parent
14
+
15
+ def parent=(p)
16
+ @parent = p
17
+ @parent.conn = self
18
+ end
19
+
20
+ def receive_data(data)
21
+ @parent.receive_data data
22
+ end
23
+
24
+ def connection_completed
25
+ @parent.connection_completed
26
+ end
27
+
28
+ def unbind(reason=nil)
29
+ @parent.unbind(reason)
30
+ end
31
+ end
32
+
33
+ class HttpConnection
34
+ include HTTPMethods
35
+ include Socksify
36
+
37
+ attr_reader :deferred
38
+ attr_accessor :error, :connopts, :uri, :conn
39
+
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.bind_connect(@connopts.bind, @connopts.bind_port, @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 exception,
68
+ # and return a failed deferred which fail any client request at next
69
+ # tick. We fail at next tick to keep a consistent API when the newly
70
+ # created HttpClient is failed. This approach has the advantage to
71
+ # remove a state check of @deferred_status after creating a new
72
+ # HttpRequest. The drawback is that users may setup a callback which we
73
+ # know won't be used.
74
+ #
75
+ # Once there is async-DNS, then we'll iterate over the outstanding
76
+ # client requests and fail them in order.
77
+ #
78
+ # Net outcome: failed connection will invoke the same ConnectionError
79
+ # message on the connection deferred, and on the client deferred.
80
+ #
81
+ EM.next_tick{client.close(e.message)}
82
+ end
83
+ end
84
+
85
+ def setup_request(method, options = {}, c = nil)
86
+ c ||= HttpClient.new(self, HttpClientOptions.new(@uri, options, method))
87
+ @deferred ? activate_connection(c) : finalize_request(c)
88
+ c
89
+ end
90
+
91
+ def finalize_request(c)
92
+ @conn.callback { c.connection_completed }
93
+
94
+ middleware.each do |m|
95
+ c.callback &m.method(:response) if m.respond_to?(:response)
96
+ end
97
+
98
+ @clients.push c
99
+ end
100
+
101
+ def middleware
102
+ [HttpRequest.middleware, @middleware].flatten
103
+ end
104
+
105
+ def post_init
106
+ @clients = []
107
+ @pending = []
108
+
109
+ @p = Http::Parser.new
110
+ @p.header_value_type = :mixed
111
+ @p.on_headers_complete = proc do |h|
112
+ client.parse_response_header(h, @p.http_version, @p.status_code)
113
+ :reset if client.req.no_body?
114
+ end
115
+
116
+ @p.on_body = proc do |b|
117
+ client.on_body_data(b)
118
+ end
119
+
120
+ @p.on_message_complete = proc do
121
+ if not client.continue?
122
+ c = @clients.shift
123
+ c.state = :finished
124
+ c.on_request_complete
125
+ end
126
+ end
127
+ end
128
+
129
+ def use(klass, *args, &block)
130
+ @middleware << klass.new(*args, &block)
131
+ end
132
+
133
+ def peer
134
+ Socket.unpack_sockaddr_in(@peer)[1] rescue nil
135
+ end
136
+
137
+ def receive_data(data)
138
+ begin
139
+ @p << data
140
+ rescue HTTP::Parser::Error => e
141
+ c = @clients.shift
142
+ c.nil? ? unbind(e.message) : c.on_error(e.message)
143
+ end
144
+ end
145
+
146
+ def connection_completed
147
+ @peer = @conn.get_peername
148
+
149
+ if @connopts.proxy && @connopts.proxy[:type] == :socks5
150
+ socksify(client.req.uri.host, client.req.uri.port, *@connopts.proxy[:authorization]) { start }
151
+ else
152
+ start
153
+ end
154
+ end
155
+
156
+ def start
157
+ @conn.start_tls(@connopts.tls) if client && client.req.ssl?
158
+ @conn.succeed
159
+ end
160
+
161
+ def redirect(client)
162
+ @pending.push client
163
+ end
164
+
165
+ def unbind(reason)
166
+ @clients.map { |c| c.unbind(reason) }
167
+
168
+ if r = @pending.shift
169
+ @clients.push r
170
+
171
+ r.reset!
172
+ @p.reset!
173
+
174
+ begin
175
+ @conn.set_deferred_status :unknown
176
+
177
+ if @connopts.proxy
178
+ @conn.reconnect(@connopts.host, @connopts.port)
179
+ else
180
+ @conn.reconnect(r.req.host, r.req.port)
181
+ end
182
+
183
+ @conn.callback { r.connection_completed }
184
+ rescue EventMachine::ConnectionError => e
185
+ @clients.pop.close(e.message)
186
+ end
187
+ end
188
+ end
189
+ alias :close :unbind
190
+
191
+ def send_data(data)
192
+ @conn.send_data data
193
+ end
194
+
195
+ def stream_file_data(filename, args = {})
196
+ @conn.stream_file_data filename, args
197
+ end
198
+
199
+ private
200
+
201
+ def client
202
+ @clients.first
203
+ end
204
+ end
205
+ end
@@ -1,5 +1,5 @@
1
1
  module EventMachine
2
2
  class HttpRequest
3
- VERSION = "1.0.1"
3
+ VERSION = "1.0.2"
4
4
  end
5
5
  end
@@ -3,19 +3,21 @@ require 'fiber'
3
3
 
4
4
  describe EventMachine::HttpRequest do
5
5
  context "with fibers" do
6
- it "should be transparent to connexion errors" do
6
+
7
+ it "should be transparent to connection errors" do
7
8
  EventMachine.run do
8
9
  Fiber.new do
9
10
  f = Fiber.current
10
- http = EventMachine::HttpRequest.new('http://non-existing.domain/').get
11
- http.callback {failed(http)}
12
- http.errback {f.resume}
13
- Fiber.yield
14
- EventMachine.stop
11
+ fired = false
12
+ http = EventMachine::HttpRequest.new('http://non-existing.domain/', :connection_timeout => 0.1).get
13
+ http.callback { failed(http) }
14
+ http.errback { f.resume :errback }
15
+
16
+ Fiber.yield.should == :errback
17
+ EM.stop
15
18
  end.resume
16
19
  end
17
20
  end
21
+
18
22
  end
19
23
  end
20
-
21
-