excon 0.62.0 → 0.92.3

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.
Files changed (125) hide show
  1. checksums.yaml +5 -5
  2. data/CONTRIBUTING.md +0 -1
  3. data/LICENSE.md +1 -1
  4. data/README.md +7 -6
  5. data/data/cacert.pem +1220 -1828
  6. data/excon.gemspec +19 -3
  7. data/lib/excon/connection.rb +216 -139
  8. data/lib/excon/constants.rb +38 -13
  9. data/lib/excon/error.rb +15 -0
  10. data/lib/excon/headers.rb +4 -3
  11. data/lib/excon/instrumentors/logging_instrumentor.rb +5 -16
  12. data/lib/excon/instrumentors/standard_instrumentor.rb +2 -9
  13. data/lib/excon/middlewares/base.rb +6 -0
  14. data/lib/excon/middlewares/capture_cookies.rb +1 -1
  15. data/lib/excon/middlewares/decompress.rb +11 -4
  16. data/lib/excon/middlewares/expects.rb +7 -1
  17. data/lib/excon/middlewares/idempotent.rb +20 -3
  18. data/lib/excon/middlewares/instrumentor.rb +8 -0
  19. data/lib/excon/middlewares/mock.rb +12 -3
  20. data/lib/excon/middlewares/redirect_follower.rb +25 -3
  21. data/lib/excon/middlewares/response_parser.rb +3 -0
  22. data/lib/excon/pretty_printer.rb +1 -8
  23. data/lib/excon/response.rb +12 -9
  24. data/lib/excon/socket.rb +59 -42
  25. data/lib/excon/ssl_socket.rb +37 -15
  26. data/lib/excon/test/plugin/server/exec.rb +5 -2
  27. data/lib/excon/test/plugin/server/puma.rb +4 -1
  28. data/lib/excon/test/plugin/server/unicorn.rb +5 -0
  29. data/lib/excon/test/plugin/server/webrick.rb +4 -1
  30. data/lib/excon/test/server.rb +1 -1
  31. data/lib/excon/unix_socket.rb +1 -0
  32. data/lib/excon/utils.rb +59 -5
  33. data/lib/excon/version.rb +1 -1
  34. data/lib/excon.rb +25 -17
  35. metadata +27 -98
  36. data/.document +0 -5
  37. data/.gitignore +0 -13
  38. data/.rspec +0 -3
  39. data/.travis.yml +0 -29
  40. data/Gemfile +0 -19
  41. data/Rakefile +0 -41
  42. data/benchmarks/class_vs_lambda.rb +0 -50
  43. data/benchmarks/concat_vs_insert.rb +0 -21
  44. data/benchmarks/concat_vs_interpolate.rb +0 -22
  45. data/benchmarks/cr_lf.rb +0 -21
  46. data/benchmarks/downcase-eq-eq_vs_casecmp.rb +0 -169
  47. data/benchmarks/excon.rb +0 -69
  48. data/benchmarks/excon_vs.rb +0 -165
  49. data/benchmarks/for_vs_array_each.rb +0 -27
  50. data/benchmarks/for_vs_hash_each.rb +0 -27
  51. data/benchmarks/has_key-vs-lookup.rb +0 -177
  52. data/benchmarks/headers_case_sensitivity.rb +0 -83
  53. data/benchmarks/headers_split_vs_match.rb +0 -34
  54. data/benchmarks/implicit_block-vs-explicit_block.rb +0 -98
  55. data/benchmarks/merging.rb +0 -21
  56. data/benchmarks/single_vs_double_quotes.rb +0 -21
  57. data/benchmarks/string_ranged_index.rb +0 -87
  58. data/benchmarks/strip_newline.rb +0 -115
  59. data/benchmarks/vs_stdlib.rb +0 -82
  60. data/changelog.txt +0 -1083
  61. data/spec/excon/error_spec.rb +0 -139
  62. data/spec/excon/test/server_spec.rb +0 -28
  63. data/spec/excon_spec.rb +0 -7
  64. data/spec/helpers/file_path_helpers.rb +0 -22
  65. data/spec/requests/basic_spec.rb +0 -40
  66. data/spec/requests/eof_requests_spec.rb +0 -36
  67. data/spec/requests/unix_socket_spec.rb +0 -46
  68. data/spec/spec_helper.rb +0 -24
  69. data/spec/support/shared_contexts/test_server_context.rb +0 -83
  70. data/spec/support/shared_examples/shared_example_for_clients.rb +0 -218
  71. data/spec/support/shared_examples/shared_example_for_streaming_clients.rb +0 -20
  72. data/spec/support/shared_examples/shared_example_for_test_servers.rb +0 -16
  73. data/tests/authorization_header_tests.rb +0 -29
  74. data/tests/bad_tests.rb +0 -47
  75. data/tests/basic_tests.rb +0 -351
  76. data/tests/batch_requests.rb +0 -133
  77. data/tests/complete_responses.rb +0 -31
  78. data/tests/data/127.0.0.1.cert.crt +0 -20
  79. data/tests/data/127.0.0.1.cert.key +0 -27
  80. data/tests/data/excon.cert.crt +0 -20
  81. data/tests/data/excon.cert.key +0 -27
  82. data/tests/data/xs +0 -1
  83. data/tests/error_tests.rb +0 -145
  84. data/tests/header_tests.rb +0 -119
  85. data/tests/middlewares/canned_response_tests.rb +0 -34
  86. data/tests/middlewares/capture_cookies_tests.rb +0 -34
  87. data/tests/middlewares/decompress_tests.rb +0 -157
  88. data/tests/middlewares/escape_path_tests.rb +0 -36
  89. data/tests/middlewares/idempotent_tests.rb +0 -206
  90. data/tests/middlewares/instrumentation_tests.rb +0 -315
  91. data/tests/middlewares/mock_tests.rb +0 -304
  92. data/tests/middlewares/redirect_follower_tests.rb +0 -112
  93. data/tests/pipeline_tests.rb +0 -40
  94. data/tests/proxy_tests.rb +0 -306
  95. data/tests/query_string_tests.rb +0 -87
  96. data/tests/rackups/basic.rb +0 -41
  97. data/tests/rackups/basic.ru +0 -3
  98. data/tests/rackups/basic_auth.ru +0 -14
  99. data/tests/rackups/deflater.ru +0 -4
  100. data/tests/rackups/proxy.ru +0 -18
  101. data/tests/rackups/query_string.ru +0 -13
  102. data/tests/rackups/redirecting.ru +0 -23
  103. data/tests/rackups/redirecting_with_cookie.ru +0 -40
  104. data/tests/rackups/request_headers.ru +0 -15
  105. data/tests/rackups/request_methods.ru +0 -21
  106. data/tests/rackups/response_header.ru +0 -18
  107. data/tests/rackups/ssl.ru +0 -16
  108. data/tests/rackups/ssl_mismatched_cn.ru +0 -15
  109. data/tests/rackups/ssl_verify_peer.ru +0 -16
  110. data/tests/rackups/streaming.ru +0 -30
  111. data/tests/rackups/thread_safety.ru +0 -17
  112. data/tests/rackups/timeout.ru +0 -14
  113. data/tests/rackups/webrick_patch.rb +0 -34
  114. data/tests/request_headers_tests.rb +0 -21
  115. data/tests/request_method_tests.rb +0 -47
  116. data/tests/request_tests.rb +0 -59
  117. data/tests/response_tests.rb +0 -197
  118. data/tests/servers/bad.rb +0 -20
  119. data/tests/servers/eof.rb +0 -17
  120. data/tests/servers/error.rb +0 -20
  121. data/tests/servers/good.rb +0 -350
  122. data/tests/test_helper.rb +0 -306
  123. data/tests/thread_safety_tests.rb +0 -39
  124. data/tests/timeout_tests.rb +0 -12
  125. data/tests/utils_tests.rb +0 -81
