http 5.2.0 → 6.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (128) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +110 -13
  4. data/http.gemspec +38 -35
  5. data/lib/http/base64.rb +22 -0
  6. data/lib/http/chainable/helpers.rb +62 -0
  7. data/lib/http/chainable/verbs.rb +136 -0
  8. data/lib/http/chainable.rb +249 -129
  9. data/lib/http/client.rb +158 -127
  10. data/lib/http/connection/internals.rb +141 -0
  11. data/lib/http/connection.rb +128 -97
  12. data/lib/http/content_type.rb +61 -6
  13. data/lib/http/errors.rb +41 -1
  14. data/lib/http/feature.rb +67 -6
  15. data/lib/http/features/auto_deflate.rb +124 -17
  16. data/lib/http/features/auto_inflate.rb +38 -15
  17. data/lib/http/features/caching/entry.rb +178 -0
  18. data/lib/http/features/caching/in_memory_store.rb +63 -0
  19. data/lib/http/features/caching.rb +216 -0
  20. data/lib/http/features/digest_auth.rb +234 -0
  21. data/lib/http/features/instrumentation.rb +97 -17
  22. data/lib/http/features/logging.rb +183 -5
  23. data/lib/http/features/normalize_uri.rb +17 -0
  24. data/lib/http/features/raise_error.rb +37 -0
  25. data/lib/http/form_data/composite_io.rb +106 -0
  26. data/lib/http/form_data/file.rb +95 -0
  27. data/lib/http/form_data/multipart/param.rb +62 -0
  28. data/lib/http/form_data/multipart.rb +106 -0
  29. data/lib/http/form_data/part.rb +52 -0
  30. data/lib/http/form_data/readable.rb +58 -0
  31. data/lib/http/form_data/urlencoded.rb +175 -0
  32. data/lib/http/form_data/version.rb +8 -0
  33. data/lib/http/form_data.rb +102 -0
  34. data/lib/http/headers/known.rb +3 -0
  35. data/lib/http/headers/normalizer.rb +50 -0
  36. data/lib/http/headers.rb +185 -92
  37. data/lib/http/mime_type/adapter.rb +24 -9
  38. data/lib/http/mime_type/json.rb +19 -4
  39. data/lib/http/mime_type.rb +21 -3
  40. data/lib/http/options/definitions.rb +189 -0
  41. data/lib/http/options.rb +172 -125
  42. data/lib/http/redirector.rb +80 -75
  43. data/lib/http/request/body.rb +87 -6
  44. data/lib/http/request/builder.rb +184 -0
  45. data/lib/http/request/proxy.rb +83 -0
  46. data/lib/http/request/writer.rb +78 -17
  47. data/lib/http/request.rb +216 -99
  48. data/lib/http/response/body.rb +103 -18
  49. data/lib/http/response/inflater.rb +35 -7
  50. data/lib/http/response/parser.rb +98 -4
  51. data/lib/http/response/status/reasons.rb +2 -4
  52. data/lib/http/response/status.rb +141 -31
  53. data/lib/http/response.rb +219 -61
  54. data/lib/http/retriable/delay_calculator.rb +91 -0
  55. data/lib/http/retriable/errors.rb +35 -0
  56. data/lib/http/retriable/performer.rb +197 -0
  57. data/lib/http/session.rb +280 -0
  58. data/lib/http/timeout/global.rb +147 -34
  59. data/lib/http/timeout/null.rb +155 -9
  60. data/lib/http/timeout/per_operation.rb +139 -18
  61. data/lib/http/uri/normalizer.rb +82 -0
  62. data/lib/http/uri/parsing.rb +182 -0
  63. data/lib/http/uri.rb +289 -124
  64. data/lib/http/version.rb +2 -1
  65. data/lib/http.rb +11 -1
  66. data/sig/http.rbs +1619 -0
  67. metadata +42 -175
  68. data/.github/workflows/ci.yml +0 -67
  69. data/.gitignore +0 -15
  70. data/.rspec +0 -1
  71. data/.rubocop/layout.yml +0 -8
  72. data/.rubocop/metrics.yml +0 -4
  73. data/.rubocop/style.yml +0 -32
  74. data/.rubocop.yml +0 -11
  75. data/.rubocop_todo.yml +0 -206
  76. data/.yardopts +0 -2
  77. data/CHANGELOG.md +0 -41
  78. data/CHANGES_OLD.md +0 -1002
  79. data/CONTRIBUTING.md +0 -26
  80. data/Gemfile +0 -50
  81. data/Guardfile +0 -18
  82. data/Rakefile +0 -64
  83. data/SECURITY.md +0 -17
  84. data/lib/http/headers/mixin.rb +0 -34
  85. data/logo.png +0 -0
  86. data/spec/lib/http/client_spec.rb +0 -556
  87. data/spec/lib/http/connection_spec.rb +0 -88
  88. data/spec/lib/http/content_type_spec.rb +0 -47
  89. data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
  90. data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
  91. data/spec/lib/http/features/instrumentation_spec.rb +0 -81
  92. data/spec/lib/http/features/logging_spec.rb +0 -65
  93. data/spec/lib/http/headers/mixin_spec.rb +0 -36
  94. data/spec/lib/http/headers_spec.rb +0 -527
  95. data/spec/lib/http/options/body_spec.rb +0 -15
  96. data/spec/lib/http/options/features_spec.rb +0 -33
  97. data/spec/lib/http/options/form_spec.rb +0 -15
  98. data/spec/lib/http/options/headers_spec.rb +0 -24
  99. data/spec/lib/http/options/json_spec.rb +0 -15
  100. data/spec/lib/http/options/merge_spec.rb +0 -68
  101. data/spec/lib/http/options/new_spec.rb +0 -30
  102. data/spec/lib/http/options/proxy_spec.rb +0 -20
  103. data/spec/lib/http/options_spec.rb +0 -13
  104. data/spec/lib/http/redirector_spec.rb +0 -529
  105. data/spec/lib/http/request/body_spec.rb +0 -211
  106. data/spec/lib/http/request/writer_spec.rb +0 -121
  107. data/spec/lib/http/request_spec.rb +0 -234
  108. data/spec/lib/http/response/body_spec.rb +0 -85
  109. data/spec/lib/http/response/parser_spec.rb +0 -74
  110. data/spec/lib/http/response/status_spec.rb +0 -253
  111. data/spec/lib/http/response_spec.rb +0 -262
  112. data/spec/lib/http/uri/normalizer_spec.rb +0 -95
  113. data/spec/lib/http/uri_spec.rb +0 -71
  114. data/spec/lib/http_spec.rb +0 -506
  115. data/spec/regression_specs.rb +0 -24
  116. data/spec/spec_helper.rb +0 -88
  117. data/spec/support/black_hole.rb +0 -13
  118. data/spec/support/capture_warning.rb +0 -10
  119. data/spec/support/dummy_server/servlet.rb +0 -190
  120. data/spec/support/dummy_server.rb +0 -43
  121. data/spec/support/fakeio.rb +0 -21
  122. data/spec/support/fuubar.rb +0 -21
  123. data/spec/support/http_handling_shared.rb +0 -190
  124. data/spec/support/proxy_server.rb +0 -39
  125. data/spec/support/servers/config.rb +0 -11
  126. data/spec/support/servers/runner.rb +0 -19
  127. data/spec/support/simplecov.rb +0 -19
  128. data/spec/support/ssl_helper.rb +0 -104
