excon 0.30.0 → 0.31.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of excon might be problematic. Click here for more details.

@@ -156,12 +156,14 @@ Shindo.tests('Excon Response Parsing') do
156
156
  tests('Transfer-Encoding') do
157
157
 
158
158
  tests('used with chunked response') do
159
- resp = Excon.post(
160
- 'http://127.0.0.1:9292/echo/transfer-encoded/chunked',
161
- :body => 'hello world'
162
- )
159
+ resp = nil
163
160
 
164
161
  tests('server sent transfer-encoding').returns('gzip, chunked') do
162
+ resp = Excon.post(
163
+ 'http://127.0.0.1:9292/echo/transfer-encoded/chunked',
164
+ :body => 'hello world'
165
+ )
166
+
165
167
  resp[:headers]['Transfer-Encoding-Sent']
166
168
  end
167
169
 
@@ -175,12 +177,14 @@ Shindo.tests('Excon Response Parsing') do
175
177
  end
176
178
 
177
179
  tests('used with non-chunked response') do
178
- resp = Excon.post(
179
- 'http://127.0.0.1:9292/echo/transfer-encoded',
180
- :body => 'hello world'
181
- )
180
+ resp = nil
182
181
 
183
182
  tests('server sent transfer-encoding').returns('gzip') do
183
+ resp = Excon.post(
184
+ 'http://127.0.0.1:9292/echo/transfer-encoded',
185
+ :body => 'hello world'
186
+ )
187
+
184
188
  resp[:headers]['Transfer-Encoding-Sent']
185
189
  end
186
190
 
@@ -195,14 +199,16 @@ Shindo.tests('Excon Response Parsing') do
195
199
 
196
200
  # sends TE header without gzip/deflate accepted (see requests_tests)
197
201
  tests('with a :response_block') do
198
- resp = nil
199
- captures = capture_response_block do |block|
200
- resp = Excon.post('http://127.0.0.1:9292/echo/transfer-encoded/chunked',
201
- :body => 'hello world',
202
- :response_block => block)
203
- end
202
+ captures = nil
204
203
 
205
204
  tests('server does not compress').returns('chunked') do
205
+ resp = nil
206
+ captures = capture_response_block do |block|
207
+ resp = Excon.post('http://127.0.0.1:9292/echo/transfer-encoded/chunked',
208
+ :body => 'hello world',
209
+ :response_block => block)
210
+ end
211
+
206
212
  resp[:headers]['Transfer-Encoding-Sent']
207
213
  end
208
214
 
@@ -17,7 +17,7 @@ module GoodServer
17
17
  #
18
18
  # Each connection to this server is persistent unless the client sends
19
19
  # "Connection: close" in the request. If a response requires the connection
20
- # to be closed, it should set `@persistent = false` and send "Connection: close".
20
+ # to be closed, use `start_response(:persistent => false)`.
21
21
  def send_response(request)
22
22
  type, path = request[:uri].path.split('/', 3)[1, 2]
23
23
  case type
@@ -25,11 +25,18 @@ module GoodServer
25
25
  case path
26
26
  when 'request'
27
27
  data = Marshal.dump(request)
28
- send_data "HTTP/1.1 200 OK\r\n"
28
+ start_response
29
29
  send_data "Content-Length: #{ data.size }\r\n"
30
30
  send_data "\r\n"
31
31
  send_data data
32
32
 
33
+ when 'request_count'
34
+ (@request_count ||= '0').next!
35
+ start_response
36
+ send_data "Content-Length: #{ @request_count.size }\r\n"
37
+ send_data "\r\n"
38
+ send_data @request_count
39
+
33
40
  when /(content|transfer)-encoded\/?(.*)/
34
41
  if (encoding_type = $1) == 'content'
35
42
  accept_header = 'Accept-Encoding'
@@ -70,7 +77,7 @@ module GoodServer
70
77
  end
71
78
  encodings = encodings.compact.join(', ')
72
79
 
73
- send_data "HTTP/1.1 200 OK\r\n"
80
+ start_response
74
81
  # let the test know what the server sent
