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.
- checksums.yaml +5 -5
- data/CONTRIBUTING.md +0 -1
- data/LICENSE.md +1 -1
- data/README.md +7 -6
- data/data/cacert.pem +1220 -1828
- data/excon.gemspec +19 -3
- data/lib/excon/connection.rb +216 -139
- data/lib/excon/constants.rb +38 -13
- data/lib/excon/error.rb +15 -0
- data/lib/excon/headers.rb +4 -3
- data/lib/excon/instrumentors/logging_instrumentor.rb +5 -16
- data/lib/excon/instrumentors/standard_instrumentor.rb +2 -9
- data/lib/excon/middlewares/base.rb +6 -0
- data/lib/excon/middlewares/capture_cookies.rb +1 -1
- data/lib/excon/middlewares/decompress.rb +11 -4
- data/lib/excon/middlewares/expects.rb +7 -1
- data/lib/excon/middlewares/idempotent.rb +20 -3
- data/lib/excon/middlewares/instrumentor.rb +8 -0
- data/lib/excon/middlewares/mock.rb +12 -3
- data/lib/excon/middlewares/redirect_follower.rb +25 -3
- data/lib/excon/middlewares/response_parser.rb +3 -0
- data/lib/excon/pretty_printer.rb +1 -8
- data/lib/excon/response.rb +12 -9
- data/lib/excon/socket.rb +59 -42
- data/lib/excon/ssl_socket.rb +37 -15
- data/lib/excon/test/plugin/server/exec.rb +5 -2
- data/lib/excon/test/plugin/server/puma.rb +4 -1
- data/lib/excon/test/plugin/server/unicorn.rb +5 -0
- data/lib/excon/test/plugin/server/webrick.rb +4 -1
- data/lib/excon/test/server.rb +1 -1
- data/lib/excon/unix_socket.rb +1 -0
- data/lib/excon/utils.rb +59 -5
- data/lib/excon/version.rb +1 -1
- data/lib/excon.rb +25 -17
- metadata +27 -98
- data/.document +0 -5
- data/.gitignore +0 -13
- data/.rspec +0 -3
- data/.travis.yml +0 -29
- data/Gemfile +0 -19
- data/Rakefile +0 -41
- data/benchmarks/class_vs_lambda.rb +0 -50
- data/benchmarks/concat_vs_insert.rb +0 -21
- data/benchmarks/concat_vs_interpolate.rb +0 -22
- data/benchmarks/cr_lf.rb +0 -21
- data/benchmarks/downcase-eq-eq_vs_casecmp.rb +0 -169
- data/benchmarks/excon.rb +0 -69
- data/benchmarks/excon_vs.rb +0 -165
- data/benchmarks/for_vs_array_each.rb +0 -27
- data/benchmarks/for_vs_hash_each.rb +0 -27
- data/benchmarks/has_key-vs-lookup.rb +0 -177
- data/benchmarks/headers_case_sensitivity.rb +0 -83
- data/benchmarks/headers_split_vs_match.rb +0 -34
- data/benchmarks/implicit_block-vs-explicit_block.rb +0 -98
- data/benchmarks/merging.rb +0 -21
- data/benchmarks/single_vs_double_quotes.rb +0 -21
- data/benchmarks/string_ranged_index.rb +0 -87
- data/benchmarks/strip_newline.rb +0 -115
- data/benchmarks/vs_stdlib.rb +0 -82
- data/changelog.txt +0 -1083
- data/spec/excon/error_spec.rb +0 -139
- data/spec/excon/test/server_spec.rb +0 -28
- data/spec/excon_spec.rb +0 -7
- data/spec/helpers/file_path_helpers.rb +0 -22
- data/spec/requests/basic_spec.rb +0 -40
- data/spec/requests/eof_requests_spec.rb +0 -36
- data/spec/requests/unix_socket_spec.rb +0 -46
- data/spec/spec_helper.rb +0 -24
- data/spec/support/shared_contexts/test_server_context.rb +0 -83
- data/spec/support/shared_examples/shared_example_for_clients.rb +0 -218
- data/spec/support/shared_examples/shared_example_for_streaming_clients.rb +0 -20
- data/spec/support/shared_examples/shared_example_for_test_servers.rb +0 -16
- data/tests/authorization_header_tests.rb +0 -29
- data/tests/bad_tests.rb +0 -47
- data/tests/basic_tests.rb +0 -351
- data/tests/batch_requests.rb +0 -133
- data/tests/complete_responses.rb +0 -31
- data/tests/data/127.0.0.1.cert.crt +0 -20
- data/tests/data/127.0.0.1.cert.key +0 -27
- data/tests/data/excon.cert.crt +0 -20
- data/tests/data/excon.cert.key +0 -27
- data/tests/data/xs +0 -1
- data/tests/error_tests.rb +0 -145
- data/tests/header_tests.rb +0 -119
- data/tests/middlewares/canned_response_tests.rb +0 -34
- data/tests/middlewares/capture_cookies_tests.rb +0 -34
- data/tests/middlewares/decompress_tests.rb +0 -157
- data/tests/middlewares/escape_path_tests.rb +0 -36
- data/tests/middlewares/idempotent_tests.rb +0 -206
- data/tests/middlewares/instrumentation_tests.rb +0 -315
- data/tests/middlewares/mock_tests.rb +0 -304
- data/tests/middlewares/redirect_follower_tests.rb +0 -112
- data/tests/pipeline_tests.rb +0 -40
- data/tests/proxy_tests.rb +0 -306
- data/tests/query_string_tests.rb +0 -87
- data/tests/rackups/basic.rb +0 -41
- data/tests/rackups/basic.ru +0 -3
- data/tests/rackups/basic_auth.ru +0 -14
- data/tests/rackups/deflater.ru +0 -4
- data/tests/rackups/proxy.ru +0 -18
- data/tests/rackups/query_string.ru +0 -13
- data/tests/rackups/redirecting.ru +0 -23
- data/tests/rackups/redirecting_with_cookie.ru +0 -40
- data/tests/rackups/request_headers.ru +0 -15
- data/tests/rackups/request_methods.ru +0 -21
- data/tests/rackups/response_header.ru +0 -18
- data/tests/rackups/ssl.ru +0 -16
- data/tests/rackups/ssl_mismatched_cn.ru +0 -15
- data/tests/rackups/ssl_verify_peer.ru +0 -16
- data/tests/rackups/streaming.ru +0 -30
- data/tests/rackups/thread_safety.ru +0 -17
- data/tests/rackups/timeout.ru +0 -14
- data/tests/rackups/webrick_patch.rb +0 -34
- data/tests/request_headers_tests.rb +0 -21
- data/tests/request_method_tests.rb +0 -47
- data/tests/request_tests.rb +0 -59
- data/tests/response_tests.rb +0 -197
- data/tests/servers/bad.rb +0 -20
- data/tests/servers/eof.rb +0 -17
- data/tests/servers/error.rb +0 -20
- data/tests/servers/good.rb +0 -350
- data/tests/test_helper.rb +0 -306
- data/tests/thread_safety_tests.rb +0 -39
- data/tests/timeout_tests.rb +0 -12
- data/tests/utils_tests.rb +0 -81
data/tests/servers/good.rb
DELETED
|
@@ -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
|
data/tests/timeout_tests.rb
DELETED
|
@@ -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
|