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
|
@@ -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
|