75
82
  send_data "#{ encoding_header }-Sent: #{ encodings }\r\n"
76
83
  send_data "#{ encoding_header }: #{ encodings }\r\n" unless encodings.empty?
@@ -91,7 +98,7 @@ module GoodServer
91
98
  when 'chunked'
92
99
  case path
93
100
  when 'simple'
94
- send_data "HTTP/1.1 200 OK\r\n"
101
+ start_response
95
102
  send_data "Transfer-Encoding: chunked\r\n"
96
103
  send_data "\r\n"
97
104
  # chunk-extension is currently ignored.
@@ -105,7 +112,7 @@ module GoodServer
105
112
 
106
113
  # merged trailers also support continuations
107
114
  when 'trailers'
108
- send_data "HTTP/1.1 200 OK\r\n"
115
+ start_response
109
116
  send_data "Transfer-Encoding: chunked\r\n"
110
117
  send_data "Test-Header: one, two\r\n"
111
118
  send_data "\r\n"
@@ -118,24 +125,21 @@ module GoodServer
118
125
  when 'content-length'
119
126
  case path
120
127
  when 'simple'
121
- send_data "HTTP/1.1 200 OK\r\n"
128
+ start_response
122
129
  send_data "Content-Length: 11\r\n"
123
130
  send_data "\r\n"
124
131
  send_data "hello world"
125
132
  end
126
133
 
127
134
  when 'unknown'
128
- @persistent = false
129
135
  case path
130
136
  when 'simple'
131
- send_data "HTTP/1.1 200 OK\r\n"
132
- send_data "Connection: close\r\n"
137
+ start_response(:persistent => false)
133
138
  send_data "\r\n"
134
139
  send_data "hello world"
135
140
 
136
141
  when 'header_continuation'
137
- send_data "HTTP/1.1 200 OK\r\n"
138
- send_data "Connection: close\r\n"
142
+ start_response(:persistent => false)
139
143
  send_data "Test-Header: one, two\r\n"
140
144
  send_data "Test-Header: three, four,\r\n"
141
145
  send_data " five, six\r\n"
@@ -147,7 +151,7 @@ module GoodServer
147
151
  # Excon will close these connections due to the errors.
148
152
  case path
149
153
  when 'malformed_header'
150
- send_data "HTTP/1.1 200 OK\r\n"
154
+ start_response
151
155
  send_data "Bad-Header\r\n" # no ':'
152
156
  send_data "\r\n"
153
157
  send_data "hello world"
@@ -159,8 +163,18 @@ module GoodServer
159
163
  send_data "hello world"
160
164
  end
161
165
  end
166
+ end
167
+
168
+ # Sends response status-line, plus headers common to all responses.
169
+ def start_response(opts = {})
170
+ opts = {
171
+ :status => '200 OK',
172
+ :persistent => @persistent # true unless client sent Connection: close
173
+ }.merge!(opts)
162
174
 
163
- close_connection(true) unless @persistent
175
+ @persistent = opts[:persistent]
176
+ send_data "HTTP/1.1 #{ opts[:status] }\r\n"
177
+ send_data "Connection: close\r\n" unless @persistent
164
178
  end
165
179
 
166
180
  def post_init
@@ -173,6 +187,7 @@ module GoodServer
173
187
  # The data is buffered, then processed and removed from the buffer
174
188
  # as data becomes available until the @request is complete.
175
189
  def receive_data(data)
190
+ @buffer.seek(0, IO::SEEK_END)
176
191
  @buffer.write(data)
177
192
 
178
193
  parse_headers unless @request
@@ -180,12 +195,15 @@ module GoodServer
180
195
 
181
196
  if @request_complete
182
197
  send_response(@request)
183
- sync_buffer
184
- @request = nil
185
- @request_complete = false
198
+ if @persistent
199
+ @request = nil
200
+ @request_complete = false
201
+ # process remaining buffer for next request
202
+ receive_data('') unless @buffer.eof?
203
+ else
204
+ close_connection(true)
205
+ end
186
206
  end
