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.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +241 -41
  3. data/LICENSE.txt +1 -1
  4. data/README.md +110 -13
  5. data/UPGRADING.md +491 -0
  6. data/http.gemspec +32 -29
  7. data/lib/http/base64.rb +11 -1
  8. data/lib/http/chainable/helpers.rb +62 -0
  9. data/lib/http/chainable/verbs.rb +136 -0
  10. data/lib/http/chainable.rb +232 -136
  11. data/lib/http/client.rb +158 -127
  12. data/lib/http/connection/internals.rb +141 -0
  13. data/lib/http/connection.rb +126 -97
  14. data/lib/http/content_type.rb +61 -6
  15. data/lib/http/errors.rb +25 -1
  16. data/lib/http/feature.rb +65 -5
  17. data/lib/http/features/auto_deflate.rb +124 -17
  18. data/lib/http/features/auto_inflate.rb +38 -15
  19. data/lib/http/features/caching/entry.rb +178 -0
  20. data/lib/http/features/caching/in_memory_store.rb +63 -0
  21. data/lib/http/features/caching.rb +216 -0
  22. data/lib/http/features/digest_auth.rb +234 -0
  23. data/lib/http/features/instrumentation.rb +97 -17
  24. data/lib/http/features/logging.rb +183 -5
  25. data/lib/http/features/normalize_uri.rb +17 -0
  26. data/lib/http/features/raise_error.rb +18 -3
  27. data/lib/http/form_data/composite_io.rb +106 -0
  28. data/lib/http/form_data/file.rb +95 -0
  29. data/lib/http/form_data/multipart/param.rb +62 -0
  30. data/lib/http/form_data/multipart.rb +106 -0
  31. data/lib/http/form_data/part.rb +52 -0
  32. data/lib/http/form_data/readable.rb +58 -0
  33. data/lib/http/form_data/urlencoded.rb +175 -0
  34. data/lib/http/form_data/version.rb +8 -0
  35. data/lib/http/form_data.rb +102 -0
  36. data/lib/http/headers/known.rb +3 -0
  37. data/lib/http/headers/normalizer.rb +17 -36
  38. data/lib/http/headers.rb +172 -65
  39. data/lib/http/mime_type/adapter.rb +24 -9
  40. data/lib/http/mime_type/json.rb +19 -4
  41. data/lib/http/mime_type.rb +21 -3
  42. data/lib/http/options/definitions.rb +189 -0
  43. data/lib/http/options.rb +172 -125
  44. data/lib/http/redirector.rb +80 -75
  45. data/lib/http/request/body.rb +87 -6
  46. data/lib/http/request/builder.rb +184 -0
  47. data/lib/http/request/proxy.rb +83 -0
  48. data/lib/http/request/writer.rb +76 -16
  49. data/lib/http/request.rb +214 -98
  50. data/lib/http/response/body.rb +103 -18
  51. data/lib/http/response/inflater.rb +35 -7
  52. data/lib/http/response/parser.rb +98 -4
  53. data/lib/http/response/status/reasons.rb +2 -4
  54. data/lib/http/response/status.rb +141 -31
  55. data/lib/http/response.rb +219 -61
  56. data/lib/http/retriable/delay_calculator.rb +38 -11
  57. data/lib/http/retriable/errors.rb +21 -0
  58. data/lib/http/retriable/performer.rb +82 -38
  59. data/lib/http/session.rb +280 -0
  60. data/lib/http/timeout/global.rb +147 -34
  61. data/lib/http/timeout/null.rb +155 -9
  62. data/lib/http/timeout/per_operation.rb +139 -18
  63. data/lib/http/uri/normalizer.rb +82 -0
  64. data/lib/http/uri/parsing.rb +182 -0
  65. data/lib/http/uri.rb +289 -124
  66. data/lib/http/version.rb +2 -1
  67. data/lib/http.rb +11 -2
  68. data/sig/deps.rbs +122 -0
  69. data/sig/http.rbs +1619 -0
  70. data/test/http/base64_test.rb +28 -0
  71. data/test/http/client_test.rb +739 -0
  72. data/test/http/connection_test.rb +1533 -0
  73. data/test/http/content_type_test.rb +190 -0
  74. data/test/http/errors_test.rb +28 -0
  75. data/test/http/feature_test.rb +49 -0
  76. data/test/http/features/auto_deflate_test.rb +317 -0
  77. data/test/http/features/auto_inflate_test.rb +213 -0
  78. data/test/http/features/caching_test.rb +942 -0
  79. data/test/http/features/digest_auth_test.rb +996 -0
  80. data/test/http/features/instrumentation_test.rb +246 -0
  81. data/test/http/features/logging_test.rb +654 -0
  82. data/test/http/features/normalize_uri_test.rb +41 -0
  83. data/test/http/features/raise_error_test.rb +77 -0
  84. data/test/http/form_data/composite_io_test.rb +215 -0
  85. data/test/http/form_data/file_test.rb +255 -0
  86. data/test/http/form_data/fixtures/the-http-gem.info +1 -0
  87. data/test/http/form_data/multipart_test.rb +303 -0
  88. data/test/http/form_data/part_test.rb +90 -0
  89. data/test/http/form_data/urlencoded_test.rb +164 -0
  90. data/test/http/form_data_test.rb +232 -0
  91. data/test/http/headers/normalizer_test.rb +93 -0
  92. data/test/http/headers_test.rb +888 -0
  93. data/test/http/mime_type/json_test.rb +39 -0
  94. data/test/http/mime_type_test.rb +150 -0
  95. data/test/http/options/base_uri_test.rb +148 -0
  96. data/test/http/options/body_test.rb +21 -0
  97. data/test/http/options/features_test.rb +38 -0
  98. data/test/http/options/form_test.rb +21 -0
  99. data/test/http/options/headers_test.rb +32 -0
  100. data/test/http/options/json_test.rb +21 -0
  101. data/test/http/options/merge_test.rb +78 -0
  102. data/test/http/options/new_test.rb +37 -0
  103. data/test/http/options/proxy_test.rb +32 -0
  104. data/test/http/options_test.rb +575 -0
  105. data/test/http/redirector_test.rb +639 -0
  106. data/test/http/request/body_test.rb +318 -0
  107. data/test/http/request/builder_test.rb +623 -0
  108. data/test/http/request/writer_test.rb +391 -0
  109. data/test/http/request_test.rb +1733 -0
  110. data/test/http/response/body_test.rb +292 -0
  111. data/test/http/response/parser_test.rb +105 -0
  112. data/test/http/response/status_test.rb +322 -0
  113. data/test/http/response_test.rb +502 -0
  114. data/test/http/retriable/delay_calculator_test.rb +194 -0
  115. data/test/http/retriable/errors_test.rb +71 -0
  116. data/test/http/retriable/performer_test.rb +551 -0
  117. data/test/http/session_test.rb +424 -0
  118. data/test/http/timeout/global_test.rb +239 -0
  119. data/test/http/timeout/null_test.rb +218 -0
  120. data/test/http/timeout/per_operation_test.rb +220 -0
  121. data/test/http/uri/normalizer_test.rb +89 -0
  122. data/test/http/uri_test.rb +1140 -0
  123. data/test/http/version_test.rb +15 -0
  124. data/test/http_test.rb +818 -0
  125. data/test/regression_tests.rb +27 -0
  126. data/test/support/dummy_server/encoding_routes.rb +47 -0
  127. data/test/support/dummy_server/routes.rb +201 -0
  128. data/test/support/dummy_server/servlet.rb +81 -0
  129. data/test/support/dummy_server.rb +200 -0
  130. data/{spec → test}/support/fakeio.rb +2 -2
  131. data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
  132. data/test/support/http_handling_shared/timeout_tests.rb +134 -0
  133. data/test/support/http_handling_shared.rb +11 -0
  134. data/test/support/proxy_server.rb +207 -0
  135. data/test/support/servers/runner.rb +67 -0
  136. data/{spec → test}/support/simplecov.rb +11 -2
  137. data/test/support/ssl_helper.rb +108 -0
  138. data/test/test_helper.rb +38 -0
  139. metadata +108 -168
  140. data/.github/workflows/ci.yml +0 -67
  141. data/.gitignore +0 -15
  142. data/.rspec +0 -1
  143. data/.rubocop/layout.yml +0 -8
  144. data/.rubocop/metrics.yml +0 -4
  145. data/.rubocop/rspec.yml +0 -9
  146. data/.rubocop/style.yml +0 -32
  147. data/.rubocop.yml +0 -11
  148. data/.rubocop_todo.yml +0 -219
  149. data/.yardopts +0 -2
  150. data/CHANGES_OLD.md +0 -1002
  151. data/Gemfile +0 -51
  152. data/Guardfile +0 -18
  153. data/Rakefile +0 -64
  154. data/lib/http/headers/mixin.rb +0 -34
  155. data/lib/http/retriable/client.rb +0 -37
  156. data/logo.png +0 -0
  157. data/spec/lib/http/client_spec.rb +0 -556
  158. data/spec/lib/http/connection_spec.rb +0 -88
  159. data/spec/lib/http/content_type_spec.rb +0 -47
  160. data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
  161. data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
  162. data/spec/lib/http/features/instrumentation_spec.rb +0 -81
  163. data/spec/lib/http/features/logging_spec.rb +0 -65
  164. data/spec/lib/http/features/raise_error_spec.rb +0 -62
  165. data/spec/lib/http/headers/mixin_spec.rb +0 -36
  166. data/spec/lib/http/headers/normalizer_spec.rb +0 -52
  167. data/spec/lib/http/headers_spec.rb +0 -527
  168. data/spec/lib/http/options/body_spec.rb +0 -15
  169. data/spec/lib/http/options/features_spec.rb +0 -33
  170. data/spec/lib/http/options/form_spec.rb +0 -15
  171. data/spec/lib/http/options/headers_spec.rb +0 -24
  172. data/spec/lib/http/options/json_spec.rb +0 -15
  173. data/spec/lib/http/options/merge_spec.rb +0 -68
  174. data/spec/lib/http/options/new_spec.rb +0 -30
  175. data/spec/lib/http/options/proxy_spec.rb +0 -20
  176. data/spec/lib/http/options_spec.rb +0 -13
  177. data/spec/lib/http/redirector_spec.rb +0 -530
  178. data/spec/lib/http/request/body_spec.rb +0 -211
  179. data/spec/lib/http/request/writer_spec.rb +0 -121
  180. data/spec/lib/http/request_spec.rb +0 -234
  181. data/spec/lib/http/response/body_spec.rb +0 -85
  182. data/spec/lib/http/response/parser_spec.rb +0 -74
  183. data/spec/lib/http/response/status_spec.rb +0 -253
  184. data/spec/lib/http/response_spec.rb +0 -262
  185. data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
  186. data/spec/lib/http/retriable/performer_spec.rb +0 -302
  187. data/spec/lib/http/uri/normalizer_spec.rb +0 -95
  188. data/spec/lib/http/uri_spec.rb +0 -71
  189. data/spec/lib/http_spec.rb +0 -535
  190. data/spec/regression_specs.rb +0 -24
  191. data/spec/spec_helper.rb +0 -89
  192. data/spec/support/black_hole.rb +0 -13
  193. data/spec/support/dummy_server/servlet.rb +0 -203
  194. data/spec/support/dummy_server.rb +0 -44
  195. data/spec/support/fuubar.rb +0 -21
  196. data/spec/support/http_handling_shared.rb +0 -190
  197. data/spec/support/proxy_server.rb +0 -39
  198. data/spec/support/servers/config.rb +0 -11
  199. data/spec/support/servers/runner.rb +0 -19
  200. data/spec/support/ssl_helper.rb +0 -104
  201. /data/{spec → test}/support/capture_warning.rb +0 -0
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe HTTP::Options, "new" do
4
- it "supports a Options instance" do
5
- opts = HTTP::Options.new
6
- expect(HTTP::Options.new(opts)).to eq(opts)
7
- end
8
-
9
- context "with a Hash" do
10
- it "coerces :response correctly" do
11
- opts = HTTP::Options.new(:response => :object)
12
- expect(opts.response).to eq(:object)
13
- end
14
-
15
- it "coerces :headers correctly" do
16
- opts = HTTP::Options.new(:headers => {:accept => "json"})
17
- expect(opts.headers).to eq([%w[Accept json]])
18
- end
19
-
20
- it "coerces :proxy correctly" do
21
- opts = HTTP::Options.new(:proxy => {:proxy_address => "127.0.0.1", :proxy_port => 8080})
22
- expect(opts.proxy).to eq(:proxy_address => "127.0.0.1", :proxy_port => 8080)
23
- end
24
-
25
- it "coerces :form correctly" do
26
- opts = HTTP::Options.new(:form => {:foo => 42})
27
- expect(opts.form).to eq(:foo => 42)
28
- end
29
- end
30
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe HTTP::Options, "proxy" do
4
- let(:opts) { HTTP::Options.new }
5
-
6
- it "defaults to {}" do
7
- expect(opts.proxy).to eq({})
8
- end
9
-
10
- it "may be specified with with_proxy" do
11
- opts2 = opts.with_proxy(:proxy_address => "127.0.0.1", :proxy_port => 8080)
12
- expect(opts.proxy).to eq({})
13
- expect(opts2.proxy).to eq(:proxy_address => "127.0.0.1", :proxy_port => 8080)
14
- end
15
-
16
- it "accepts proxy address, port, username, and password" do
17
- opts2 = opts.with_proxy(:proxy_address => "127.0.0.1", :proxy_port => 8080, :proxy_username => "username", :proxy_password => "password")
18
- expect(opts2.proxy).to eq(:proxy_address => "127.0.0.1", :proxy_port => 8080, :proxy_username => "username", :proxy_password => "password")
19
- end
20
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe HTTP::Options do
4
- subject { described_class.new(:response => :body) }
5
-
6
- it "has reader methods for attributes" do
7
- expect(subject.response).to eq(:body)
8
- end
9
-
10
- it "coerces to a Hash" do
11
- expect(subject.to_hash).to be_a(Hash)
12
- end
13
- end
@@ -1,530 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe HTTP::Redirector do
4
- def simple_response(status, body = "", headers = {})
5
- HTTP::Response.new(
6
- :status => status,
7
- :version => "1.1",
8
- :headers => headers,
9
- :body => body,
10
- :request => HTTP::Request.new(:verb => :get, :uri => "http://example.com")
11
- )
12
- end
13
-
14
- def redirect_response(status, location, set_cookie = {})
15
- res = simple_response status, "", "Location" => location
16
- set_cookie.each do |name, value|
17
- res.headers.add("Set-Cookie", "#{name}=#{value}; path=/; httponly; secure; SameSite=none; Secure")
18
- end
19
- res
20
- end
21
-
22
- describe "#strict" do
23
- subject { redirector.strict }
24
-
25
- context "by default" do
26
- let(:redirector) { described_class.new }
27
- it { is_expected.to be true }
28
- end
29
- end
30
-
31
- describe "#max_hops" do
32
- subject { redirector.max_hops }
33
-
34
- context "by default" do
35
- let(:redirector) { described_class.new }
36
- it { is_expected.to eq 5 }
37
- end
38
- end
39
-
40
- describe "#perform" do
41
- let(:options) { {} }
42
- let(:redirector) { described_class.new options }
43
-
44
- it "fails with TooManyRedirectsError if max hops reached" do
45
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
46
- res = proc { |prev_req| redirect_response(301, "#{prev_req.uri}/1") }
47
-
48
- expect { redirector.perform(req, res.call(req), &res) }.
49
- to raise_error HTTP::Redirector::TooManyRedirectsError
50
- end
51
-
52
- it "fails with EndlessRedirectError if endless loop detected" do
53
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
54
- res = redirect_response(301, req.uri)
55
-
56
- expect { redirector.perform(req, res) { res } }.
57
- to raise_error HTTP::Redirector::EndlessRedirectError
58
- end
59
-
60
- it "fails with StateError if there were no Location header" do
61
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
62
- res = simple_response(301)
63
-
64
- expect { |b| redirector.perform(req, res, &b) }.
65
- to raise_error HTTP::StateError
66
- end
67
-
68
- it "returns first non-redirect response" do
69
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
70
- hops = [
71
- redirect_response(301, "http://example.com/1"),
72
- redirect_response(301, "http://example.com/2"),
73
- redirect_response(301, "http://example.com/3"),
74
- simple_response(200, "foo"),
75
- redirect_response(301, "http://example.com/4"),
76
- simple_response(200, "bar")
77
- ]
78
-
79
- res = redirector.perform(req, hops.shift) { hops.shift }
80
- expect(res.to_s).to eq "foo"
81
- end
82
-
83
- it "concatenates multiple Location headers" do
84
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
85
- headers = HTTP::Headers.new
86
-
87
- %w[http://example.com /123].each { |loc| headers.add("Location", loc) }
88
-
89
- res = redirector.perform(req, simple_response(301, "", headers)) do |redirect|
90
- simple_response(200, redirect.uri.to_s)
91
- end
92
-
93
- expect(res.to_s).to eq "http://example.com/123"
94
- end
95
-
96
- it "returns cookies in response" do
97
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
98
- hops = [
99
- redirect_response(301, "http://example.com/1", {"foo" => "42"}),
100
- redirect_response(301, "http://example.com/2", {"bar" => "53", "deleted" => "foo"}),
101
- redirect_response(301, "http://example.com/3", {"baz" => "64", "deleted" => ""}),
102
- redirect_response(301, "http://example.com/4", {"baz" => "65"}),
103
- simple_response(200, "bar")
104
- ]
105
-
106
- request_cookies = [
107
- {"foo" => "42"},
108
- {"foo" => "42", "bar" => "53", "deleted" => "foo"},
109
- {"foo" => "42", "bar" => "53", "baz" => "64"},
110
- {"foo" => "42", "bar" => "53", "baz" => "65"}
111
- ]
112
-
113
- res = redirector.perform(req, hops.shift) do |request|
114
- req_cookie = HTTP::Cookie.cookie_value_to_hash(request.headers["Cookie"] || "")
115
- expect(req_cookie).to eq request_cookies.shift
116
- hops.shift
117
- end
118
-
119
- expect(res.to_s).to eq "bar"
120
- expect(res.cookies.cookies.to_h { |c| [c.name, c.value] }).to eq({
121
- "foo" => "42",
122
- "bar" => "53",
123
- "baz" => "65"
124
- })
125
- end
126
-
127
- it "returns original cookies in response" do
128
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
129
- req.headers.set("Cookie", "foo=42; deleted=baz")
130
- hops = [
131
- redirect_response(301, "http://example.com/1", {"bar" => "64", "deleted" => ""}),
132
- simple_response(200, "bar")
133
- ]
134
-
135
- request_cookies = [
136
- {"foo" => "42", "bar" => "64"},
137
- {"foo" => "42", "bar" => "64"}
138
- ]
139
-
140
- res = redirector.perform(req, hops.shift) do |request|
141
- req_cookie = HTTP::Cookie.cookie_value_to_hash(request.headers["Cookie"] || "")
142
- expect(req_cookie).to eq request_cookies.shift
143
- hops.shift
144
- end
145
- expect(res.to_s).to eq "bar"
146
- cookies = res.cookies.cookies.to_h { |c| [c.name, c.value] }
147
- expect(cookies["foo"]).to eq "42"
148
- expect(cookies["bar"]).to eq "64"
149
- expect(cookies["deleted"]).to eq nil
150
- end
151
-
152
- context "with on_redirect callback" do
153
- let(:options) do
154
- {
155
- :on_redirect => proc do |response, location|
156
- @redirect_response = response
157
- @redirect_location = location
158
- end
159
- }
160
- end
161
-
162
- it "calls on_redirect" do
163
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
164
- hops = [
165
- redirect_response(301, "http://example.com/1"),
166
- redirect_response(301, "http://example.com/2"),
167
- simple_response(200, "foo")
168
- ]
169
-
170
- redirector.perform(req, hops.shift) do |prev_req, _|
171
- expect(@redirect_location.uri.to_s).to eq prev_req.uri.to_s
172
- expect(@redirect_response.code).to eq 301
173
- hops.shift
174
- end
175
- end
176
- end
177
-
178
- context "following 300 redirect" do
179
- context "with strict mode" do
180
- let(:options) { {:strict => true} }
181
-
182
- it "it follows with original verb if it's safe" do
183
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
184
- res = redirect_response 300, "http://example.com/1"
185
-
186
- redirector.perform(req, res) do |prev_req, _|
187
- expect(prev_req.verb).to be :head
188
- simple_response 200
189
- end
190
- end
191
-
192
- it "raises StateError if original request was PUT" do
193
- req = HTTP::Request.new :verb => :put, :uri => "http://example.com"
194
- res = redirect_response 300, "http://example.com/1"
195
-
196
- expect { redirector.perform(req, res) { simple_response 200 } }.
197
- to raise_error HTTP::StateError
198
- end
199
-
200
- it "raises StateError if original request was POST" do
201
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
202
- res = redirect_response 300, "http://example.com/1"
203
-
204
- expect { redirector.perform(req, res) { simple_response 200 } }.
205
- to raise_error HTTP::StateError
206
- end
207
-
208
- it "raises StateError if original request was DELETE" do
209
- req = HTTP::Request.new :verb => :delete, :uri => "http://example.com"
210
- res = redirect_response 300, "http://example.com/1"
211
-
212
- expect { redirector.perform(req, res) { simple_response 200 } }.
213
- to raise_error HTTP::StateError
214
- end
215
- end
216
-
217
- context "with non-strict mode" do
218
- let(:options) { {:strict => false} }
219
-
220
- it "it follows with original verb if it's safe" do
221
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
222
- res = redirect_response 300, "http://example.com/1"
223
-
224
- redirector.perform(req, res) do |prev_req, _|
225
- expect(prev_req.verb).to be :head
226
- simple_response 200
227
- end
228
- end
229
-
230
- it "it follows with GET if original request was PUT" do
231
- req = HTTP::Request.new :verb => :put, :uri => "http://example.com"
232
- res = redirect_response 300, "http://example.com/1"
233
-
234
- redirector.perform(req, res) do |prev_req, _|
235
- expect(prev_req.verb).to be :get
236
- simple_response 200
237
- end
238
- end
239
-
240
- it "it follows with GET if original request was POST" do
241
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
242
- res = redirect_response 300, "http://example.com/1"
243
-
244
- redirector.perform(req, res) do |prev_req, _|
245
- expect(prev_req.verb).to be :get
246
- simple_response 200
247
- end
248
- end
249
-
250
- it "it follows with GET if original request was DELETE" do
251
- req = HTTP::Request.new :verb => :delete, :uri => "http://example.com"
252
- res = redirect_response 300, "http://example.com/1"
253
-
254
- redirector.perform(req, res) do |prev_req, _|
255
- expect(prev_req.verb).to be :get
256
- simple_response 200
257
- end
258
- end
259
- end
260
- end
261
-
262
- context "following 301 redirect" do
263
- context "with strict mode" do
264
- let(:options) { {:strict => true} }
265
-
266
- it "it follows with original verb if it's safe" do
267
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
268
- res = redirect_response 301, "http://example.com/1"
269
-
270
- redirector.perform(req, res) do |prev_req, _|
271
- expect(prev_req.verb).to be :head
272
- simple_response 200
273
- end
274
- end
275
-
276
- it "raises StateError if original request was PUT" do
277
- req = HTTP::Request.new :verb => :put, :uri => "http://example.com"
278
- res = redirect_response 301, "http://example.com/1"
279
-
280
- expect { redirector.perform(req, res) { simple_response 200 } }.
281
- to raise_error HTTP::StateError
282
- end
283
-
284
- it "raises StateError if original request was POST" do
285
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
286
- res = redirect_response 301, "http://example.com/1"
287
-
288
- expect { redirector.perform(req, res) { simple_response 200 } }.
289
- to raise_error HTTP::StateError
290
- end
291
-
292
- it "raises StateError if original request was DELETE" do
293
- req = HTTP::Request.new :verb => :delete, :uri => "http://example.com"
294
- res = redirect_response 301, "http://example.com/1"
295
-
296
- expect { redirector.perform(req, res) { simple_response 200 } }.
297
- to raise_error HTTP::StateError
298
- end
299
- end
300
-
301
- context "with non-strict mode" do
302
- let(:options) { {:strict => false} }
303
-
304
- it "it follows with original verb if it's safe" do
305
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
306
- res = redirect_response 301, "http://example.com/1"
307
-
308
- redirector.perform(req, res) do |prev_req, _|
309
- expect(prev_req.verb).to be :head
310
- simple_response 200
311
- end
312
- end
313
-
314
- it "it follows with GET if original request was PUT" do
315
- req = HTTP::Request.new :verb => :put, :uri => "http://example.com"
316
- res = redirect_response 301, "http://example.com/1"
317
-
318
- redirector.perform(req, res) do |prev_req, _|
319
- expect(prev_req.verb).to be :get
320
- simple_response 200
321
- end
322
- end
323
-
324
- it "it follows with GET if original request was POST" do
325
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
326
- res = redirect_response 301, "http://example.com/1"
327
-
328
- redirector.perform(req, res) do |prev_req, _|
329
- expect(prev_req.verb).to be :get
330
- simple_response 200
331
- end
332
- end
333
-
334
- it "it follows with GET if original request was DELETE" do
335
- req = HTTP::Request.new :verb => :delete, :uri => "http://example.com"
336
- res = redirect_response 301, "http://example.com/1"
337
-
338
- redirector.perform(req, res) do |prev_req, _|
339
- expect(prev_req.verb).to be :get
340
- simple_response 200
341
- end
342
- end
343
- end
344
- end
345
-
346
- context "following 302 redirect" do
347
- context "with strict mode" do
348
- let(:options) { {:strict => true} }
349
-
350
- it "it follows with original verb if it's safe" do
351
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
352
- res = redirect_response 302, "http://example.com/1"
353
-
354
- redirector.perform(req, res) do |prev_req, _|
355
- expect(prev_req.verb).to be :head
356
- simple_response 200
357
- end
358
- end
359
-
360
- it "raises StateError if original request was PUT" do
361
- req = HTTP::Request.new :verb => :put, :uri => "http://example.com"
362
- res = redirect_response 302, "http://example.com/1"
363
-
364
- expect { redirector.perform(req, res) { simple_response 200 } }.
365
- to raise_error HTTP::StateError
366
- end
367
-
368
- it "raises StateError if original request was POST" do
369
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
370
- res = redirect_response 302, "http://example.com/1"
371
-
372
- expect { redirector.perform(req, res) { simple_response 200 } }.
373
- to raise_error HTTP::StateError
374
- end
375
-
376
- it "raises StateError if original request was DELETE" do
377
- req = HTTP::Request.new :verb => :delete, :uri => "http://example.com"
378
- res = redirect_response 302, "http://example.com/1"
379
-
380
- expect { redirector.perform(req, res) { simple_response 200 } }.
381
- to raise_error HTTP::StateError
382
- end
383
- end
384
-
385
- context "with non-strict mode" do
386
- let(:options) { {:strict => false} }
387
-
388
- it "it follows with original verb if it's safe" do
389
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
390
- res = redirect_response 302, "http://example.com/1"
391
-
392
- redirector.perform(req, res) do |prev_req, _|
393
- expect(prev_req.verb).to be :head
394
- simple_response 200
395
- end
396
- end
397
-
398
- it "it follows with GET if original request was PUT" do
399
- req = HTTP::Request.new :verb => :put, :uri => "http://example.com"
400
- res = redirect_response 302, "http://example.com/1"
401
-
402
- redirector.perform(req, res) do |prev_req, _|
403
- expect(prev_req.verb).to be :get
404
- simple_response 200
405
- end
406
- end
407
-
408
- it "it follows with GET if original request was POST" do
409
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
410
- res = redirect_response 302, "http://example.com/1"
411
-
412
- redirector.perform(req, res) do |prev_req, _|
413
- expect(prev_req.verb).to be :get
414
- simple_response 200
415
- end
416
- end
417
-
418
- it "it follows with GET if original request was DELETE" do
419
- req = HTTP::Request.new :verb => :delete, :uri => "http://example.com"
420
- res = redirect_response 302, "http://example.com/1"
421
-
422
- redirector.perform(req, res) do |prev_req, _|
423
- expect(prev_req.verb).to be :get
424
- simple_response 200
425
- end
426
- end
427
- end
428
- end
429
-
430
- context "following 303 redirect" do
431
- it "follows with HEAD if original request was HEAD" do
432
- req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
433
- res = redirect_response 303, "http://example.com/1"
434
-
435
- redirector.perform(req, res) do |prev_req, _|
436
- expect(prev_req.verb).to be :head
437
- simple_response 200
438
- end
439
- end
440
-
441
- it "follows with GET if original request was GET" do
442
- req = HTTP::Request.new :verb => :get, :uri => "http://example.com"
443
- res = redirect_response 303, "http://example.com/1"
444
-
445
- redirector.perform(req, res) do |prev_req, _|
446
- expect(prev_req.verb).to be :get
447
- simple_response 200
448
- end
449
- end
450
-
451
- it "follows with GET if original request was neither GET nor HEAD" do
452
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
453
- res = redirect_response 303, "http://example.com/1"
454
-
455
- redirector.perform(req, res) do |prev_req, _|
456
- expect(prev_req.verb).to be :get
457
- simple_response 200
458
- end
459
- end
460
- end
461
-
462
- context "following 307 redirect" do
463
- it "follows with original request's verb" do
464
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
465
- res = redirect_response 307, "http://example.com/1"
466
-
467
- redirector.perform(req, res) do |prev_req, _|
468
- expect(prev_req.verb).to be :post
469
- simple_response 200
470
- end
471
- end
472
- end
473
-
474
- context "following 308 redirect" do
475
- it "follows with original request's verb" do
476
- req = HTTP::Request.new :verb => :post, :uri => "http://example.com"
477
- res = redirect_response 308, "http://example.com/1"
478
-
479
- redirector.perform(req, res) do |prev_req, _|
480
- expect(prev_req.verb).to be :post
481
- simple_response 200
482
- end
483
- end
484
- end
485
-
486
- describe "changing verbs during redirects" do
487
- let(:options) { {:strict => false} }
488
- let(:post_body) { HTTP::Request::Body.new("i might be way longer in real life") }
489
- let(:cookie) { "dont=eat my cookies" }
490
-
491
- def a_dangerous_request(verb)
492
- HTTP::Request.new(
493
- :verb => verb, :uri => "http://example.com",
494
- :body => post_body, :headers => {
495
- "Content-Type" => "meme",
496
- "Cookie" => cookie
497
- }
498
- )
499
- end
500
-
501
- def empty_body
502
- HTTP::Request::Body.new(nil)
503
- end
504
-
505
- it "follows without body/content type if it has to change verb" do
506
- req = a_dangerous_request(:post)
507
- res = redirect_response 302, "http://example.com/1"
508
-
509
- redirector.perform(req, res) do |prev_req, _|
510
- expect(prev_req.body).to eq(empty_body)
511
- expect(prev_req.headers["Cookie"]).to eq(cookie)
512
- expect(prev_req.headers["Content-Type"]).to eq(nil)
513
- simple_response 200
514
- end
515
- end
516
-
517
- it "leaves body/content-type intact if it does not have to change verb" do
518
- req = a_dangerous_request(:post)
519
- res = redirect_response 307, "http://example.com/1"
520
-
521
- redirector.perform(req, res) do |prev_req, _|
522
- expect(prev_req.body).to eq(post_body)
523
- expect(prev_req.headers["Cookie"]).to eq(cookie)
524
- expect(prev_req.headers["Content-Type"]).to eq("meme")
525
- simple_response 200
526
- end
527
- end
528
- end
529
- end
530
- end