http 5.3.1 → 6.0.0
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 +4 -4
- data/CHANGELOG.md +241 -41
- data/LICENSE.txt +1 -1
- data/README.md +110 -13
- data/UPGRADING.md +491 -0
- data/http.gemspec +32 -29
- data/lib/http/base64.rb +11 -1
- data/lib/http/chainable/helpers.rb +62 -0
- data/lib/http/chainable/verbs.rb +136 -0
- data/lib/http/chainable.rb +232 -136
- data/lib/http/client.rb +158 -127
- data/lib/http/connection/internals.rb +141 -0
- data/lib/http/connection.rb +126 -97
- data/lib/http/content_type.rb +61 -6
- data/lib/http/errors.rb +25 -1
- data/lib/http/feature.rb +65 -5
- data/lib/http/features/auto_deflate.rb +124 -17
- data/lib/http/features/auto_inflate.rb +38 -15
- data/lib/http/features/caching/entry.rb +178 -0
- data/lib/http/features/caching/in_memory_store.rb +63 -0
- data/lib/http/features/caching.rb +216 -0
- data/lib/http/features/digest_auth.rb +234 -0
- data/lib/http/features/instrumentation.rb +97 -17
- data/lib/http/features/logging.rb +183 -5
- data/lib/http/features/normalize_uri.rb +17 -0
- data/lib/http/features/raise_error.rb +18 -3
- data/lib/http/form_data/composite_io.rb +106 -0
- data/lib/http/form_data/file.rb +95 -0
- data/lib/http/form_data/multipart/param.rb +62 -0
- data/lib/http/form_data/multipart.rb +106 -0
- data/lib/http/form_data/part.rb +52 -0
- data/lib/http/form_data/readable.rb +58 -0
- data/lib/http/form_data/urlencoded.rb +175 -0
- data/lib/http/form_data/version.rb +8 -0
- data/lib/http/form_data.rb +102 -0
- data/lib/http/headers/known.rb +3 -0
- data/lib/http/headers/normalizer.rb +17 -36
- data/lib/http/headers.rb +172 -65
- data/lib/http/mime_type/adapter.rb +24 -9
- data/lib/http/mime_type/json.rb +19 -4
- data/lib/http/mime_type.rb +21 -3
- data/lib/http/options/definitions.rb +189 -0
- data/lib/http/options.rb +172 -125
- data/lib/http/redirector.rb +80 -75
- data/lib/http/request/body.rb +87 -6
- data/lib/http/request/builder.rb +184 -0
- data/lib/http/request/proxy.rb +83 -0
- data/lib/http/request/writer.rb +76 -16
- data/lib/http/request.rb +214 -98
- data/lib/http/response/body.rb +103 -18
- data/lib/http/response/inflater.rb +35 -7
- data/lib/http/response/parser.rb +98 -4
- data/lib/http/response/status/reasons.rb +2 -4
- data/lib/http/response/status.rb +141 -31
- data/lib/http/response.rb +219 -61
- data/lib/http/retriable/delay_calculator.rb +38 -11
- data/lib/http/retriable/errors.rb +21 -0
- data/lib/http/retriable/performer.rb +82 -38
- data/lib/http/session.rb +280 -0
- data/lib/http/timeout/global.rb +147 -34
- data/lib/http/timeout/null.rb +155 -9
- data/lib/http/timeout/per_operation.rb +139 -18
- data/lib/http/uri/normalizer.rb +82 -0
- data/lib/http/uri/parsing.rb +182 -0
- data/lib/http/uri.rb +289 -124
- data/lib/http/version.rb +2 -1
- data/lib/http.rb +11 -2
- data/sig/deps.rbs +122 -0
- data/sig/http.rbs +1619 -0
- data/test/http/base64_test.rb +28 -0
- data/test/http/client_test.rb +739 -0
- data/test/http/connection_test.rb +1533 -0
- data/test/http/content_type_test.rb +190 -0
- data/test/http/errors_test.rb +28 -0
- data/test/http/feature_test.rb +49 -0
- data/test/http/features/auto_deflate_test.rb +317 -0
- data/test/http/features/auto_inflate_test.rb +213 -0
- data/test/http/features/caching_test.rb +942 -0
- data/test/http/features/digest_auth_test.rb +996 -0
- data/test/http/features/instrumentation_test.rb +246 -0
- data/test/http/features/logging_test.rb +654 -0
- data/test/http/features/normalize_uri_test.rb +41 -0
- data/test/http/features/raise_error_test.rb +77 -0
- data/test/http/form_data/composite_io_test.rb +215 -0
- data/test/http/form_data/file_test.rb +255 -0
- data/test/http/form_data/fixtures/the-http-gem.info +1 -0
- data/test/http/form_data/multipart_test.rb +303 -0
- data/test/http/form_data/part_test.rb +90 -0
- data/test/http/form_data/urlencoded_test.rb +164 -0
- data/test/http/form_data_test.rb +232 -0
- data/test/http/headers/normalizer_test.rb +93 -0
- data/test/http/headers_test.rb +888 -0
- data/test/http/mime_type/json_test.rb +39 -0
- data/test/http/mime_type_test.rb +150 -0
- data/test/http/options/base_uri_test.rb +148 -0
- data/test/http/options/body_test.rb +21 -0
- data/test/http/options/features_test.rb +38 -0
- data/test/http/options/form_test.rb +21 -0
- data/test/http/options/headers_test.rb +32 -0
- data/test/http/options/json_test.rb +21 -0
- data/test/http/options/merge_test.rb +78 -0
- data/test/http/options/new_test.rb +37 -0
- data/test/http/options/proxy_test.rb +32 -0
- data/test/http/options_test.rb +575 -0
- data/test/http/redirector_test.rb +639 -0
- data/test/http/request/body_test.rb +318 -0
- data/test/http/request/builder_test.rb +623 -0
- data/test/http/request/writer_test.rb +391 -0
- data/test/http/request_test.rb +1733 -0
- data/test/http/response/body_test.rb +292 -0
- data/test/http/response/parser_test.rb +105 -0
- data/test/http/response/status_test.rb +322 -0
- data/test/http/response_test.rb +502 -0
- data/test/http/retriable/delay_calculator_test.rb +194 -0
- data/test/http/retriable/errors_test.rb +71 -0
- data/test/http/retriable/performer_test.rb +551 -0
- data/test/http/session_test.rb +424 -0
- data/test/http/timeout/global_test.rb +239 -0
- data/test/http/timeout/null_test.rb +218 -0
- data/test/http/timeout/per_operation_test.rb +220 -0
- data/test/http/uri/normalizer_test.rb +89 -0
- data/test/http/uri_test.rb +1140 -0
- data/test/http/version_test.rb +15 -0
- data/test/http_test.rb +818 -0
- data/test/regression_tests.rb +27 -0
- data/test/support/dummy_server/encoding_routes.rb +47 -0
- data/test/support/dummy_server/routes.rb +201 -0
- data/test/support/dummy_server/servlet.rb +81 -0
- data/test/support/dummy_server.rb +200 -0
- data/{spec → test}/support/fakeio.rb +2 -2
- data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
- data/test/support/http_handling_shared/timeout_tests.rb +134 -0
- data/test/support/http_handling_shared.rb +11 -0
- data/test/support/proxy_server.rb +207 -0
- data/test/support/servers/runner.rb +67 -0
- data/{spec → test}/support/simplecov.rb +11 -2
- data/test/support/ssl_helper.rb +108 -0
- data/test/test_helper.rb +38 -0
- metadata +108 -168
- data/.github/workflows/ci.yml +0 -67
- data/.gitignore +0 -15
- data/.rspec +0 -1
- data/.rubocop/layout.yml +0 -8
- data/.rubocop/metrics.yml +0 -4
- data/.rubocop/rspec.yml +0 -9
- data/.rubocop/style.yml +0 -32
- data/.rubocop.yml +0 -11
- data/.rubocop_todo.yml +0 -219
- data/.yardopts +0 -2
- data/CHANGES_OLD.md +0 -1002
- data/Gemfile +0 -51
- data/Guardfile +0 -18
- data/Rakefile +0 -64
- data/lib/http/headers/mixin.rb +0 -34
- data/lib/http/retriable/client.rb +0 -37
- data/logo.png +0 -0
- data/spec/lib/http/client_spec.rb +0 -556
- data/spec/lib/http/connection_spec.rb +0 -88
- data/spec/lib/http/content_type_spec.rb +0 -47
- data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
- data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
- data/spec/lib/http/features/instrumentation_spec.rb +0 -81
- data/spec/lib/http/features/logging_spec.rb +0 -65
- data/spec/lib/http/features/raise_error_spec.rb +0 -62
- data/spec/lib/http/headers/mixin_spec.rb +0 -36
- data/spec/lib/http/headers/normalizer_spec.rb +0 -52
- data/spec/lib/http/headers_spec.rb +0 -527
- data/spec/lib/http/options/body_spec.rb +0 -15
- data/spec/lib/http/options/features_spec.rb +0 -33
- data/spec/lib/http/options/form_spec.rb +0 -15
- data/spec/lib/http/options/headers_spec.rb +0 -24
- data/spec/lib/http/options/json_spec.rb +0 -15
- data/spec/lib/http/options/merge_spec.rb +0 -68
- data/spec/lib/http/options/new_spec.rb +0 -30
- data/spec/lib/http/options/proxy_spec.rb +0 -20
- data/spec/lib/http/options_spec.rb +0 -13
- data/spec/lib/http/redirector_spec.rb +0 -530
- data/spec/lib/http/request/body_spec.rb +0 -211
- data/spec/lib/http/request/writer_spec.rb +0 -121
- data/spec/lib/http/request_spec.rb +0 -234
- data/spec/lib/http/response/body_spec.rb +0 -85
- data/spec/lib/http/response/parser_spec.rb +0 -74
- data/spec/lib/http/response/status_spec.rb +0 -253
- data/spec/lib/http/response_spec.rb +0 -262
- data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
- data/spec/lib/http/retriable/performer_spec.rb +0 -302
- data/spec/lib/http/uri/normalizer_spec.rb +0 -95
- data/spec/lib/http/uri_spec.rb +0 -71
- data/spec/lib/http_spec.rb +0 -535
- data/spec/regression_specs.rb +0 -24
- data/spec/spec_helper.rb +0 -89
- data/spec/support/black_hole.rb +0 -13
- data/spec/support/dummy_server/servlet.rb +0 -203
- data/spec/support/dummy_server.rb +0 -44
- data/spec/support/fuubar.rb +0 -21
- data/spec/support/http_handling_shared.rb +0 -190
- data/spec/support/proxy_server.rb +0 -39
- data/spec/support/servers/config.rb +0 -11
- data/spec/support/servers/runner.rb +0 -19
- data/spec/support/ssl_helper.rb +0 -104
- /data/{spec → test}/support/capture_warning.rb +0 -0
data/spec/lib/http_spec.rb
DELETED
|
@@ -1,535 +0,0 @@
|
|
|
1
|
-
# encoding: utf-8
|
|
2
|
-
# frozen_string_literal: true
|
|
3
|
-
|
|
4
|
-
require "json"
|
|
5
|
-
|
|
6
|
-
require "support/dummy_server"
|
|
7
|
-
require "support/proxy_server"
|
|
8
|
-
|
|
9
|
-
RSpec.describe HTTP do
|
|
10
|
-
run_server(:dummy) { DummyServer.new }
|
|
11
|
-
run_server(:dummy_ssl) { DummyServer.new(:ssl => true) }
|
|
12
|
-
|
|
13
|
-
let(:ssl_client) do
|
|
14
|
-
HTTP::Client.new :ssl_context => SSLHelper.client_context
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
context "getting resources" do
|
|
18
|
-
it "is easy" do
|
|
19
|
-
response = HTTP.get dummy.endpoint
|
|
20
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context "with URI instance" do
|
|
24
|
-
it "is easy" do
|
|
25
|
-
response = HTTP.get HTTP::URI.parse dummy.endpoint
|
|
26
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
context "with query string parameters" do
|
|
31
|
-
it "is easy" do
|
|
32
|
-
response = HTTP.get "#{dummy.endpoint}/params", :params => {:foo => "bar"}
|
|
33
|
-
expect(response.to_s).to match(/Params!/)
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
context "with query string parameters in the URI and opts hash" do
|
|
38
|
-
it "includes both" do
|
|
39
|
-
response = HTTP.get "#{dummy.endpoint}/multiple-params?foo=bar", :params => {:baz => "quux"}
|
|
40
|
-
expect(response.to_s).to match(/More Params!/)
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
context "with two leading slashes in path" do
|
|
45
|
-
it "is allowed" do
|
|
46
|
-
expect { HTTP.get "#{dummy.endpoint}//" }.not_to raise_error
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
context "with headers" do
|
|
51
|
-
it "is easy" do
|
|
52
|
-
response = HTTP.accept("application/json").get dummy.endpoint
|
|
53
|
-
expect(response.to_s.include?("json")).to be true
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
context "with a large request body" do
|
|
58
|
-
let(:request_body) { "“" * 1_000_000 } # use multi-byte character
|
|
59
|
-
|
|
60
|
-
[:null, 6, {:read => 2, :write => 2, :connect => 2}].each do |timeout|
|
|
61
|
-
context "with `.timeout(#{timeout.inspect})`" do
|
|
62
|
-
let(:client) { HTTP.timeout(timeout) }
|
|
63
|
-
|
|
64
|
-
it "writes the whole body" do
|
|
65
|
-
response = client.post "#{dummy.endpoint}/echo-body", :body => request_body
|
|
66
|
-
|
|
67
|
-
expect(response.body.to_s).to eq(request_body.b)
|
|
68
|
-
expect(response.headers["Content-Length"].to_i).to eq request_body.bytesize
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
describe ".via" do
|
|
76
|
-
context "anonymous proxy" do
|
|
77
|
-
run_server(:proxy) { ProxyServer.new }
|
|
78
|
-
|
|
79
|
-
it "proxies the request" do
|
|
80
|
-
response = HTTP.via(proxy.addr, proxy.port).get dummy.endpoint
|
|
81
|
-
expect(response.headers["X-Proxied"]).to eq "true"
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
it "responds with the endpoint's body" do
|
|
85
|
-
response = HTTP.via(proxy.addr, proxy.port).get dummy.endpoint
|
|
86
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
it "raises an argument error if no port given" do
|
|
90
|
-
expect { HTTP.via(proxy.addr) }.to raise_error HTTP::RequestError
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
it "ignores credentials" do
|
|
94
|
-
response = HTTP.via(proxy.addr, proxy.port, "username", "password").get dummy.endpoint
|
|
95
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# TODO: htt:s://github.com/httprb/http/issues/627
|
|
99
|
-
xcontext "ssl" do
|
|
100
|
-
it "responds with the endpoint's body" do
|
|
101
|
-
response = ssl_client.via(proxy.addr, proxy.port).get dummy_ssl.endpoint
|
|
102
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
it "ignores credentials" do
|
|
106
|
-
response = ssl_client.via(proxy.addr, proxy.port, "username", "password").get dummy_ssl.endpoint
|
|
107
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
context "proxy with authentication" do
|
|
113
|
-
run_server(:proxy) { AuthProxyServer.new }
|
|
114
|
-
|
|
115
|
-
it "proxies the request" do
|
|
116
|
-
response = HTTP.via(proxy.addr, proxy.port, "username", "password").get dummy.endpoint
|
|
117
|
-
expect(response.headers["X-Proxied"]).to eq "true"
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
it "responds with the endpoint's body" do
|
|
121
|
-
response = HTTP.via(proxy.addr, proxy.port, "username", "password").get dummy.endpoint
|
|
122
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
it "responds with 407 when wrong credentials given" do
|
|
126
|
-
response = HTTP.via(proxy.addr, proxy.port, "user", "pass").get dummy.endpoint
|
|
127
|
-
expect(response.status).to eq(407)
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
it "responds with 407 if no credentials given" do
|
|
131
|
-
response = HTTP.via(proxy.addr, proxy.port).get dummy.endpoint
|
|
132
|
-
expect(response.status).to eq(407)
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
# TODO: htt:s://github.com/httprb/http/issues/627
|
|
136
|
-
xcontext "ssl" do
|
|
137
|
-
it "responds with the endpoint's body" do
|
|
138
|
-
response = ssl_client.via(proxy.addr, proxy.port, "username", "password").get dummy_ssl.endpoint
|
|
139
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
it "responds with 407 when wrong credentials given" do
|
|
143
|
-
response = ssl_client.via(proxy.addr, proxy.port, "user", "pass").get dummy_ssl.endpoint
|
|
144
|
-
expect(response.status).to eq(407)
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
it "responds with 407 if no credentials given" do
|
|
148
|
-
response = ssl_client.via(proxy.addr, proxy.port).get dummy_ssl.endpoint
|
|
149
|
-
expect(response.status).to eq(407)
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
describe ".retry" do
|
|
156
|
-
it "ensure endpoint counts retries" do
|
|
157
|
-
expect(HTTP.get("#{dummy.endpoint}/retry-2").to_s).to eq "retried 1x"
|
|
158
|
-
expect(HTTP.get("#{dummy.endpoint}/retry-2").to_s).to eq "retried 2x"
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
it "retries the request" do
|
|
162
|
-
response = HTTP.retriable(delay: 0, retry_statuses: 500...600).get "#{dummy.endpoint}/retry-2"
|
|
163
|
-
expect(response.to_s).to eq "retried 2x"
|
|
164
|
-
end
|
|
165
|
-
|
|
166
|
-
it "retries the request and gives us access to the failed requests" do
|
|
167
|
-
err = nil
|
|
168
|
-
retry_callback = ->(_, _, res) { expect(res.to_s).to match(/^retried \dx$/) }
|
|
169
|
-
begin
|
|
170
|
-
HTTP.retriable(
|
|
171
|
-
should_retry: ->(*) { true },
|
|
172
|
-
tries: 3,
|
|
173
|
-
delay: 0,
|
|
174
|
-
on_retry: retry_callback
|
|
175
|
-
).get "#{dummy.endpoint}/retry-2"
|
|
176
|
-
rescue HTTP::Error => e
|
|
177
|
-
err = e
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
expect(err.response.to_s).to eq "retried 3x"
|
|
181
|
-
end
|
|
182
|
-
end
|
|
183
|
-
|
|
184
|
-
context "posting forms to resources" do
|
|
185
|
-
it "is easy" do
|
|
186
|
-
response = HTTP.post "#{dummy.endpoint}/form", :form => {:example => "testing-form"}
|
|
187
|
-
expect(response.to_s).to eq("passed :)")
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
context "loading binary data" do
|
|
192
|
-
it "is encoded as bytes" do
|
|
193
|
-
response = HTTP.get "#{dummy.endpoint}/bytes"
|
|
194
|
-
expect(response.to_s.encoding).to eq(Encoding::BINARY)
|
|
195
|
-
end
|
|
196
|
-
end
|
|
197
|
-
|
|
198
|
-
context "loading endpoint with charset" do
|
|
199
|
-
it "uses charset from headers" do
|
|
200
|
-
response = HTTP.get "#{dummy.endpoint}/iso-8859-1"
|
|
201
|
-
expect(response.to_s.encoding).to eq(Encoding::ISO8859_1)
|
|
202
|
-
expect(response.to_s.encode(Encoding::UTF_8)).to eq("testæ")
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
context "with encoding option" do
|
|
206
|
-
it "respects option" do
|
|
207
|
-
response = HTTP.get "#{dummy.endpoint}/iso-8859-1", :encoding => Encoding::BINARY
|
|
208
|
-
expect(response.to_s.encoding).to eq(Encoding::BINARY)
|
|
209
|
-
end
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
context "passing a string encoding type" do
|
|
214
|
-
it "finds encoding" do
|
|
215
|
-
response = HTTP.get dummy.endpoint, :encoding => "ascii"
|
|
216
|
-
expect(response.to_s.encoding).to eq(Encoding::ASCII)
|
|
217
|
-
end
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
context "loading text with no charset" do
|
|
221
|
-
it "is binary encoded" do
|
|
222
|
-
response = HTTP.get dummy.endpoint
|
|
223
|
-
expect(response.to_s.encoding).to eq(Encoding::BINARY)
|
|
224
|
-
end
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
context "posting with an explicit body" do
|
|
228
|
-
it "is easy" do
|
|
229
|
-
response = HTTP.post "#{dummy.endpoint}/body", :body => "testing-body"
|
|
230
|
-
expect(response.to_s).to eq("passed :)")
|
|
231
|
-
end
|
|
232
|
-
end
|
|
233
|
-
|
|
234
|
-
context "with redirects" do
|
|
235
|
-
it "is easy for 301" do
|
|
236
|
-
response = HTTP.follow.get("#{dummy.endpoint}/redirect-301")
|
|
237
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
it "is easy for 302" do
|
|
241
|
-
response = HTTP.follow.get("#{dummy.endpoint}/redirect-302")
|
|
242
|
-
expect(response.to_s).to match(/<!doctype html>/)
|
|
243
|
-
end
|
|
244
|
-
end
|
|
245
|
-
|
|
246
|
-
context "head requests" do
|
|
247
|
-
it "is easy" do
|
|
248
|
-
response = HTTP.head dummy.endpoint
|
|
249
|
-
expect(response.status).to eq(200)
|
|
250
|
-
expect(response["content-type"]).to match(/html/)
|
|
251
|
-
end
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
describe ".auth" do
|
|
255
|
-
it "sets Authorization header to the given value" do
|
|
256
|
-
client = HTTP.auth "abc"
|
|
257
|
-
expect(client.default_options.headers[:authorization]).to eq "abc"
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
it "accepts any #to_s object" do
|
|
261
|
-
client = HTTP.auth double :to_s => "abc"
|
|
262
|
-
expect(client.default_options.headers[:authorization]).to eq "abc"
|
|
263
|
-
end
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
describe ".basic_auth" do
|
|
267
|
-
it "fails when options is not a Hash" do
|
|
268
|
-
expect { HTTP.basic_auth "[FOOBAR]" }.to raise_error(NoMethodError)
|
|
269
|
-
end
|
|
270
|
-
|
|
271
|
-
it "fails when :pass is not given" do
|
|
272
|
-
expect { HTTP.basic_auth :user => "[USER]" }.to raise_error(KeyError)
|
|
273
|
-
end
|
|
274
|
-
|
|
275
|
-
it "fails when :user is not given" do
|
|
276
|
-
expect { HTTP.basic_auth :pass => "[PASS]" }.to raise_error(KeyError)
|
|
277
|
-
end
|
|
278
|
-
|
|
279
|
-
it "sets Authorization header with proper BasicAuth value" do
|
|
280
|
-
client = HTTP.basic_auth :user => "foo", :pass => "bar"
|
|
281
|
-
expect(client.default_options.headers[:authorization]).
|
|
282
|
-
to match(%r{^Basic [A-Za-z0-9+/]+=*$})
|
|
283
|
-
end
|
|
284
|
-
end
|
|
285
|
-
|
|
286
|
-
describe ".persistent" do
|
|
287
|
-
let(:host) { "https://api.github.com" }
|
|
288
|
-
|
|
289
|
-
context "with host only given" do
|
|
290
|
-
subject { HTTP.persistent host }
|
|
291
|
-
it { is_expected.to be_an HTTP::Client }
|
|
292
|
-
it { is_expected.to be_persistent }
|
|
293
|
-
end
|
|
294
|
-
|
|
295
|
-
context "with host and block given" do
|
|
296
|
-
it "returns last evaluation of last expression" do
|
|
297
|
-
expect(HTTP.persistent(host) { :http }).to be :http
|
|
298
|
-
end
|
|
299
|
-
|
|
300
|
-
it "auto-closes connection" do
|
|
301
|
-
HTTP.persistent host do |client|
|
|
302
|
-
expect(client).to receive(:close).and_call_original
|
|
303
|
-
client.get("/repos/httprb/http.rb")
|
|
304
|
-
end
|
|
305
|
-
end
|
|
306
|
-
end
|
|
307
|
-
|
|
308
|
-
context "with timeout specified" do
|
|
309
|
-
subject(:client) { HTTP.persistent host, :timeout => 100 }
|
|
310
|
-
it "sets keep_alive_timeout" do
|
|
311
|
-
options = client.default_options
|
|
312
|
-
expect(options.keep_alive_timeout).to eq(100)
|
|
313
|
-
end
|
|
314
|
-
end
|
|
315
|
-
end
|
|
316
|
-
|
|
317
|
-
describe ".timeout" do
|
|
318
|
-
context "specifying a null timeout" do
|
|
319
|
-
subject(:client) { HTTP.timeout :null }
|
|
320
|
-
|
|
321
|
-
it "sets timeout_class to Null" do
|
|
322
|
-
expect(client.default_options.timeout_class).
|
|
323
|
-
to be HTTP::Timeout::Null
|
|
324
|
-
end
|
|
325
|
-
end
|
|
326
|
-
|
|
327
|
-
context "specifying per operation timeouts" do
|
|
328
|
-
subject(:client) { HTTP.timeout :read => 123 }
|
|
329
|
-
|
|
330
|
-
it "sets timeout_class to PerOperation" do
|
|
331
|
-
expect(client.default_options.timeout_class).
|
|
332
|
-
to be HTTP::Timeout::PerOperation
|
|
333
|
-
end
|
|
334
|
-
|
|
335
|
-
it "sets given timeout options" do
|
|
336
|
-
expect(client.default_options.timeout_options).
|
|
337
|
-
to eq :read_timeout => 123
|
|
338
|
-
end
|
|
339
|
-
end
|
|
340
|
-
|
|
341
|
-
context "specifying per operation timeouts as frozen hash" do
|
|
342
|
-
let(:frozen_options) { {:read => 123}.freeze }
|
|
343
|
-
subject(:client) { HTTP.timeout(frozen_options) }
|
|
344
|
-
|
|
345
|
-
it "does not raise an error" do
|
|
346
|
-
expect { client }.not_to raise_error
|
|
347
|
-
end
|
|
348
|
-
end
|
|
349
|
-
|
|
350
|
-
context "specifying a global timeout" do
|
|
351
|
-
subject(:client) { HTTP.timeout 123 }
|
|
352
|
-
|
|
353
|
-
it "sets timeout_class to Global" do
|
|
354
|
-
expect(client.default_options.timeout_class).
|
|
355
|
-
to be HTTP::Timeout::Global
|
|
356
|
-
end
|
|
357
|
-
|
|
358
|
-
it "sets given timeout option" do
|
|
359
|
-
expect(client.default_options.timeout_options).
|
|
360
|
-
to eq :global_timeout => 123
|
|
361
|
-
end
|
|
362
|
-
end
|
|
363
|
-
end
|
|
364
|
-
|
|
365
|
-
describe ".cookies" do
|
|
366
|
-
let(:endpoint) { "#{dummy.endpoint}/cookies" }
|
|
367
|
-
|
|
368
|
-
it "passes correct `Cookie` header" do
|
|
369
|
-
expect(HTTP.cookies(:abc => :def).get(endpoint).to_s).
|
|
370
|
-
to eq "abc: def"
|
|
371
|
-
end
|
|
372
|
-
|
|
373
|
-
it "properly works with cookie jars from response" do
|
|
374
|
-
res = HTTP.get(endpoint).flush
|
|
375
|
-
|
|
376
|
-
expect(HTTP.cookies(res.cookies).get(endpoint).to_s).
|
|
377
|
-
to eq "foo: bar"
|
|
378
|
-
end
|
|
379
|
-
|
|
380
|
-
it "properly merges cookies" do
|
|
381
|
-
res = HTTP.get(endpoint).flush
|
|
382
|
-
client = HTTP.cookies(:foo => 123, :bar => 321).cookies(res.cookies)
|
|
383
|
-
|
|
384
|
-
expect(client.get(endpoint).to_s).to eq "foo: bar\nbar: 321"
|
|
385
|
-
end
|
|
386
|
-
|
|
387
|
-
it "properly merges Cookie headers and cookies" do
|
|
388
|
-
client = HTTP.headers("Cookie" => "foo=bar").cookies(:baz => :moo)
|
|
389
|
-
expect(client.get(endpoint).to_s).to eq "foo: bar\nbaz: moo"
|
|
390
|
-
end
|
|
391
|
-
end
|
|
392
|
-
|
|
393
|
-
describe ".nodelay" do
|
|
394
|
-
before do
|
|
395
|
-
HTTP.default_options = {:socket_class => socket_spy_class}
|
|
396
|
-
end
|
|
397
|
-
|
|
398
|
-
after do
|
|
399
|
-
HTTP.default_options = {}
|
|
400
|
-
end
|
|
401
|
-
|
|
402
|
-
let(:socket_spy_class) do
|
|
403
|
-
Class.new(TCPSocket) do
|
|
404
|
-
def self.setsockopt_calls
|
|
405
|
-
@setsockopt_calls ||= []
|
|
406
|
-
end
|
|
407
|
-
|
|
408
|
-
def setsockopt(*args)
|
|
409
|
-
self.class.setsockopt_calls << args
|
|
410
|
-
super
|
|
411
|
-
end
|
|
412
|
-
end
|
|
413
|
-
end
|
|
414
|
-
|
|
415
|
-
it "sets TCP_NODELAY on the underlying socket" do
|
|
416
|
-
HTTP.get(dummy.endpoint)
|
|
417
|
-
expect(socket_spy_class.setsockopt_calls).to eq([])
|
|
418
|
-
HTTP.nodelay.get(dummy.endpoint)
|
|
419
|
-
expect(socket_spy_class.setsockopt_calls).to eq([[Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1]])
|
|
420
|
-
end
|
|
421
|
-
end
|
|
422
|
-
|
|
423
|
-
describe ".use" do
|
|
424
|
-
it "turns on given feature" do
|
|
425
|
-
client = HTTP.use :auto_deflate
|
|
426
|
-
expect(client.default_options.features.keys).to eq [:auto_deflate]
|
|
427
|
-
end
|
|
428
|
-
|
|
429
|
-
context "with :auto_deflate" do
|
|
430
|
-
it "sends gzipped body" do
|
|
431
|
-
client = HTTP.use :auto_deflate
|
|
432
|
-
body = "Hello!"
|
|
433
|
-
response = client.post("#{dummy.endpoint}/echo-body", :body => body)
|
|
434
|
-
encoded = response.to_s
|
|
435
|
-
|
|
436
|
-
expect(Zlib::GzipReader.new(StringIO.new(encoded)).read).to eq body
|
|
437
|
-
end
|
|
438
|
-
|
|
439
|
-
it "sends deflated body" do
|
|
440
|
-
client = HTTP.use :auto_deflate => {:method => "deflate"}
|
|
441
|
-
body = "Hello!"
|
|
442
|
-
response = client.post("#{dummy.endpoint}/echo-body", :body => body)
|
|
443
|
-
encoded = response.to_s
|
|
444
|
-
|
|
445
|
-
expect(Zlib::Inflate.inflate(encoded)).to eq body
|
|
446
|
-
end
|
|
447
|
-
end
|
|
448
|
-
|
|
449
|
-
context "with :auto_inflate" do
|
|
450
|
-
it "returns raw body when Content-Encoding type is missing" do
|
|
451
|
-
client = HTTP.use :auto_inflate
|
|
452
|
-
body = "Hello!"
|
|
453
|
-
response = client.post("#{dummy.endpoint}/encoded-body", :body => body)
|
|
454
|
-
expect(response.to_s).to eq("#{body}-raw")
|
|
455
|
-
end
|
|
456
|
-
|
|
457
|
-
it "returns decoded body" do
|
|
458
|
-
client = HTTP.use(:auto_inflate).headers("Accept-Encoding" => "gzip")
|
|
459
|
-
body = "Hello!"
|
|
460
|
-
response = client.post("#{dummy.endpoint}/encoded-body", :body => body)
|
|
461
|
-
|
|
462
|
-
expect(response.to_s).to eq("#{body}-gzipped")
|
|
463
|
-
end
|
|
464
|
-
|
|
465
|
-
it "returns deflated body" do
|
|
466
|
-
client = HTTP.use(:auto_inflate).headers("Accept-Encoding" => "deflate")
|
|
467
|
-
body = "Hello!"
|
|
468
|
-
response = client.post("#{dummy.endpoint}/encoded-body", :body => body)
|
|
469
|
-
|
|
470
|
-
expect(response.to_s).to eq("#{body}-deflated")
|
|
471
|
-
end
|
|
472
|
-
|
|
473
|
-
it "returns empty body for no content response where Content-Encoding is gzip" do
|
|
474
|
-
client = HTTP.use(:auto_inflate).headers("Accept-Encoding" => "gzip")
|
|
475
|
-
body = "Hello!"
|
|
476
|
-
response = client.post("#{dummy.endpoint}/no-content-204", :body => body)
|
|
477
|
-
|
|
478
|
-
expect(response.to_s).to eq("")
|
|
479
|
-
end
|
|
480
|
-
|
|
481
|
-
it "returns empty body for no content response where Content-Encoding is deflate" do
|
|
482
|
-
client = HTTP.use(:auto_inflate).headers("Accept-Encoding" => "deflate")
|
|
483
|
-
body = "Hello!"
|
|
484
|
-
response = client.post("#{dummy.endpoint}/no-content-204", :body => body)
|
|
485
|
-
|
|
486
|
-
expect(response.to_s).to eq("")
|
|
487
|
-
end
|
|
488
|
-
end
|
|
489
|
-
|
|
490
|
-
context "with :normalize_uri" do
|
|
491
|
-
it "normalizes URI" do
|
|
492
|
-
response = HTTP.get "#{dummy.endpoint}/héllö-wörld"
|
|
493
|
-
expect(response.to_s).to eq("hello world")
|
|
494
|
-
end
|
|
495
|
-
|
|
496
|
-
it "uses the custom URI Normalizer method" do
|
|
497
|
-
client = HTTP.use(:normalize_uri => {:normalizer => :itself.to_proc})
|
|
498
|
-
response = client.get("#{dummy.endpoint}/héllö-wörld")
|
|
499
|
-
expect(response.status).to eq(400)
|
|
500
|
-
end
|
|
501
|
-
|
|
502
|
-
it "raises if custom URI Normalizer returns invalid path" do
|
|
503
|
-
client = HTTP.use(:normalize_uri => {:normalizer => :itself.to_proc})
|
|
504
|
-
expect { client.get("#{dummy.endpoint}/hello\nworld") }.
|
|
505
|
-
to raise_error HTTP::RequestError, 'Invalid request URI: "/hello\nworld"'
|
|
506
|
-
end
|
|
507
|
-
|
|
508
|
-
it "raises if custom URI Normalizer returns invalid host" do
|
|
509
|
-
normalizer = lambda do |uri|
|
|
510
|
-
uri.port = nil
|
|
511
|
-
uri.instance_variable_set(:@host, "example\ncom")
|
|
512
|
-
uri
|
|
513
|
-
end
|
|
514
|
-
client = HTTP.use(:normalize_uri => {:normalizer => normalizer})
|
|
515
|
-
expect { client.get(dummy.endpoint) }.
|
|
516
|
-
to raise_error HTTP::RequestError, 'Invalid host: "example\ncom"'
|
|
517
|
-
end
|
|
518
|
-
|
|
519
|
-
it "uses the default URI normalizer" do
|
|
520
|
-
client = HTTP.use :normalize_uri
|
|
521
|
-
expect(HTTP::URI::NORMALIZER).to receive(:call).and_call_original
|
|
522
|
-
response = client.get("#{dummy.endpoint}/héllö-wörld")
|
|
523
|
-
expect(response.to_s).to eq("hello world")
|
|
524
|
-
end
|
|
525
|
-
end
|
|
526
|
-
end
|
|
527
|
-
|
|
528
|
-
it "unifies socket errors into HTTP::ConnectionError" do
|
|
529
|
-
expect { HTTP.get "http://thishostshouldnotexists.com" }.
|
|
530
|
-
to raise_error HTTP::ConnectionError
|
|
531
|
-
|
|
532
|
-
expect { HTTP.get "http://127.0.0.1:111" }.
|
|
533
|
-
to raise_error HTTP::ConnectionError
|
|
534
|
-
end
|
|
535
|
-
end
|
data/spec/regression_specs.rb
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "spec_helper"
|
|
4
|
-
|
|
5
|
-
RSpec.describe "Regression testing" do
|
|
6
|
-
describe "#248" do
|
|
7
|
-
it "does not fail with github" do
|
|
8
|
-
github_uri = "http://github.com/"
|
|
9
|
-
expect { HTTP.get(github_uri).to_s }.not_to raise_error
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
it "does not fail with googleapis" do
|
|
13
|
-
google_uri = "https://www.googleapis.com/oauth2/v1/userinfo?alt=json"
|
|
14
|
-
expect { HTTP.get(google_uri).to_s }.not_to raise_error
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
describe "#422" do
|
|
19
|
-
it "reads body when 200 OK response contains Upgrade header" do
|
|
20
|
-
res = HTTP.get("https://httpbin.org/response-headers?Upgrade=h2,h2c")
|
|
21
|
-
expect(res.parse(:json)).to include("Upgrade" => "h2,h2c")
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
end
|
data/spec/spec_helper.rb
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require_relative "./support/simplecov"
|
|
4
|
-
require_relative "./support/fuubar" unless ENV["CI"]
|
|
5
|
-
|
|
6
|
-
require "http"
|
|
7
|
-
require "rspec/its"
|
|
8
|
-
require "rspec/memory"
|
|
9
|
-
require "support/capture_warning"
|
|
10
|
-
require "support/fakeio"
|
|
11
|
-
|
|
12
|
-
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
|
13
|
-
RSpec.configure do |config|
|
|
14
|
-
config.expect_with :rspec do |expectations|
|
|
15
|
-
# This option will default to `true` in RSpec 4. It makes the `description`
|
|
16
|
-
# and `failure_message` of custom matchers include text for helper methods
|
|
17
|
-
# defined using `chain`, e.g.:
|
|
18
|
-
# be_bigger_than(2).and_smaller_than(4).description
|
|
19
|
-
# # => "be bigger than 2 and smaller than 4"
|
|
20
|
-
# ...rather than:
|
|
21
|
-
# # => "be bigger than 2"
|
|
22
|
-
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
config.mock_with :rspec do |mocks|
|
|
26
|
-
# Prevents you from mocking or stubbing a method that does not exist on
|
|
27
|
-
# a real object. This is generally recommended, and will default to
|
|
28
|
-
# `true` in RSpec 4.
|
|
29
|
-
mocks.verify_partial_doubles = true
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
|
33
|
-
# have no way to turn it off -- the option exists only for backwards
|
|
34
|
-
# compatibility in RSpec 3). It causes shared context metadata to be
|
|
35
|
-
# inherited by the metadata hash of host groups and examples, rather than
|
|
36
|
-
# triggering implicit auto-inclusion in groups with matching metadata.
|
|
37
|
-
config.shared_context_metadata_behavior = :apply_to_host_groups
|
|
38
|
-
|
|
39
|
-
# These two settings work together to allow you to limit a spec run
|
|
40
|
-
# to individual examples or groups you care about by tagging them with
|
|
41
|
-
# `:focus` metadata. When nothing is tagged with `:focus`, all examples
|
|
42
|
-
# get run.
|
|
43
|
-
config.filter_run :focus
|
|
44
|
-
config.filter_run_excluding :flaky if defined?(JRUBY_VERSION) && ENV["CI"]
|
|
45
|
-
config.run_all_when_everything_filtered = true
|
|
46
|
-
|
|
47
|
-
# This setting enables warnings. It's recommended, but in some cases may
|
|
48
|
-
# be too noisy due to issues in dependencies.
|
|
49
|
-
config.warnings = 0 == ENV["GUARD_RSPEC"].to_i
|
|
50
|
-
|
|
51
|
-
# Allows RSpec to persist some state between runs in order to support
|
|
52
|
-
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
|
53
|
-
# you configure your source control system to ignore this file.
|
|
54
|
-
config.example_status_persistence_file_path = "spec/examples.txt"
|
|
55
|
-
|
|
56
|
-
# Limits the available syntax to the non-monkey patched syntax that is
|
|
57
|
-
# recommended. For more details, see:
|
|
58
|
-
# - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
|
|
59
|
-
# - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
|
|
60
|
-
# - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
|
|
61
|
-
config.disable_monkey_patching!
|
|
62
|
-
|
|
63
|
-
# Many RSpec users commonly either run the entire suite or an individual
|
|
64
|
-
# file, and it's useful to allow more verbose output when running an
|
|
65
|
-
# individual spec file.
|
|
66
|
-
if config.files_to_run.one?
|
|
67
|
-
# Use the documentation formatter for detailed output,
|
|
68
|
-
# unless a formatter has already been configured
|
|
69
|
-
# (e.g. via a command-line flag).
|
|
70
|
-
config.default_formatter = "doc"
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# Print the 10 slowest examples and example groups at the
|
|
74
|
-
# end of the spec run, to help surface which specs are running
|
|
75
|
-
# particularly slow.
|
|
76
|
-
config.profile_examples = 10
|
|
77
|
-
|
|
78
|
-
# Run specs in random order to surface order dependencies. If you find an
|
|
79
|
-
# order dependency and want to debug it, you can fix the order by providing
|
|
80
|
-
# the seed, which is printed after each run.
|
|
81
|
-
# --seed 1234
|
|
82
|
-
config.order = :random
|
|
83
|
-
|
|
84
|
-
# Seed global randomization in this process using the `--seed` CLI option.
|
|
85
|
-
# Setting this allows you to use `--seed` to deterministically reproduce
|
|
86
|
-
# test failures related to randomization by passing the same `--seed` value
|
|
87
|
-
# as the one that triggered the failure.
|
|
88
|
-
Kernel.srand config.seed
|
|
89
|
-
end
|