@@ -1,350 +0,0 @@
1
- #!/usr/bin/env ruby
2
-
3
- require 'eventmachine'
4
- require 'stringio'
5
- require 'uri'
6
- require 'zlib'
7
-
8
- module GoodServer
9
- # This method will be called with each request received.
10
- #
11
- # request = {
12
- # :method => method,
13
- # :uri => URI.parse(uri),
14
- # :headers => {},
15
- # :body => ''
16
- # }
17
- #
18
- # Each connection to this server is persistent unless the client sends
19
- # "Connection: close" in the request. If a response requires the connection
20
- # to be closed, use `start_response(:persistent => false)`.
21
- def send_response(request)
22
- type, path = request[:uri].path.split('/', 3)[1, 2]
23
- case type
24
- when 'echo'
25
- case path
26
- when 'request'
27
- data = Marshal.dump(request)
28
- start_response
29
- send_data "Content-Length: #{ data.size }\r\n"
30
- send_data "\r\n"
31
- send_data data
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 "Connection: Keep-Alive\r\n"
38
- send_data "\r\n"
39
- send_data @request_count
40
-
41
- when /(content|transfer)-encoded\/?(.*)/
42
- if (encoding_type = $1) == 'content'
43
- accept_header = 'Accept-Encoding'
44
- encoding_header = 'Content-Encoding'
45
- else
46
- accept_header = 'TE'
47
- encoding_header = 'Transfer-Encoding'
48
- end
49
- chunked = $2 == 'chunked'
50
-
51
- encodings = parse_encodings(request[:headers][accept_header])
52
- while encoding = encodings.pop
53
- break if ['gzip', 'deflate'].include?(encoding)
54
- end
55
-
56
- case encoding
57
- when 'gzip'
58
- body = request[:body]
59
- if(body.nil? || body.empty?)
60
- body = ''
61
- else
62
- io = (Zlib::GzipWriter.new(StringIO.new) << request[:body]).finish
63
- io.rewind
64
- body = io.read
65
- end
66
- when 'deflate'
67
- # drops the zlib header
68
- deflator = Zlib::Deflate.new(nil, -Zlib::MAX_WBITS)
69
- body = deflator.deflate(request[:body], Zlib::FINISH)
70
- deflator.close
71
- else
72
- body = request[:body]
73
- end
74
-
75
- # simulate server pre/post content encoding
76
- encodings = [
77
- request[:headers]["#{ encoding_header }-Pre"],
78
- encoding,
79
- request[:headers]["#{ encoding_header }-Post"],
80
- ]
81
- if chunked && encoding_type == 'transfer'
82
- encodings << 'chunked'
83
- end
84
- encodings = encodings.compact.join(', ')
85
-
86
- start_response
87
- # let the test know what the server sent
88
- send_data "#{ encoding_header }-Sent: #{ encodings }\r\n"
89
- send_data "#{ encoding_header }: #{ encodings }\r\n" unless encodings.empty?
90
- if chunked
91
- if encoding_type == 'content'
92
- send_data "Transfer-Encoding: chunked\r\n"
93
- end
94
- send_data "\r\n"
95
- send_data chunks_for(body)
96
- send_data "\r\n"
97
- else
98
- send_data "Content-Length: #{ body.size }\r\n"
99
- send_data "\r\n"
100
- send_data body
101
- end
102
- end
103
-
104
- when 'chunked'
105
- case path
106
- when 'simple'
107
- start_response
108
- send_data "Transfer-Encoding: chunked\r\n"
109
- send_data "\r\n"
110
- # chunk-extension is currently ignored.
111
- # this works because "6; chunk-extension".to_i => "6"
112
- send_data "6; chunk-extension\r\n"
113
- send_data "hello \r\n"
114
- send_data "5; chunk-extension\r\n"
115
- send_data "world\r\n"
116
- send_data "0; chunk-extension\r\n" # last-chunk
117
- send_data "\r\n"
118
-
119
- # merged trailers also support continuations
120
- when 'trailers'
121
- start_response
122
- send_data "Transfer-Encoding: chunked\r\n"
123
- send_data "Test-Header: one, two\r\n"
124
- send_data "\r\n"
125
- send_data chunks_for('hello world')
126
- send_data "Test-Header: three, four,\r\n"
127
- send_data "\tfive, six\r\n"
128
- send_data "\r\n"
129
- end
130
-
131
- when 'content-length'
132
- case path
133
- when 'simple'
134
- start_response
135
- send_data "Content-Length: 11\r\n"
136
- send_data "\r\n"
137
- send_data "hello world"
138
- end
139
-
140
- when 'unknown'
141
- case path
142
- when 'cookies'
143
- start_response(:persistent => false)
144
- send_data "Set-Cookie: one, two\r\n"
145
- send_data "Set-Cookie: three, four\r\n"
146
- send_data "\r\n"
147
- send_data "hello world"
148
-
149
- when 'simple'
150
- start_response(:persistent => false)
151
- send_data "\r\n"
152
- send_data "hello world"
153
-
154
- when 'header_continuation'
155
- start_response(:persistent => false)
156
- send_data "Test-Header: one, two\r\n"
157
- send_data "Test-Header: three, four,\r\n"
158
- send_data " five, six\r\n"
159
- send_data "\r\n"
160
- send_data "hello world"
161
- end
162
-
163
- when 'bad'
164
- # Excon will close these connections due to the errors.
165
- case path
166
- when 'malformed_header'
167
- start_response
168
- send_data "Bad-Header\r\n" # no ':'
169
- send_data "\r\n"
170
- send_data "hello world"
171
-
172
- when 'malformed_header_continuation'
173
- send_data "HTTP/1.1 200 OK\r\n"
174
- send_data " Bad-Header: one, two\r\n" # no previous header
175
- send_data "\r\n"
176
- send_data "hello world"
177
- end
178
-
179
- when 'not-found'
180
- start_response(:status => "404 Not Found")
181
- send_data "Content-Length: 11\r\n"
182
- send_data "\r\n"
183
- send_data "hello world"
184
- end
185
- end
186
-
187
- # Sends response status-line, plus headers common to all responses.
188
- def start_response(opts = {})
189
- opts = {
190
- :status => '200 OK',
191
- :persistent => @persistent # true unless client sent Connection: close
192
- }.merge!(opts)
193
-
194
- @persistent = opts[:persistent]
195
- send_data "HTTP/1.1 #{ opts[:status] }\r\n"
196
- send_data "Connection: close\r\n" unless @persistent
197
- end
198
-
199
- def post_init
200
- @buffer = StringIO.new
201
- @buffer.set_encoding('BINARY') if @buffer.respond_to?(:set_encoding)
202
- end
203
-
204
- # Receives a String of +data+ sent from the client.
205
- # +data+ may only be a portion of what the client sent.
206
- # The data is buffered, then processed and removed from the buffer
207
- # as data becomes available until the @request is complete.
208
- def receive_data(data)
209
- @buffer.seek(0, IO::SEEK_END)
210
- @buffer.write(data)
211
-
212
- parse_headers unless @request
213
- parse_body if @request
214
-
215
- if @request_complete
216
- send_response(@request)
217
- if @persistent
218
- @request = nil
219
- @request_complete = false
220
- # process remaining buffer for next request
221
- receive_data('') unless @buffer.eof?
222
- else
223
- close_connection(true)
224
- end
225
- end
226
- end
227
-
228
- # Removes the processed portion of the buffer
229
- # by replacing the buffer with it's contents from the current pos.
230
- def sync_buffer
231
- @buffer.string = @buffer.read
232
- end
233
-
234
- def parse_headers
235
- @buffer.rewind
236
- # wait until buffer contains the end of the headers
237
- if /\sHTTP\/\d+\.\d+\r\n.*?\r\n\r\n/m =~ @buffer.read
238
- @buffer.rewind
239
- # For persistent connections, the buffer could start with the
240
- # \r\n chunked-message terminator from the previous request.
241
- # This will discard anything up to the request-line.
242
- until m = /^(\w+)\s(.*)\sHTTP\/\d+\.\d+$/.match(@buffer.readline.chop!); end
243
- method, uri = m[1, 2]
244
-
245
- headers = {}
246
- last_key = nil
247
- until (line = @buffer.readline.chop!).empty?
248
- if !line.lstrip!.nil?
249
- headers[last_key] << ' ' << line.rstrip
250
- else
251
- key, value = line.split(':', 2)
252
- headers[key] = ([headers[key]] << value.strip).compact.join(', ')
253
- last_key = key
254
- end
255
- end
256
-
257
- sync_buffer
258
-
259
- @chunked = headers['Transfer-Encoding'] =~ /chunked/i
260
- @content_length = headers['Content-Length'].to_i
261
- @persistent = headers['Connection'] !~ /close/i
262
- @request = {
263
- :method => method,
264
- :uri => URI.parse(uri),
265
- :headers => headers,
266
- :body => ''
267
- }
268
- end
269
- end
270
-
271
- def parse_body
272
- if @chunked
273
- @buffer.rewind
274
- until @request_complete || @buffer.eof?
275
- unless @chunk_size
276
- # in case buffer only contains a portion of the chunk-size line
277
- if (line = @buffer.readline) =~ /\r\n\z/
278
- @chunk_size = line.to_i(16)
279
- if @chunk_size > 0
280
- sync_buffer
281
- else # last-chunk
282
- @buffer.read(2) # the final \r\n may or may not be in the buffer
283
- sync_buffer
284
- @chunk_size = nil
285
- @request_complete = true
286
- end
287
- end
288
- end
289
- if @chunk_size
290
- if @buffer.size >= @chunk_size + 2
291
- @request[:body] << @buffer.read(@chunk_size + 2).chop!
292
- @chunk_size = nil
293
- sync_buffer
294
- else
295
- break # wait for more data
296
- end
297
- end
298
- end
299
- elsif @content_length > 0
300
- @buffer.rewind
301
- unless @buffer.eof? # buffer only contained the headers
302
- @request[:body] << @buffer.read(@content_length - @request[:body].size)
303
- sync_buffer
304
- if @request[:body].size == @content_length
305
- @request_complete = true
306
- end
307
- end
308
- else
309
- # no body
310
- @request_complete = true
311
- end
312
- end
313
-
314
- def chunks_for(str)
315
- chunks = ''
316
- str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
317
- chunk_size = str.size / 2
318
- until (chunk = str.slice!(0, chunk_size)).empty?
319
- chunks << chunk.size.to_s(16) << "\r\n"
320
- chunks << chunk << "\r\n"
321
- end
322
- chunks << "0\r\n" # last-chunk
323
- end
324
-
325
- # only supports a single quality parameter for tokens
326
- def parse_encodings(encodings)
327
- return [] if encodings.nil?
328
- split_header_value(encodings).map do |value|
329
- token, q_val = /^(.*?)(?:;q=(.*))?$/.match(value.strip)[1, 2]
330
- if q_val && q_val.to_f == 0
331
- nil
332
- else
333
- [token, (q_val || 1).to_f]
334
- end
335
- end.compact.sort_by {|_, q_val| q_val }.map {|token, _| token }
336
- end
337
-
338
- # Splits a header value +str+ according to HTTP specification.
339
- def split_header_value(str)
340
- return [] if str.nil?
341
- str.strip.scan(%r'\G((?:"(?:\\.|[^"])+?"|[^",]+)+)
342
- (?:,\s*|\Z)'xn).flatten
343
- end
344
- end
345
-
346
- EM.run do
347
- EM.start_server("127.0.0.1", 9292, GoodServer)
348
- EM.start_server("::1", 9293, GoodServer) unless RUBY_PLATFORM == 'java'
349
- $stderr.puts "ready"
350
- end
data/tests/test_helper.rb DELETED
@@ -1,306 +0,0 @@
1
- require 'rubygems' if RUBY_VERSION < '1.9'
2
- require 'bundler/setup'
3
- require 'excon'
4
- require 'delorean'
5
- require 'open4'
6
-
7
- Excon.defaults.merge!(
8
- :connect_timeout => 5,
9
- :read_timeout => 5,
10
- :write_timeout => 5
11
- )
12
-
13
- def basic_tests(url = 'http://127.0.0.1:9292', 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
21
-
22
- tests("nonblock => #{nonblock}, persistent => #{persistent}") do
23
-
24
- tests('GET /content-length/100') do
25
- response = nil
26
-
27
- tests('response.status').returns(200) do
28
- response = connection.request(:method => :get, :path => '/content-length/100')
29
-
30
- response.status
31
- end
32
-
33
- tests('response[:status]').returns(200) do
34
- response[:status]
35
- end
36
-
37
- tests("response.headers['Content-Length']").returns('100') do
38
- response.headers['Content-Length']
39
- end
40
-
41
- tests("response.headers['Content-Type']").returns('text/html;charset=utf-8') do
42
- response.headers['Content-Type']
43
- end
44
-
45
- test("Time.parse(response.headers['Date']).is_a?(Time)") do
46
- pending if connection.data[:scheme] == Excon::UNIX
47
- Time.parse(response.headers['Date']).is_a?(Time)
48
- end
49
-
50
- test("!!(response.headers['Server'] =~ /^WEBrick/)") do
51
- pending if connection.data[:scheme] == Excon::UNIX
52
- !!(response.headers['Server'] =~ /^WEBrick/)
53
- end
54
-
55
- tests("response.headers['Custom']").returns("Foo: bar") do
56
- response.headers['Custom']
57
- end
58
-
59
- tests("response.remote_ip").returns("127.0.0.1") do
60
- pending if connection.data[:scheme] == Excon::UNIX
61
- response.remote_ip
62
- end
63
-
64
- tests("response.body").returns('x' * 100) do
65
- response.body
66
- end
67
-
68
- tests("deprecated block usage").returns(['x' * 100, 0, 100]) do
69
- data = []
70
- silence_warnings do
71
- connection.request(:method => :get, :path => '/content-length/100') do |chunk, remaining_length, total_length|
72
- data = [chunk, remaining_length, total_length]
73
- end
74
- end
75
- data
76
- end
77
-
78
- tests("response_block usage").returns(['x' * 100, 0, 100]) do
79
- data = []
80
- response_block = lambda do |chunk, remaining_length, total_length|
81
- data = [chunk, remaining_length, total_length]
82
- end
83
- connection.request(:method => :get, :path => '/content-length/100', :response_block => response_block)
84
- data
85
- end
86
-
87
- end
88
-
89
- tests('POST /body-sink') do
90
-
91
- tests('response.body').returns("5000000") do
92
- response = connection.request(:method => :post, :path => '/body-sink', :headers => { 'Content-Type' => 'text/plain' }, :body => 'x' * 5_000_000)
93
- response.body
94
- end
95
-
96
- tests('empty body').returns('0') do
97
- response = connection.request(:method => :post, :path => '/body-sink', :headers => { 'Content-Type' => 'text/plain' }, :body => '')
98
- response.body
99
- end
100
-
101
- end
102
-
103
- tests('POST /echo') do
104
-
105
- tests('with file').returns('x' * 100 + "\n") do
106
- file_path = File.join(File.dirname(__FILE__), "data", "xs")
107
- response = connection.request(:method => :post, :path => '/echo', :body => File.open(file_path))
108
- response.body
109
- end
110
-
111
- tests('without request_block').returns('x' * 100) do
112
- response = connection.request(:method => :post, :path => '/echo', :body => 'x' * 100)
113
- response.body
114
- end
115
-
116
- tests('with request_block').returns('x' * 100) do
117
- data = ['x'] * 100
118
- request_block = lambda do
119
- data.shift.to_s
120
- end
121
- response = connection.request(:method => :post, :path => '/echo', :request_block => request_block)
122
- response.body
123
- end
124
-
125
- tests('with multi-byte strings') do
126
- body = "\xC3\xBC" * 100
127
- headers = { 'Custom' => body.dup }
128
- if RUBY_VERSION >= '1.9'
129
- body.force_encoding('BINARY')
130
- headers['Custom'].force_encoding('UTF-8')
131
- end
132
-
133
- returns(body, 'properly concatenates request+headers and body') do
134
- response = connection.request(:method => :post, :path => '/echo', :headers => headers, :body => body)
135
- response.body
136
- end
137
- end
138
-
139
- end
140
-
141
- tests('PUT /echo') do
142
-
143
- tests('with file').returns('x' * 100 + "\n") do
144
- file_path = File.join(File.dirname(__FILE__), "data", "xs")
145
- response = connection.request(:method => :put, :path => '/echo', :body => File.open(file_path))
146
- response.body
147
- end
148
-
149
- tests('without request_block').returns('x' * 100) do
150
- response = connection.request(:method => :put, :path => '/echo', :body => 'x' * 100)
151
- response.body
152
- end
153
-
154
- tests('request_block usage').returns('x' * 100) do
155
- data = ['x'] * 100
156
- request_block = lambda do
157
- data.shift.to_s
158
- end
159
- response = connection.request(:method => :put, :path => '/echo', :request_block => request_block)
160
- response.body
161
- end
162
-
163
- tests('with multi-byte strings') do
164
- body = "\xC3\xBC" * 100
165
- headers = { 'Custom' => body.dup }
166
- if RUBY_VERSION >= '1.9'
167
- body.force_encoding('BINARY')
168
- headers['Custom'].force_encoding('UTF-8')
169
- end
170
-
171
- returns(body, 'properly concatenates request+headers and body') do
172
- response = connection.request(:method => :put, :path => '/echo', :headers => headers, :body => body)
173
- response.body
174
- end
175
- end
176
-
177
- end
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
-
186
- end
187
- end
188
- end
189
-
190
-
191
- PROXY_ENV_VARIABLES = %w{http_proxy https_proxy no_proxy} # All lower-case
192
-
193
- def env_init(env={})
194
- current = {}
195
- PROXY_ENV_VARIABLES.each do |key|
196
- current[key] = ENV.delete(key)
197
- current[key.upcase] = ENV.delete(key.upcase)
198
- end
199
- env_stack << current
200
-
201
- env.each do |key, value|
202
- ENV[key] = value
203
- end
204
- end
205
-
206
- def env_restore
207
- ENV.update(env_stack.pop)
208
- end
209
-
210
- def env_stack
211
- @env_stack ||= []
212
- end
213
-
214
- def silence_warnings
215
- orig_verbose = $VERBOSE
216
- $VERBOSE = nil
217
- yield
218
- ensure
219
- $VERBOSE = orig_verbose
220
- end
221
-
222
- def capture_response_block
223
- captures = []
224
- yield lambda {|chunk, remaining_bytes, total_bytes|
225
- captures << [chunk, remaining_bytes, total_bytes]
226
- }
227
- captures
228
- end
229
-
230
- def rackup_path(*parts)
231
- File.expand_path(File.join(File.dirname(__FILE__), 'rackups', *parts))
232
- end
233
-
234
- def with_rackup(name, host="127.0.0.1")
235
- unless RUBY_PLATFORM == 'java'
236
- GC.disable if RUBY_VERSION < '1.9'
237
- pid, w, r, e = Open4.popen4("rackup", "-s", "webrick", "--host", host, rackup_path(name))
238
- else
239
- pid, w, r, e = IO.popen4("rackup", "-s", "webrick", "--host", host, rackup_path(name))
240
- end
241
- until e.gets =~ /HTTPServer#start:/; end
242
- yield
243
- ensure
244
- Process.kill(9, pid)
245
- unless RUBY_PLATFORM == 'java'
246
- GC.enable if RUBY_VERSION < '1.9'
247
- Process.wait(pid)
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
264
- end
265
-
266
- def with_unicorn(name, listen='127.0.0.1:9292')
267
- unless RUBY_PLATFORM == 'java'
268
- GC.disable if RUBY_VERSION < '1.9'
269
- unix_socket = listen.sub('unix://', '') if listen.start_with? 'unix://'
270
- pid, w, r, e = Open4.popen4("unicorn", "--no-default-middleware","-l", listen, rackup_path(name))
271
- until e.gets =~ /worker=0 ready/; end
272
- else
273
- # need to find suitable server for jruby
274
- end
275
- yield
276
- ensure
277
- unless RUBY_PLATFORM == 'java'
278
- Process.kill(9, pid)
279
- GC.enable if RUBY_VERSION < '1.9'
280
- Process.wait(pid)
281
- end
282
- if not unix_socket.nil? and File.exist?(unix_socket)
283
- File.delete(unix_socket)
284
- end
285
- end
286
-
287
- def server_path(*parts)
288
- File.expand_path(File.join(File.dirname(__FILE__), 'servers', *parts))
289
- end
290
-
291
- def with_server(name)
292
- unless RUBY_PLATFORM == 'java'
293
- GC.disable if RUBY_VERSION < '1.9'
294
- pid, w, r, e = Open4.popen4(server_path("#{name}.rb"))
295
- else
296
- pid, w, r, e = IO.popen4(server_path("#{name}.rb"))
297
- end
298
- until e.gets =~ /ready/; end
299
- yield
300
- ensure
301
- Process.kill(9, pid)
302
- unless RUBY_PLATFORM == 'java'
303
- GC.enable if RUBY_VERSION < '1.9'
304
- Process.wait(pid)
305
- end
306
- end
@@ -1,39 +0,0 @@
1
- Shindo.tests('Excon thread safety') do
2
-
3
- tests('thread_safe_sockets configuration') do
4
- tests('thread_safe_sockets default').returns(true) do
5
- connection = Excon.new('http://foo.com')
6
- connection.data[:thread_safe_sockets]
7
- end
8
-
9
- tests('with thread_safe_sockets set false').returns(false) do
10
- connection = Excon.new('http://foo.com', :thread_safe_sockets => false)
11
- connection.data[:thread_safe_sockets]
12
- end
13
- end
14
-
15
- with_rackup('thread_safety.ru') do
16
- connection = Excon.new('http://127.0.0.1:9292')
17
-
18
- long_thread = Thread.new {
19
- response = connection.request(:method => 'GET', :path => '/id/1/wait/2')
20
- Thread.current[:success] = response.body == '1'
21
- }
22
-
23
- short_thread = Thread.new {
24
- response = connection.request(:method => 'GET', :path => '/id/2/wait/1')
25
- Thread.current[:success] = response.body == '2'
26
- }
27
-
28
- test('long_thread') do
29
- long_thread.join
30
- short_thread.join
31
-
32
- long_thread[:success]
33
- end
34
-
35
- test('short_thread') do
36
- short_thread[:success]
37
- end
38
- end
39
- end
@@ -1,12 +0,0 @@
1
- Shindo.tests('read should timeout') do
2
- with_rackup('timeout.ru') do
3
-
4
- [false, true].each do |nonblock|
5
- tests("nonblock => #{nonblock} hits read_timeout").raises(Excon::Errors::Timeout) do
6
- connection = Excon.new('http://127.0.0.1:9292', :nonblock => nonblock)
7
- connection.request(:method => :get, :path => '/timeout', :read_timeout => 1)
8
- end
9
- end
10
-
11
- end
12
- end