187
-
188
- @buffer.seek(0, IO::SEEK_END) # wait for more data
189
207
  end
190
208
 
191
209
  # Removes the processed portion of the buffer
@@ -243,8 +261,8 @@ module GoodServer
243
261
  sync_buffer
244
262
  else # last-chunk
245
263
  @buffer.read(2) # the final \r\n may or may not be in the buffer
264
+ sync_buffer
246
265
  @chunk_size = nil
247
- @body_pos = nil
248
266
  @request_complete = true
249
267
  end
250
268
  end
@@ -263,10 +281,9 @@ module GoodServer
263
281
  @buffer.rewind
264
282
  unless @buffer.eof? # buffer only contained the headers
265
283
  @request[:body] << @buffer.read(@content_length - @request[:body].size)
284
+ sync_buffer
266
285
  if @request[:body].size == @content_length
267
286
  @request_complete = true
268
- else
269
- sync_buffer
270
287
  end
271
288
  end
272
289
  else
@@ -1,7 +1,8 @@
1
1
  require 'rubygems' if RUBY_VERSION < '1.9'
2
- require 'bundler'
3
-
4
- Bundler.require(:default, :development)
2
+ require 'bundler/setup'
3
+ require 'excon'
4
+ require 'delorean'
5
+ require 'open4'
5
6
 