@@ -1,71 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe HTTP::URI do
4
- let(:example_ipv6_address) { "2606:2800:220:1:248:1893:25c8:1946" }
5
-
6
- let(:example_http_uri_string) { "http://example.com" }
7
- let(:example_https_uri_string) { "https://example.com" }
8
- let(:example_ipv6_uri_string) { "https://[#{example_ipv6_address}]" }
9
-
10
- subject(:http_uri) { described_class.parse(example_http_uri_string) }
11
- subject(:https_uri) { described_class.parse(example_https_uri_string) }
12
- subject(:ipv6_uri) { described_class.parse(example_ipv6_uri_string) }
13
-
14
- it "knows URI schemes" do
15
- expect(http_uri.scheme).to eq "http"
16
- expect(https_uri.scheme).to eq "https"
17
- end
18
-
19
- it "sets default ports for HTTP URIs" do
20
- expect(http_uri.port).to eq 80
21
- end
22
-
23
- it "sets default ports for HTTPS URIs" do
24
- expect(https_uri.port).to eq 443
25
- end
26
-
27
- describe "#host" do
28
- it "strips brackets from IPv6 addresses" do
29
- expect(ipv6_uri.host).to eq("2606:2800:220:1:248:1893:25c8:1946")
30
- end
31
- end
32
-
33
- describe "#normalized_host" do
34
- it "strips brackets from IPv6 addresses" do
35
- expect(ipv6_uri.normalized_host).to eq("2606:2800:220:1:248:1893:25c8:1946")
36
- end
37
- end
38
-
39
- describe "#host=" do
40
- it "updates cached values for #host and #normalized_host" do
41
- expect(http_uri.host).to eq("example.com")
42
- expect(http_uri.normalized_host).to eq("example.com")
43
-
44
- http_uri.host = "[#{example_ipv6_address}]"
45
-
46
- expect(http_uri.host).to eq(example_ipv6_address)
47
- expect(http_uri.normalized_host).to eq(example_ipv6_address)
48
- end
49
-
50
- it "ensures IPv6 addresses are bracketed in the inner Addressable::URI" do
51
- expect(http_uri.host).to eq("example.com")
52
- expect(http_uri.normalized_host).to eq("example.com")
53
-
54
- http_uri.host = example_ipv6_address
55
-
56
- expect(http_uri.host).to eq(example_ipv6_address)
57
- expect(http_uri.normalized_host).to eq(example_ipv6_address)
58
- expect(http_uri.instance_variable_get(:@uri).host).to eq("[#{example_ipv6_address}]")
59
- end
60
- end
61
-
62
- describe "#dup" do
63
- it "doesn't share internal value between duplicates" do
64
- duplicated_uri = http_uri.dup
65
- duplicated_uri.host = "example.org"
66
-
67
- expect(duplicated_uri.to_s).to eq("http://example.org")
68
- expect(http_uri.to_s).to eq("http://example.com")
69
- end
70
- end
71
- end
@@ -1,506 +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
- context "posting forms to resources" do
156
- it "is easy" do
157
- response = HTTP.post "#{dummy.endpoint}/form", :form => {:example => "testing-form"}
158
- expect(response.to_s).to eq("passed :)")
159
- end
160
- end
161
-
162
- context "loading binary data" do
163
- it "is encoded as bytes" do
164
- response = HTTP.get "#{dummy.endpoint}/bytes"
165
- expect(response.to_s.encoding).to eq(Encoding::BINARY)
166
- end
167
- end
168
-
169
- context "loading endpoint with charset" do
170
- it "uses charset from headers" do
171
- response = HTTP.get "#{dummy.endpoint}/iso-8859-1"
172
- expect(response.to_s.encoding).to eq(Encoding::ISO8859_1)
173
- expect(response.to_s.encode(Encoding::UTF_8)).to eq("testæ")
174
- end
175
-
176
- context "with encoding option" do
177
- it "respects option" do
178
- response = HTTP.get "#{dummy.endpoint}/iso-8859-1", :encoding => Encoding::BINARY
179
- expect(response.to_s.encoding).to eq(Encoding::BINARY)
180
- end
181
- end
182
- end
183
-
184
- context "passing a string encoding type" do
185
- it "finds encoding" do
186
- response = HTTP.get dummy.endpoint, :encoding => "ascii"
187
- expect(response.to_s.encoding).to eq(Encoding::ASCII)
188
- end
189
- end
190
-
191
- context "loading text with no charset" do
192
- it "is binary encoded" do
193
- response = HTTP.get dummy.endpoint
194
- expect(response.to_s.encoding).to eq(Encoding::BINARY)
195
- end
196
- end
197
-
198
- context "posting with an explicit body" do
199
- it "is easy" do
200
- response = HTTP.post "#{dummy.endpoint}/body", :body => "testing-body"
201
- expect(response.to_s).to eq("passed :)")
202
- end
203
- end
204
-
205
- context "with redirects" do
206
- it "is easy for 301" do
207
- response = HTTP.follow.get("#{dummy.endpoint}/redirect-301")
208
- expect(response.to_s).to match(/<!doctype html>/)
209
- end
210
-
211
- it "is easy for 302" do
212
- response = HTTP.follow.get("#{dummy.endpoint}/redirect-302")
213
- expect(response.to_s).to match(/<!doctype html>/)
214
- end
215
- end
216
-
217
- context "head requests" do
218
- it "is easy" do
219
- response = HTTP.head dummy.endpoint
220
- expect(response.status).to eq(200)
221
- expect(response["content-type"]).to match(/html/)
222
- end
223
- end
224
-
225
- describe ".auth" do
226
- it "sets Authorization header to the given value" do
227
- client = HTTP.auth "abc"
228
- expect(client.default_options.headers[:authorization]).to eq "abc"
229
- end
230
-
231
- it "accepts any #to_s object" do
232
- client = HTTP.auth double :to_s => "abc"
233
- expect(client.default_options.headers[:authorization]).to eq "abc"
234
- end
235
- end
236
-
237
- describe ".basic_auth" do
238
- it "fails when options is not a Hash" do
239
- expect { HTTP.basic_auth "[FOOBAR]" }.to raise_error(NoMethodError)
240
- end
241
-
242
- it "fails when :pass is not given" do
243
- expect { HTTP.basic_auth :user => "[USER]" }.to raise_error(KeyError)
244
- end
245
-
246
- it "fails when :user is not given" do
247
- expect { HTTP.basic_auth :pass => "[PASS]" }.to raise_error(KeyError)
248
- end
249
-
250
- it "sets Authorization header with proper BasicAuth value" do
251
- client = HTTP.basic_auth :user => "foo", :pass => "bar"
252
- expect(client.default_options.headers[:authorization]).
253
- to match(%r{^Basic [A-Za-z0-9+/]+=*$})
254
- end
255
- end
256
-
257
- describe ".persistent" do
258
- let(:host) { "https://api.github.com" }
259
-
260
- context "with host only given" do
261
- subject { HTTP.persistent host }
262
- it { is_expected.to be_an HTTP::Client }
263
- it { is_expected.to be_persistent }
264
- end
265
-
266
- context "with host and block given" do
267
- it "returns last evaluation of last expression" do
268
- expect(HTTP.persistent(host) { :http }).to be :http
269
- end
270
-
271
- it "auto-closes connection" do
272
- HTTP.persistent host do |client|
273
- expect(client).to receive(:close).and_call_original
274
- client.get("/repos/httprb/http.rb")
275
- end
276
- end
277
- end
278
-
279
- context "with timeout specified" do
280
- subject(:client) { HTTP.persistent host, :timeout => 100 }
281
- it "sets keep_alive_timeout" do
282
- options = client.default_options
283
- expect(options.keep_alive_timeout).to eq(100)
284
- end
285
- end
286
- end
287
-
288
- describe ".timeout" do
289
- context "specifying a null timeout" do
290
- subject(:client) { HTTP.timeout :null }
291
-
292
- it "sets timeout_class to Null" do
293
- expect(client.default_options.timeout_class).
294
- to be HTTP::Timeout::Null
295
- end
296
- end
297
-
298
- context "specifying per operation timeouts" do
299
- subject(:client) { HTTP.timeout :read => 123 }
300
-
301
- it "sets timeout_class to PerOperation" do
302
- expect(client.default_options.timeout_class).
303
- to be HTTP::Timeout::PerOperation
304
- end
305
-
306
- it "sets given timeout options" do
307
- expect(client.default_options.timeout_options).
308
- to eq :read_timeout => 123
309
- end
310
- end
311
-
312
- context "specifying per operation timeouts as frozen hash" do
313
- let(:frozen_options) { {:read => 123}.freeze }
314
- subject(:client) { HTTP.timeout(frozen_options) }
315
-
316
- it "does not raise an error" do
317
- expect { client }.not_to raise_error
318
- end
319
- end
320
-
321
- context "specifying a global timeout" do
322
- subject(:client) { HTTP.timeout 123 }
323
-
324
- it "sets timeout_class to Global" do
325
- expect(client.default_options.timeout_class).
326
- to be HTTP::Timeout::Global
327
- end
328
-
329
- it "sets given timeout option" do
330
- expect(client.default_options.timeout_options).
331
- to eq :global_timeout => 123
332
- end
333
- end
334
- end
335
-
336
- describe ".cookies" do
337
- let(:endpoint) { "#{dummy.endpoint}/cookies" }
338
-
339
- it "passes correct `Cookie` header" do
340
- expect(HTTP.cookies(:abc => :def).get(endpoint).to_s).
341
- to eq "abc: def"
342
- end
343
-
344
- it "properly works with cookie jars from response" do
345
- res = HTTP.get(endpoint).flush
346
-
347
- expect(HTTP.cookies(res.cookies).get(endpoint).to_s).
348
- to eq "foo: bar"
349
- end
350
-
351
- it "properly merges cookies" do
352
- res = HTTP.get(endpoint).flush
353
- client = HTTP.cookies(:foo => 123, :bar => 321).cookies(res.cookies)
354
-
355
- expect(client.get(endpoint).to_s).to eq "foo: bar\nbar: 321"
356
- end
357
-
358
- it "properly merges Cookie headers and cookies" do
359
- client = HTTP.headers("Cookie" => "foo=bar").cookies(:baz => :moo)
360
- expect(client.get(endpoint).to_s).to eq "foo: bar\nbaz: moo"
361
- end
362
- end
363
-
364
- describe ".nodelay" do
365
- before do
366
- HTTP.default_options = {:socket_class => socket_spy_class}
367
- end
368
-
369
- after do
370
- HTTP.default_options = {}
371
- end
372
-
373
- let(:socket_spy_class) do
374
- Class.new(TCPSocket) do
375
- def self.setsockopt_calls
376
- @setsockopt_calls ||= []
377
- end
378
-
379
- def setsockopt(*args)
380
- self.class.setsockopt_calls << args
381
- super
382
- end
383
- end
384
- end
385
-
386
- it "sets TCP_NODELAY on the underlying socket" do
387
- HTTP.get(dummy.endpoint)
388
- expect(socket_spy_class.setsockopt_calls).to eq([])
389
- HTTP.nodelay.get(dummy.endpoint)
390
- expect(socket_spy_class.setsockopt_calls).to eq([[Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1]])
391
- end
392
- end
393
-
394
- describe ".use" do
395
- it "turns on given feature" do
396
- client = HTTP.use :auto_deflate
397
- expect(client.default_options.features.keys).to eq [:auto_deflate]
398
- end
399
-
400
- context "with :auto_deflate" do
401
- it "sends gzipped body" do
402
- client = HTTP.use :auto_deflate
403
- body = "Hello!"
404
- response = client.post("#{dummy.endpoint}/echo-body", :body => body)
405
- encoded = response.to_s
406
-
407
- expect(Zlib::GzipReader.new(StringIO.new(encoded)).read).to eq body
408
- end
409
-
410
- it "sends deflated body" do
411
- client = HTTP.use :auto_deflate => {:method => "deflate"}
412
- body = "Hello!"
413
- response = client.post("#{dummy.endpoint}/echo-body", :body => body)
414
- encoded = response.to_s
415
-
416
- expect(Zlib::Inflate.inflate(encoded)).to eq body
417
- end
418
- end
419
-
420
- context "with :auto_inflate" do
421
- it "returns raw body when Content-Encoding type is missing" do
422
- client = HTTP.use :auto_inflate
423
- body = "Hello!"
424
- response = client.post("#{dummy.endpoint}/encoded-body", :body => body)
425
- expect(response.to_s).to eq("#{body}-raw")
426
- end
427
-
428
- it "returns decoded body" do
429
- client = HTTP.use(:auto_inflate).headers("Accept-Encoding" => "gzip")
430
- body = "Hello!"
431
- response = client.post("#{dummy.endpoint}/encoded-body", :body => body)
432
-
433
- expect(response.to_s).to eq("#{body}-gzipped")
434
- end
435
-
436
- it "returns deflated body" do
437
- client = HTTP.use(:auto_inflate).headers("Accept-Encoding" => "deflate")
438
- body = "Hello!"
439
- response = client.post("#{dummy.endpoint}/encoded-body", :body => body)
440
-
441
- expect(response.to_s).to eq("#{body}-deflated")
442
- end
443
-
444
- it "returns empty body for no content response where Content-Encoding is gzip" do
445
- client = HTTP.use(:auto_inflate).headers("Accept-Encoding" => "gzip")
446
- body = "Hello!"
447
- response = client.post("#{dummy.endpoint}/no-content-204", :body => body)
448
-
449
- expect(response.to_s).to eq("")
450
- end
451
-
452
- it "returns empty body for no content response where Content-Encoding is deflate" do
453
- client = HTTP.use(:auto_inflate).headers("Accept-Encoding" => "deflate")
454
- body = "Hello!"
455
- response = client.post("#{dummy.endpoint}/no-content-204", :body => body)
456
-
457
- expect(response.to_s).to eq("")
458
- end
459
- end
460
-
461
- context "with :normalize_uri" do
462
- it "normalizes URI" do
463
- response = HTTP.get "#{dummy.endpoint}/héllö-wörld"
464
- expect(response.to_s).to eq("hello world")
465
- end
466
-
467
- it "uses the custom URI Normalizer method" do
468
- client = HTTP.use(:normalize_uri => {:normalizer => :itself.to_proc})
469
- response = client.get("#{dummy.endpoint}/héllö-wörld")
470
- expect(response.status).to eq(400)
471
- end
472
-
473
- it "raises if custom URI Normalizer returns invalid path" do
474
- client = HTTP.use(:normalize_uri => {:normalizer => :itself.to_proc})
475
- expect { client.get("#{dummy.endpoint}/hello\nworld") }.
476
- to raise_error HTTP::RequestError, 'Invalid request URI: "/hello\nworld"'
477
- end
478
-
479
- it "raises if custom URI Normalizer returns invalid host" do
480
- normalizer = lambda do |uri|
481
- uri.port = nil
482
- uri.instance_variable_set(:@host, "example\ncom")
483
- uri
484
- end
485
- client = HTTP.use(:normalize_uri => {:normalizer => normalizer})
486
- expect { client.get(dummy.endpoint) }.
487
- to raise_error HTTP::RequestError, 'Invalid host: "example\ncom"'
488
- end
489
-
490
- it "uses the default URI normalizer" do
491
- client = HTTP.use :normalize_uri
492
- expect(HTTP::URI::NORMALIZER).to receive(:call).and_call_original
493
- response = client.get("#{dummy.endpoint}/héllö-wörld")
494
- expect(response.to_s).to eq("hello world")
495
- end
496
- end
497
- end
498
-
499
- it "unifies socket errors into HTTP::ConnectionError" do
500
- expect { HTTP.get "http://thishostshouldnotexists.com" }.
501
- to raise_error HTTP::ConnectionError
502
-
503
- expect { HTTP.get "http://127.0.0.1:111" }.
504
- to raise_error HTTP::ConnectionError
505
- end
506
- end
@@ -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,88 +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 "support/capture_warning"
9
- require "support/fakeio"
10
-
11
- # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
12
- RSpec.configure do |config|
13
- config.expect_with :rspec do |expectations|
14
- # This option will default to `true` in RSpec 4. It makes the `description`
15
- # and `failure_message` of custom matchers include text for helper methods
16
- # defined using `chain`, e.g.:
17
- # be_bigger_than(2).and_smaller_than(4).description
18
- # # => "be bigger than 2 and smaller than 4"
19
- # ...rather than:
20
- # # => "be bigger than 2"
21
- expectations.include_chain_clauses_in_custom_matcher_descriptions = true
22
- end
23
-
24
- config.mock_with :rspec do |mocks|
25
- # Prevents you from mocking or stubbing a method that does not exist on
26
- # a real object. This is generally recommended, and will default to
27
- # `true` in RSpec 4.
28
- mocks.verify_partial_doubles = true
29
- end
30
-
31
- # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
32
- # have no way to turn it off -- the option exists only for backwards
33
- # compatibility in RSpec 3). It causes shared context metadata to be
34
- # inherited by the metadata hash of host groups and examples, rather than
35
- # triggering implicit auto-inclusion in groups with matching metadata.
36
- config.shared_context_metadata_behavior = :apply_to_host_groups
37
-
38
- # These two settings work together to allow you to limit a spec run
39
- # to individual examples or groups you care about by tagging them with
40
- # `:focus` metadata. When nothing is tagged with `:focus`, all examples
41
- # get run.
42
- config.filter_run :focus
43
- config.filter_run_excluding :flaky if defined?(JRUBY_VERSION) && ENV["CI"]
44
- config.run_all_when_everything_filtered = true
45
-
46
- # This setting enables warnings. It's recommended, but in some cases may
47
- # be too noisy due to issues in dependencies.
48
- config.warnings = 0 == ENV["GUARD_RSPEC"].to_i
49
-
50
- # Allows RSpec to persist some state between runs in order to support
51
- # the `--only-failures` and `--next-failure` CLI options. We recommend
52
- # you configure your source control system to ignore this file.
53
- config.example_status_persistence_file_path = "spec/examples.txt"
54
-
55
- # Limits the available syntax to the non-monkey patched syntax that is
56
- # recommended. For more details, see:
57
- # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
58
- # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
59
- # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
60
- config.disable_monkey_patching!
61
-
62
- # Many RSpec users commonly either run the entire suite or an individual
63
- # file, and it's useful to allow more verbose output when running an
64
- # individual spec file.
65
- if config.files_to_run.one?
66
- # Use the documentation formatter for detailed output,
67
- # unless a formatter has already been configured
68
- # (e.g. via a command-line flag).
69
- config.default_formatter = "doc"
70
- end
71
-
72
- # Print the 10 slowest examples and example groups at the
73
- # end of the spec run, to help surface which specs are running
74
- # particularly slow.
75
- config.profile_examples = 10
76
-
77
- # Run specs in random order to surface order dependencies. If you find an
78
- # order dependency and want to debug it, you can fix the order by providing
79
- # the seed, which is printed after each run.
80
- # --seed 1234
81
- config.order = :random
82
-
83
- # Seed global randomization in this process using the `--seed` CLI option.
84
- # Setting this allows you to use `--seed` to deterministically reproduce
85
- # test failures related to randomization by passing the same `--seed` value
86
- # as the one that triggered the failure.
87
- Kernel.srand config.seed
88
- end