excon 0.64.0 → 0.65.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.
- checksums.yaml +4 -4
- data/data/cacert.pem +108 -2
- data/excon.gemspec +7 -2
- data/lib/excon.rb +11 -11
- data/lib/excon/connection.rb +25 -25
- data/lib/excon/response.rb +1 -1
- data/lib/excon/version.rb +1 -1
- metadata +3 -101
- data/.document +0 -5
- data/.github/stale.yml +0 -17
- data/.gitignore +0 -13
- data/.rspec +0 -3
- data/.travis.yml +0 -17
- 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 -1113
- 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/helpers/warning_helpers.rb +0 -9
- 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 -38
- data/spec/requests/validation_spec.rb +0 -80
- data/spec/spec_helper.rb +0 -26
- data/spec/support/shared_contexts/test_server_context.rb +0 -83
- data/spec/support/shared_contexts/test_stub_context.rb +0 -11
- data/spec/support/shared_examples/shared_example_for_clients.rb +0 -220
- 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 -27
- data/tests/bad_tests.rb +0 -69
- 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 -17
- data/tests/data/127.0.0.1.cert.key +0 -28
- data/tests/data/excon.cert.crt +0 -17
- data/tests/data/excon.cert.key +0 -28
- data/tests/data/xs +0 -1
- data/tests/error_tests.rb +0 -145
- data/tests/header_tests.rb +0 -119
- data/tests/instrumentors/logging_instrumentor_tests.rb +0 -28
- data/tests/middleware_tests.rb +0 -27
- 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 -245
- 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 -58
- data/tests/response_tests.rb +0 -197
- data/tests/servers/bad.rb +0 -25
- data/tests/servers/eof.rb +0 -17
- data/tests/servers/error.rb +0 -20
- data/tests/servers/good.rb +0 -342
- data/tests/servers/good_ipv4.rb +0 -8
- data/tests/servers/good_ipv6.rb +0 -8
- data/tests/test_helper.rb +0 -297
- data/tests/thread_safety_tests.rb +0 -39
- data/tests/timeout_tests.rb +0 -12
- data/tests/utils_tests.rb +0 -81
@@ -1,220 +0,0 @@
|
|
1
|
-
require 'time'
|
2
|
-
|
3
|
-
shared_examples_for 'a basic client' do |url = 'http://127.0.0.1:9292', opts = {}|
|
4
|
-
# TODO: Ditch iterator and manually write a context for each set of options
|
5
|
-
([true, false] * 2).combination(2).to_a.uniq.each do |nonblock, persistent|
|
6
|
-
context "when nonblock is #{nonblock} and persistent is #{persistent}" do
|
7
|
-
opts = opts.merge(ssl_verify_peer: false, nonblock: nonblock, persistent: persistent)
|
8
|
-
|
9
|
-
let(:conn) { Excon.new(url, opts) }
|
10
|
-
|
11
|
-
context 'when :method is get and :path is /content-length/100' do
|
12
|
-
describe '#request' do
|
13
|
-
let(:response) do
|
14
|
-
conn.request(method: :get, path: '/content-length/100')
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'returns an Excon::Response' do
|
18
|
-
expect(response).to be_instance_of Excon::Response
|
19
|
-
end
|
20
|
-
describe Excon::Response do
|
21
|
-
describe '#status' do
|
22
|
-
it 'returns 200' do
|
23
|
-
expect(response.status).to eq 200
|
24
|
-
end
|
25
|
-
|
26
|
-
it '#status returns 200' do
|
27
|
-
expect(response[:status]).to eq 200
|
28
|
-
end
|
29
|
-
end
|
30
|
-
describe '#headers' do
|
31
|
-
it '["Content-Length"] returns 100' do
|
32
|
-
expect(response.headers['Content-Length']).to eq '100'
|
33
|
-
end
|
34
|
-
it '["Content-Type"] returns "text/html;charset=utf-8"' do
|
35
|
-
expect(response.headers['Content-Type']).to eq 'text/html;charset=utf-8'
|
36
|
-
end
|
37
|
-
|
38
|
-
it "['Date'] returns a valid date" do
|
39
|
-
if RUBY_PLATFORM == 'java' && conn.data[:scheme] == Excon::UNIX
|
40
|
-
skip('until puma responds with a date header')
|
41
|
-
else
|
42
|
-
time = Time.parse(response.headers['Date'])
|
43
|
-
expect(time.is_a?(Time)).to be true
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
it "['Server'] matches /^WEBrick/" do
|
48
|
-
pending('until unix_socket response has server header') if conn.data[:scheme] == Excon::UNIX
|
49
|
-
expect(!!(response.headers['Server'] =~ /^WEBrick/)).to be true
|
50
|
-
end
|
51
|
-
|
52
|
-
it "['Custom'] returns Foo: bar" do
|
53
|
-
expect(response.headers['Custom']).to eq 'Foo: bar'
|
54
|
-
end
|
55
|
-
end
|
56
|
-
describe '#remote_ip' do
|
57
|
-
it 'returns 127.0.0.1' do
|
58
|
-
pending('until pigs can fly') if conn.data[:scheme] == Excon::UNIX
|
59
|
-
expect(response.remote_ip).to eq '127.0.0.1'
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
context('when tcp_nodelay is true') do
|
65
|
-
describe '#request' do
|
66
|
-
response = nil
|
67
|
-
options = opts.merge(ssl_verify_peer: false, nonblock: nonblock, tcp_nodelay: true)
|
68
|
-
connection = Excon.new(url, options)
|
69
|
-
|
70
|
-
it 'returns an Excon::Response' do
|
71
|
-
expect do
|
72
|
-
response = connection.request(method: :get, path: '/content-length/100')
|
73
|
-
end.to_not raise_error
|
74
|
-
end
|
75
|
-
|
76
|
-
describe Excon::Response do
|
77
|
-
describe '#body' do
|
78
|
-
describe '.status' do
|
79
|
-
it '#returns 200' do
|
80
|
-
expect(response.status).to eq 200
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
context 'when utilizing deprecated block usage' do
|
90
|
-
describe '#request' do
|
91
|
-
data = []
|
92
|
-
it 'yields with a chunk, remaining length, and total length' do
|
93
|
-
expect do
|
94
|
-
silence_warnings do
|
95
|
-
conn.request(method: :get, path: '/content-length/100') do |chunk, remaining_length, total_length|
|
96
|
-
data = [chunk, remaining_length, total_length]
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end.to_not raise_error
|
100
|
-
end
|
101
|
-
it 'completes with expected data' do
|
102
|
-
expect(data).to eq ['x' * 100, 0, 100]
|
103
|
-
end
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
context 'when utilizing response_block usage' do
|
108
|
-
describe '#request' do
|
109
|
-
data = []
|
110
|
-
it 'yields a chunk, remaining length, and total_length' do
|
111
|
-
response_block = lambda do |chunk, remaining_length, total_length|
|
112
|
-
data = [chunk, remaining_length, total_length]
|
113
|
-
end
|
114
|
-
expect do
|
115
|
-
conn.request(method: :get, path: '/content-length/100', response_block: response_block)
|
116
|
-
end.to_not raise_error
|
117
|
-
end
|
118
|
-
it 'completes with expected data' do
|
119
|
-
expect(data).to eq ['x' * 100, 0, 100]
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
123
|
-
context 'when method is :post' do
|
124
|
-
context 'when :path is /body-sink' do
|
125
|
-
context 'when a body parameter is supplied' do
|
126
|
-
response = nil
|
127
|
-
it 'returns an Excon::Response' do
|
128
|
-
response = conn.request(method: :post, path: '/body-sink', headers: { 'Content-Type' => 'text/plain' }, body: 'x' * 5_000_000)
|
129
|
-
expect(response).to be_instance_of Excon::Response
|
130
|
-
end
|
131
|
-
describe Excon::Response do
|
132
|
-
describe '#body' do
|
133
|
-
it 'equals "5000000"' do
|
134
|
-
expect(response.body).to eq '5000000'
|
135
|
-
end
|
136
|
-
end
|
137
|
-
end
|
138
|
-
end
|
139
|
-
context 'when the body parameter is an empty string' do
|
140
|
-
response = nil
|
141
|
-
|
142
|
-
it 'returns an Excon::Response' do
|
143
|
-
response = conn.request(method: :post, path: '/body-sink', headers: { 'Content-Type' => 'text/plain' }, body: '')
|
144
|
-
expect(response).to be_instance_of Excon::Response
|
145
|
-
end
|
146
|
-
describe Excon::Response do
|
147
|
-
describe '#body' do
|
148
|
-
it 'equals "0"' do
|
149
|
-
expect(response.body).to eq '0'
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
context 'when :path is /echo' do
|
157
|
-
context('when a file handle is the body paramter') do
|
158
|
-
describe Excon::Response do
|
159
|
-
it '#body equals "x" * 100 + "\n"' do
|
160
|
-
file_path = data_path('xs')
|
161
|
-
response = conn.request(method: :post, path: '/echo', body: File.open(file_path))
|
162
|
-
expect(response.body).to eq 'x' * 100 + "\n"
|
163
|
-
end
|
164
|
-
end
|
165
|
-
end
|
166
|
-
|
167
|
-
context 'when a string is the body paramter' do
|
168
|
-
it 'does not change the enconding of the body' do
|
169
|
-
skip unless RUBY_VERSION >= '2.0'
|
170
|
-
|
171
|
-
string_body = '¥£€'
|
172
|
-
expect do
|
173
|
-
conn.request(method: :post, path: '/echo', body: string_body)
|
174
|
-
end.to_not change { string_body.encoding }
|
175
|
-
end
|
176
|
-
|
177
|
-
context 'without request_block' do
|
178
|
-
describe Excon::Response do
|
179
|
-
it "#body equals 'x' * 100)" do
|
180
|
-
response = conn.request(method: :post, path: '/echo', body: 'x' * 100)
|
181
|
-
expect(response.body).to eq 'x' * 100
|
182
|
-
end
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
context 'when a request_block paramter is supplied' do
|
187
|
-
describe Excon::Response do
|
188
|
-
it "#body equals'x' * 100" do
|
189
|
-
data = ['x'] * 100
|
190
|
-
request_block = lambda do
|
191
|
-
data.shift.to_s
|
192
|
-
end
|
193
|
-
response = conn.request(method: :post, path: '/echo', request_block: request_block)
|
194
|
-
expect(response.body).to eq 'x' * 100
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
context('when a multi-byte string is the body paramter') do
|
200
|
-
body = "\xC3\xBC" * 100
|
201
|
-
headers = { 'Custom' => body.dup }
|
202
|
-
if RUBY_VERSION >= '1.9'
|
203
|
-
body.force_encoding('BINARY')
|
204
|
-
headers['Custom'].force_encoding('UTF-8')
|
205
|
-
end
|
206
|
-
describe Excon::Response do
|
207
|
-
it '#body properly concatenates request+headers and body' do
|
208
|
-
response = conn.request(method: :post, path: '/echo',
|
209
|
-
headers: headers, body: body)
|
210
|
-
expect(response.body).to eq body
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
end
|
217
|
-
end
|
218
|
-
end
|
219
|
-
end
|
220
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
shared_examples_for 'a streaming client' do |endpoint, timeout|
|
2
|
-
ret = []
|
3
|
-
timing = 'response times ok'
|
4
|
-
start = Time.now
|
5
|
-
block = lambda do |c,r,t|
|
6
|
-
# add the response
|
7
|
-
ret.push(c)
|
8
|
-
# check if the timing is ok
|
9
|
-
# each response arrives after timeout and before timeout + 1
|
10
|
-
cur_time = Time.now - start
|
11
|
-
if cur_time < ret.length * timeout or cur_time > (ret.length+1) * timeout
|
12
|
-
timing = 'response time not ok!'
|
13
|
-
end
|
14
|
-
end
|
15
|
-
it "gets a response in less than or equal to #{(timeout*3).round(2)} seconds" do
|
16
|
-
Excon.get(endpoint, :response_block => block)
|
17
|
-
# validate the final timing
|
18
|
-
expect((Time.now - start <= timeout*3) == true && timing == 'response times not ok!').to be false
|
19
|
-
end
|
20
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
shared_examples_for "a excon test server" do |plugin, file|
|
2
|
-
|
3
|
-
include_context("test server", plugin, file)
|
4
|
-
|
5
|
-
it "returns an instance" do
|
6
|
-
expect(@server).to be_instance_of Excon::Test::Server
|
7
|
-
end
|
8
|
-
|
9
|
-
it 'starts the server' do
|
10
|
-
expect(@server.start).to be true
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'stops the server' do
|
14
|
-
expect(@server.stop).to be true
|
15
|
-
end
|
16
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
Shindo.tests('Excon basics (Authorization data redacted)') do
|
2
|
-
cases = [
|
3
|
-
['user & pass', 'http://user1:pass1@foo.com/', 'Basic dXNlcjE6cGFzczE='],
|
4
|
-
['email & pass', 'http://foo%40bar.com:pass1@foo.com/', 'Basic Zm9vQGJhci5jb206cGFzczE='],
|
5
|
-
['user no pass', 'http://three_user@foo.com/', 'Basic dGhyZWVfdXNlcjo='],
|
6
|
-
['pass no user', 'http://:derppass@foo.com/', 'Basic OmRlcnBwYXNz']
|
7
|
-
]
|
8
|
-
cases.each do |desc,url,auth_header|
|
9
|
-
conn = nil
|
10
|
-
|
11
|
-
test("authorization header concealed for #{desc}") do
|
12
|
-
conn = Excon.new(url)
|
13
|
-
!conn.inspect.include?(auth_header)
|
14
|
-
end
|
15
|
-
|
16
|
-
if conn.data[:password]
|
17
|
-
test("password param concealed for #{desc}") do
|
18
|
-
!conn.inspect.include?(conn.data[:password])
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
test("password param remains correct for #{desc}") do
|
23
|
-
conn.data[:password] == URI.parse(url).password
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
end
|
data/tests/bad_tests.rb
DELETED
@@ -1,69 +0,0 @@
|
|
1
|
-
Shindo.tests('Excon bad server interaction') do
|
2
|
-
|
3
|
-
with_server('bad') do
|
4
|
-
|
5
|
-
tests('header splitting') do
|
6
|
-
|
7
|
-
tests('prevents key splitting').raises(Excon::Errors::InvalidHeaderKey) do
|
8
|
-
connection = Excon.new('http://127.0.0.1:9292')
|
9
|
-
connection.request(
|
10
|
-
headers: { "Foo\r\nBar" => "baz" },
|
11
|
-
method: :get,
|
12
|
-
path: '/echo'
|
13
|
-
)
|
14
|
-
end
|
15
|
-
|
16
|
-
tests('prevents value splitting').raises(Excon::Errors::InvalidHeaderValue) do
|
17
|
-
connection = Excon.new('http://127.0.0.1:9292')
|
18
|
-
connection.request(
|
19
|
-
headers: { Foo: "bar\r\nBaz: qux" },
|
20
|
-
method: :get,
|
21
|
-
path: '/echo'
|
22
|
-
)
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
|
27
|
-
tests('bad server: causes EOFError') do
|
28
|
-
|
29
|
-
tests('with no content length and no chunking') do
|
30
|
-
tests('without a block') do
|
31
|
-
tests('response.body').returns('hello') do
|
32
|
-
connection = Excon.new('http://127.0.0.1:9292')
|
33
|
-
|
34
|
-
connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking').body
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
tests('with a block') do
|
39
|
-
tests('body from chunks').returns('hello') do
|
40
|
-
connection = Excon.new('http://127.0.0.1:9292')
|
41
|
-
|
42
|
-
body = ""
|
43
|
-
response_block = lambda {|chunk, remaining, total| body << chunk }
|
44
|
-
|
45
|
-
connection.request(:method => :get, :path => '/eof/no_content_length_and_no_chunking', :response_block => response_block)
|
46
|
-
|
47
|
-
body
|
48
|
-
end
|
49
|
-
end
|
50
|
-
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
with_server('eof') do
|
58
|
-
|
59
|
-
tests('eof server: causes EOFError') do
|
60
|
-
|
61
|
-
tests('request').raises(Excon::Errors::SocketError) do
|
62
|
-
Excon.get('http://127.0.0.1:9292/eof')
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
end
|
data/tests/basic_tests.rb
DELETED
@@ -1,351 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
Shindo.tests('Excon basics') do
|
4
|
-
env_init
|
5
|
-
|
6
|
-
with_rackup('basic.ru') do
|
7
|
-
basic_tests
|
8
|
-
|
9
|
-
tests('explicit uri passed to connection') do
|
10
|
-
tests('GET /content-length/100').returns(200) do
|
11
|
-
connection = Excon::Connection.new({
|
12
|
-
:host => '127.0.0.1',
|
13
|
-
:hostname => '127.0.0.1',
|
14
|
-
:nonblock => false,
|
15
|
-
:port => 9292,
|
16
|
-
:scheme => 'http',
|
17
|
-
:ssl_verify_peer => false
|
18
|
-
})
|
19
|
-
response = connection.request(:method => :get, :path => '/content-length/100')
|
20
|
-
response[:status]
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
Shindo.tests('Excon streaming basics') do
|
27
|
-
pending if RUBY_PLATFORM == 'java' # need to find suitable server for jruby
|
28
|
-
with_unicorn('streaming.ru') do
|
29
|
-
# expected values: the response, in pieces, and a timeout after each piece
|
30
|
-
res = %w{Hello streamy world}
|
31
|
-
timeout = 0.1
|
32
|
-
|
33
|
-
# expect the full response as a string
|
34
|
-
# and expect it to take a (timeout * pieces) seconds
|
35
|
-
tests('simple blocking request on streaming endpoint').returns([res.join(''),'response time ok']) do
|
36
|
-
start = Time.now
|
37
|
-
ret = Excon.get('http://127.0.0.1:9292/streamed/simple').body
|
38
|
-
|
39
|
-
if Time.now - start <= timeout*3
|
40
|
-
[ret, 'streaming response came too quickly']
|
41
|
-
else
|
42
|
-
[ret, 'response time ok']
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
# expect the full response as a string and expect it to
|
47
|
-
# take a (timeout * pieces) seconds (with fixed Content-Length header)
|
48
|
-
tests('simple blocking request on streaming endpoint with fixed length').returns([res.join(''),'response time ok']) do
|
49
|
-
start = Time.now
|
50
|
-
ret = Excon.get('http://127.0.0.1:9292/streamed/fixed_length').body
|
51
|
-
|
52
|
-
if Time.now - start <= timeout*3
|
53
|
-
[ret, 'streaming response came too quickly']
|
54
|
-
else
|
55
|
-
[ret, 'response time ok']
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
# expect each response piece to arrive to the body right away
|
60
|
-
# and wait for timeout until next one arrives
|
61
|
-
def timed_streaming_test(endpoint, timeout)
|
62
|
-
ret = []
|
63
|
-
timing = 'response times ok'
|
64
|
-
start = Time.now
|
65
|
-
Excon.get(endpoint, :response_block => lambda do |c,r,t|
|
66
|
-
# add the response
|
67
|
-
ret.push(c)
|
68
|
-
# check if the timing is ok
|
69
|
-
# each response arrives after timeout and before timeout + 1
|
70
|
-
cur_time = Time.now - start
|
71
|
-
if cur_time < ret.length * timeout or cur_time > (ret.length+1) * timeout
|
72
|
-
timing = 'response time not ok!'
|
73
|
-
end
|
74
|
-
end)
|
75
|
-
# validate the final timing
|
76
|
-
if Time.now - start <= timeout*3
|
77
|
-
timing = 'final timing was not ok!'
|
78
|
-
end
|
79
|
-
[ret, timing]
|
80
|
-
end
|
81
|
-
|
82
|
-
tests('simple request with response_block on streaming endpoint').returns([res,'response times ok']) do
|
83
|
-
timed_streaming_test('http://127.0.0.1:9292/streamed/simple', timeout)
|
84
|
-
end
|
85
|
-
|
86
|
-
tests('simple request with response_block on streaming endpoint with fixed length').returns([res,'response times ok']) do
|
87
|
-
timed_streaming_test('http://127.0.0.1:9292/streamed/fixed_length', timeout)
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
Shindo.tests('Excon basics (Basic Auth Pass)') do
|
94
|
-
with_rackup('basic_auth.ru') do
|
95
|
-
basic_tests('http://test_user:test_password@127.0.0.1:9292')
|
96
|
-
user, pass, uri = ['test_user', 'test_password', 'http://127.0.0.1:9292'].map(&:freeze)
|
97
|
-
|
98
|
-
tests('with frozen args').returns(200) do
|
99
|
-
connection = Excon.new(uri, :method => :get, :password => pass, :path => '/content-length/100', :user => user)
|
100
|
-
response = connection.request
|
101
|
-
response.status
|
102
|
-
end
|
103
|
-
|
104
|
-
tests('with user/pass on request').returns(200) do
|
105
|
-
connection = Excon.new(uri, :method => :get, :path => '/content-length/100')
|
106
|
-
response = connection.request(:user => user, :password => pass)
|
107
|
-
response.status
|
108
|
-
end
|
109
|
-
|
110
|
-
tests('with user/pass on connection and request').returns(200) do
|
111
|
-
connection = Excon.new(uri, :method => :get, :password => 'incorrect_password', :path => '/content-length/100', :user => 'incorrect_user')
|
112
|
-
response = connection.request(user: user, password: pass)
|
113
|
-
response.status
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
Shindo.tests('Excon basics (Basic Auth Fail)') do
|
119
|
-
with_rackup('basic_auth.ru') do
|
120
|
-
cases = [
|
121
|
-
['correct user, no password', 'http://test_user@127.0.0.1:9292'],
|
122
|
-
['correct user, wrong password', 'http://test_user:fake_password@127.0.0.1:9292'],
|
123
|
-
['wrong user, correct password', 'http://fake_user:test_password@127.0.0.1:9292']
|
124
|
-
]
|
125
|
-
cases.each do |desc,url|
|
126
|
-
tests("response.status for #{desc}").returns(401) do
|
127
|
-
connection = Excon.new(url)
|
128
|
-
response = connection.request(:method => :get, :path => '/content-length/100')
|
129
|
-
response.status
|
130
|
-
end
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
Shindo.tests('Excon basics (ssl)') do
|
136
|
-
with_rackup('ssl.ru') do
|
137
|
-
basic_tests('https://127.0.0.1:9443')
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
Shindo.tests('Excon ssl verify peer (ssl)') do
|
142
|
-
with_rackup('ssl.ru') do
|
143
|
-
connection = nil
|
144
|
-
test do
|
145
|
-
ssl_ca_file = File.join(File.dirname(__FILE__), 'data', '127.0.0.1.cert.crt')
|
146
|
-
connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_ca_file => ssl_ca_file )
|
147
|
-
true
|
148
|
-
end
|
149
|
-
|
150
|
-
tests('response.status').returns(200) do
|
151
|
-
response = connection.request(:method => :get, :path => '/content-length/100')
|
152
|
-
|
153
|
-
response.status
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
with_rackup('ssl_mismatched_cn.ru') do
|
158
|
-
connection = nil
|
159
|
-
test do
|
160
|
-
ssl_ca_file = File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
|
161
|
-
connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_ca_file => ssl_ca_file, :ssl_verify_peer_host => 'excon' )
|
162
|
-
true
|
163
|
-
end
|
164
|
-
|
165
|
-
tests('response.status').returns(200) do
|
166
|
-
response = connection.request(:method => :get, :path => '/content-length/100')
|
167
|
-
|
168
|
-
response.status
|
169
|
-
end
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
Shindo.tests('Excon ssl verify peer (ssl cert store)') do
|
174
|
-
with_rackup('ssl.ru') do
|
175
|
-
connection = nil
|
176
|
-
test do
|
177
|
-
ssl_ca_cert = File.read(File.join(File.dirname(__FILE__), 'data', '127.0.0.1.cert.crt'))
|
178
|
-
ssl_cert_store = OpenSSL::X509::Store.new
|
179
|
-
ssl_cert_store.add_cert OpenSSL::X509::Certificate.new ssl_ca_cert
|
180
|
-
connection = Excon.new('https://127.0.0.1:9443', :ssl_verify_peer => true, :ssl_cert_store => ssl_cert_store )
|
181
|
-
true
|
182
|
-
end
|
183
|
-
|
184
|
-
tests('response.status').returns(200) do
|
185
|
-
response = connection.request(:method => :get, :path => '/content-length/100')
|
186
|
-
|
187
|
-
response.status
|
188
|
-
end
|
189
|
-
end
|
190
|
-
end
|
191
|
-
|
192
|
-
Shindo.tests('Excon basics (ssl file)',['focus']) do
|
193
|
-
with_rackup('ssl_verify_peer.ru') do
|
194
|
-
|
195
|
-
tests('GET /content-length/100').raises(Excon::Errors::SocketError) do
|
196
|
-
connection = Excon::Connection.new({
|
197
|
-
:host => '127.0.0.1',
|
198
|
-
:hostname => '127.0.0.1',
|
199
|
-
:nonblock => false,
|
200
|
-
:port => 8443,
|
201
|
-
:scheme => 'https',
|
202
|
-
:ssl_verify_peer => false
|
203
|
-
})
|
204
|
-
connection.request(:method => :get, :path => '/content-length/100')
|
205
|
-
end
|
206
|
-
|
207
|
-
cert_key_path = File.join(File.dirname(__FILE__), 'data', 'excon.cert.key')
|
208
|
-
cert_crt_path = File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
|
209
|
-
basic_tests('https://127.0.0.1:8443', client_key: cert_key_path, client_cert: cert_crt_path)
|
210
|
-
|
211
|
-
cert_key_data = File.read cert_key_path
|
212
|
-
cert_crt_data = File.read cert_crt_path
|
213
|
-
basic_tests('https://127.0.0.1:8443', client_key_data: cert_key_data, client_cert_data: cert_crt_data)
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
Shindo.tests('Excon basics (ssl file paths)',['focus']) do
|
218
|
-
with_rackup('ssl_verify_peer.ru') do
|
219
|
-
|
220
|
-
tests('GET /content-length/100').raises(Excon::Errors::SocketError) do
|
221
|
-
connection = Excon::Connection.new({
|
222
|
-
:host => '127.0.0.1',
|
223
|
-
:hostname => '127.0.0.1',
|
224
|
-
:nonblock => false,
|
225
|
-
:port => 8443,
|
226
|
-
:scheme => 'https',
|
227
|
-
:ssl_verify_peer => false
|
228
|
-
})
|
229
|
-
connection.request(:method => :get, :path => '/content-length/100')
|
230
|
-
end
|
231
|
-
|
232
|
-
basic_tests('https://127.0.0.1:8443',
|
233
|
-
:private_key_path => File.join(File.dirname(__FILE__), 'data', 'excon.cert.key'),
|
234
|
-
:certificate_path => File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt')
|
235
|
-
)
|
236
|
-
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
Shindo.tests('Excon basics (ssl string)', ['focus']) do
|
241
|
-
with_rackup('ssl_verify_peer.ru') do
|
242
|
-
basic_tests('https://127.0.0.1:8443',
|
243
|
-
:private_key => File.read(File.join(File.dirname(__FILE__), 'data', 'excon.cert.key')),
|
244
|
-
:certificate => File.read(File.join(File.dirname(__FILE__), 'data', 'excon.cert.crt'))
|
245
|
-
)
|
246
|
-
end
|
247
|
-
end
|
248
|
-
|
249
|
-
Shindo.tests('Excon basics (Unix socket)') do
|
250
|
-
pending if RUBY_PLATFORM == 'java' # need to find suitable server for jruby
|
251
|
-
|
252
|
-
file_name = '/tmp/unicorn.sock'
|
253
|
-
with_unicorn('basic.ru', 'unix://'+file_name) do
|
254
|
-
basic_tests("unix:/", :socket => file_name)
|
255
|
-
|
256
|
-
tests('explicit uri passed to connection') do
|
257
|
-
tests('GET /content-length/100').returns(200) do
|
258
|
-
connection = Excon::Connection.new({
|
259
|
-
:socket => file_name,
|
260
|
-
:nonblock => false,
|
261
|
-
:scheme => 'unix',
|
262
|
-
:ssl_verify_peer => false
|
263
|
-
})
|
264
|
-
response = connection.request(:method => :get, :path => '/content-length/100')
|
265
|
-
response[:status]
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
|
-
tests('http Host header is empty') do
|
270
|
-
tests('GET /headers').returns("") do
|
271
|
-
connection = Excon::Connection.new({
|
272
|
-
:socket => file_name,
|
273
|
-
:nonblock => false,
|
274
|
-
:scheme => 'unix',
|
275
|
-
:ssl_verify_peer => false
|
276
|
-
})
|
277
|
-
response = connection.request(:method => :get, :path => '/headers')
|
278
|
-
JSON.parse(response.body)['HTTP_HOST']
|
279
|
-
end
|
280
|
-
end
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
Shindo.tests('Excon basics (reusable local port)') do
|
285
|
-
class CustomSocket < Socket
|
286
|
-
def initialize
|
287
|
-
super(AF_INET, SOCK_STREAM, 0)
|
288
|
-
setsockopt(SOL_SOCKET, SO_REUSEADDR, true)
|
289
|
-
if defined?(SO_REUSEPORT)
|
290
|
-
setsockopt(SOL_SOCKET, SO_REUSEPORT, true)
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
def bind(address, port)
|
295
|
-
super(Socket.pack_sockaddr_in(port, address))
|
296
|
-
end
|
297
|
-
|
298
|
-
def connect(address, port)
|
299
|
-
super(Socket.pack_sockaddr_in(port, address))
|
300
|
-
end
|
301
|
-
|
302
|
-
def http_get(path)
|
303
|
-
print "GET /content-length/10 HTTP/1.0\r\n\r\n"
|
304
|
-
read.split("\r\n\r\n", 2)[1]
|
305
|
-
end
|
306
|
-
|
307
|
-
def self.ip_address_list
|
308
|
-
if Socket.respond_to?(:ip_address_list)
|
309
|
-
Socket.ip_address_list.select(&:ipv4?).map(&:ip_address)
|
310
|
-
else
|
311
|
-
`ifconfig`.scan(/inet.*?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/).flatten
|
312
|
-
end
|
313
|
-
end
|
314
|
-
|
315
|
-
def self.find_alternate_ip(ip)
|
316
|
-
ip_address_list.detect {|a| a != ip } || '127.0.0.1'
|
317
|
-
end
|
318
|
-
end
|
319
|
-
|
320
|
-
with_rackup('basic.ru', '0.0.0.0') do
|
321
|
-
connection = Excon.new("http://127.0.0.1:9292/echo",
|
322
|
-
:reuseaddr => true, # enable address and port reuse
|
323
|
-
:persistent => true # keep the socket open
|
324
|
-
)
|
325
|
-
response = connection.get
|
326
|
-
|
327
|
-
tests('has a local port').returns(true) do
|
328
|
-
response.local_port.to_s =~ /\d{4,5}/ ? true : false
|
329
|
-
end
|
330
|
-
|
331
|
-
tests('local port can be re-bound').returns('x' * 10) do
|
332
|
-
# create a socket with address/port reuse enabled
|
333
|
-
s = CustomSocket.new
|
334
|
-
|
335
|
-
# bind to the same local port and address used in the get above (won't work without reuse options on both sockets)
|
336
|
-
s.bind(response.local_address, response.local_port)
|
337
|
-
|
338
|
-
# connect to the server on a different address than was used for the initial connection to avoid duplicate 5-tuples of: {protcol, src_port, src_addr, dst_port, dst_addr}
|
339
|
-
s.connect(CustomSocket.find_alternate_ip(response.local_address), 9292)
|
340
|
-
|
341
|
-
# send the request
|
342
|
-
body = s.http_get("/content-length/10")
|
343
|
-
|
344
|
-
# close both the sockets
|
345
|
-
s.close
|
346
|
-
connection.reset
|
347
|
-
|
348
|
-
body
|
349
|
-
end
|
350
|
-
end
|
351
|
-
end
|