6
7
  Excon.defaults.merge!(
7
8
  :connect_timeout => 5,
@@ -10,17 +11,22 @@ Excon.defaults.merge!(
10
11
  )
11
12
 
12
13
  def basic_tests(url = 'http://127.0.0.1:9292', options = {})
13
- reset_connection = !!options.delete(:reset_connection)
14
- [false, true].each do |nonblock|
15
- options = options.merge({:ssl_verify_peer => false, :nonblock => nonblock })
16
- connection = Excon.new(url, options)
14
+ ([true, false] * 2).combination(2).to_a.uniq.each do |nonblock, persistent|
15
+ connection = nil
16
+ test do
17
+ options = options.merge({:ssl_verify_peer => false, :nonblock => nonblock, :persistent => persistent })
18
+ connection = Excon.new(url, options)
19
+ true
20
+ end
17
21
 
18
- tests("nonblock => #{nonblock}") do
22
+ tests("nonblock => #{nonblock}, persistent => #{persistent}") do
19
23
 
20
24
  tests('GET /content-length/100') do
21
- response = connection.request(:method => :get, :path => '/content-length/100')
25
+ response = nil
22
26
 
23
27
  tests('response.status').returns(200) do
28
+ response = connection.request(:method => :get, :path => '/content-length/100')
29
+
24
30
  response.status
25
31
  end
26
32
 
@@ -28,11 +34,6 @@ def basic_tests(url = 'http://127.0.0.1:9292', options = {})
28
34
  response[:status]
29
35
  end
30
36
 
31
- tests("response.headers['Connection']").returns('Keep-Alive') do
32
- pending if connection.data[:scheme] == Excon::UNIX
33
- response.headers['Connection']
34
- end
35
-
36
37
  tests("response.headers['Content-Length']").returns('100') do
37
38
  response.headers['Content-Length']
38
39
  end
@@ -88,9 +89,6 @@ def basic_tests(url = 'http://127.0.0.1:9292', options = {})
88
89
  tests('POST /body-sink') do
89
90
 
90
91
  tests('response.body').returns("5000000") do
91
- if reset_connection && !nonblock
92
- connection.reset
93
- end
94
92
  response = connection.request(:method => :post, :path => '/body-sink', :headers => { 'Content-Type' => 'text/plain' }, :body => 'x' * 5_000_000)
95
93
  response.body
96
94
  end
@@ -178,6 +176,13 @@ def basic_tests(url = 'http://127.0.0.1:9292', options = {})
178
176
 
179
177
  end
180
178
 
179
+ tests('should succeed with tcp_nodelay').returns(200) do
180
+ options = options.merge(:ssl_verify_peer => false, :nonblock => nonblock, :tcp_nodelay => true)
181
+ connection = Excon.new(url, options)
182
+ response = connection.request(:method => :get, :path => '/content-length/100')
183
+ response.status
184
+ end
185
+
181
186
  end
182
187
  end
183
188
  end
@@ -228,7 +233,7 @@ end
228
233
 
229
234
  def with_rackup(name)
230
235
  unless RUBY_PLATFORM == 'java'
231
- GC.disable
236
+ GC.disable if RUBY_VERSION < '1.9'
232
237
  pid, w, r, e = Open4.popen4("rackup", rackup_path(name))
233
238
  else
234
239
  pid, w, r, e = IO.popen4("rackup", rackup_path(name))
@@ -238,14 +243,29 @@ def with_rackup(name)
238
243
  ensure
239
244
  Process.kill(9, pid)
240
245
  unless RUBY_PLATFORM == 'java'
241
- GC.enable
246
+ GC.enable if RUBY_VERSION < '1.9'
242
247
  Process.wait(pid)
243
248
  end
249
+
250
+ # dump server errors
251
+ lines = e.read.split($/)
252
+ while line = lines.shift
253
+ case line
254
+ when /(ERROR|Error)/
255
+ unless line =~ /(null cert chain|did not return a certificate|SSL_read:: internal error)/
256
+ in_err = true
257
+ puts
258
+ end
259
+ when /^(127|localhost)/
260
+ in_err = false
261
+ end
262
+ puts line if in_err
263
+ end
244
264
  end
245
265
 
246
266
  def with_unicorn(name, file_name='/tmp/unicorn.sock')
247
267
  unless RUBY_PLATFORM == 'java'
248
- GC.disable
268
+ GC.disable if RUBY_VERSION < '1.9'
249
269
  pid, w, r, e = Open4.popen4("unicorn", "-l", "unix://#{file_name}", rackup_path(name))
250
270
  until e.gets =~ /worker=0 ready/; end
251
271
  else
@@ -255,7 +275,7 @@ def with_unicorn(name, file_name='/tmp/unicorn.sock')
255
275
  ensure
256
276
  unless RUBY_PLATFORM == 'java'
257
277
  Process.kill(9, pid)
258
- GC.enable
278
+ GC.enable if RUBY_VERSION < '1.9'
259
279
  Process.wait(pid)
260
280
  end
261
281
  if File.exist?(file_name)
@@ -269,7 +289,7 @@ end
269
289
 
270
290
  def with_server(name)
271
291
  unless RUBY_PLATFORM == 'java'
272
- GC.disable
292
+ GC.disable if RUBY_VERSION < '1.9'
273
293
  pid, w, r, e = Open4.popen4(server_path("#{name}.rb"))
274
294
  else
275
295
  pid, w, r, e = IO.popen4(server_path("#{name}.rb"))
@@ -279,7 +299,7 @@ def with_server(name)
279
299
  ensure
280
300
  Process.kill(9, pid)
281
301
  unless RUBY_PLATFORM == 'java'
282
- GC.enable
302
+ GC.enable if RUBY_VERSION < '1.9'
283
303
  Process.wait(pid)
284
304
  end
285
305
  end
@@ -12,10 +12,10 @@ Shindo.tests('Excon thread safety') do
12
12
  Thread.current[:success] = response.body == '2'
13
13
  }
14
14
 
15
- long_thread.join
16
- short_thread.join
17
-
18
15
  test('long_thread') do
16
+ long_thread.join
17
+ short_thread.join
18
+
19
19
  long_thread[:success]
20
20
  end
21
21
 
@@ -2,12 +2,11 @@ Shindo.tests('read should timeout') do
2
2
  with_rackup('timeout.ru') do
3
3
 
4
4
  [false, true].each do |nonblock|
5
- connection = Excon.new('http://127.0.0.1:9292', :nonblock => nonblock)
6
-
7
5
  tests("nonblock => #{nonblock} hits read_timeout").raises(Excon::Errors::Timeout) do
6
+ connection = Excon.new('http://127.0.0.1:9292', :nonblock => nonblock)
8
7
  connection.request(:method => :get, :path => '/timeout', :read_timeout => 1)
9
8
  end
10
-
11
9
  end
10
+
12
11
  end
13
12
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: excon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.30.0
4
+ version: 0.31.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2013-11-25 00:00:00.000000000 Z
14
+ date: 2013-12-16 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: activesupport
@@ -205,6 +205,7 @@ files:
205
205
  - tests/middlewares/instrumentation_tests.rb
206
206
  - tests/middlewares/mock_tests.rb
207
207
  - tests/middlewares/redirect_follower_tests.rb
208
+ - tests/pipeline_tests.rb
208
209
  - tests/proxy_tests.rb
209
210
  - tests/query_string_tests.rb
210
211
  - tests/rackups/basic.rb
@@ -220,9 +221,10 @@ files:
220
221
  - tests/rackups/ssl_verify_peer.ru
221
222
  - tests/rackups/thread_safety.ru
222
223
  - tests/rackups/timeout.ru
224
+ - tests/rackups/webrick_patch.rb
223
225
  - tests/request_headers_tests.rb
224
226
  - tests/request_method_tests.rb
225
- - tests/requests_tests.rb
227
+ - tests/request_tests.rb
226
228
  - tests/response_tests.rb
227
229
  - tests/servers/bad.rb
228
230
  - tests/servers/eof.rb
@@ -248,7 +250,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
248
250
  version: '0'
249
251
  segments:
250
252
  - 0
251
- hash: -1886435120012632846
253
+ hash: -1399644688570873046
252
254
  required_rubygems_version: !ruby/object:Gem::Requirement
253
255
  none: false
254
256
  requirements:
@@ -1,73 +0,0 @@
1
- Shindo.tests('requests should succeed') do
2
- with_rackup('basic.ru') do
3
-
4
- tests('HEAD /content-length/100, GET /content-length/100') do
5
-
6
- connection = Excon.new('http://127.0.0.1:9292')
7
- responses = connection.requests([
8
- {:method => :head, :path => '/content-length/100'},
9
- {:method => :get, :path => '/content-length/100'}
10
- ])
11
-
12
- tests('head body is empty').returns('') do
13
- responses.first.body
14
- end
15
-
16
- tests('head content length is 100').returns('100') do
17
- responses.first.headers['Content-Length']
18
- end
19
-
20
- tests('get body is non-empty').returns('x' * 100) do
21
- responses.last.body
22
- end
23
-
24
- tests('get content length is 100').returns('100') do
25
- responses.last.headers['Content-Length']
26
- end
27
-
28
- end
29
-
30
- tests('requests should succeed with tcp_nodelay') do
31
-
32
- connection = Excon.new('http://127.0.0.1:9292', :tcp_nodelay => true)
33
-
34
- tests('GET /content-length/100') do
35
- responses = connection.requests([
36
- {:method => :get, :path => '/content-length/100'}
37
- ])
38
-
39
- tests('get content length is 100').returns('100') do
40
- responses.last.headers['Content-Length']
41
- end
42
- end
43
- end
44
- end
45
-
46
- with_server('good') do
47
-
48
- tests('sets transfer-coding and connection options') do
49
-
50
- tests('without a :response_block') do
51
- request = Marshal.load(
52
- Excon.get('http://127.0.0.1:9292/echo/request').body
53
- )
54
- returns('trailers, deflate, gzip') { request[:headers]['TE'] }
55
- returns('TE') { request[:headers]['Connection'] }
56
- end
57
-
58
- tests('with a :response_block') do
59
- captures = capture_response_block do |block|
60
- Excon.get('http://127.0.0.1:9292/echo/request',
61
- :response_block => block)
62
- end
63
- data = captures.map {|capture| capture[0] }.join
64
- request = Marshal.load(data)
65
-
66
- returns('trailers') { request[:headers]['TE'] }
67
- returns('TE') { request[:headers]['Connection'] }
68
- end
69
-
70
- end
71
-
72
- end
73
- end