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
|
@@ -0,0 +1,1733 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "test_helper"
|
|
4
|
+
|
|
5
|
+
class HTTPRequestTest < Minitest::Test
|
|
6
|
+
cover "HTTP::Request*"
|
|
7
|
+
|
|
8
|
+
def build_request(verb: :get, uri: "http://example.com/foo?bar=baz", headers: { accept: "text/html" }, proxy: {},
|
|
9
|
+
**)
|
|
10
|
+
HTTP::Request.new(verb: verb, uri: uri, headers: headers, proxy: proxy, **)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# #initialize
|
|
14
|
+
|
|
15
|
+
def test_initialize_provides_a_headers_accessor
|
|
16
|
+
assert_kind_of HTTP::Headers, build_request.headers
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def test_initialize_provides_a_scheme_accessor
|
|
20
|
+
assert_equal :http, build_request.scheme
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_initialize_provides_a_verb_accessor
|
|
24
|
+
assert_equal :get, build_request.verb
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def test_initialize_provides_a_uri_accessor
|
|
28
|
+
assert_equal HTTP::URI.parse("http://example.com/foo?bar=baz"), build_request.uri
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def test_initialize_provides_a_proxy_accessor
|
|
32
|
+
assert_equal({}, build_request.proxy)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_initialize_provides_a_version_accessor_defaulting_to_1_1
|
|
36
|
+
assert_equal "1.1", build_request.version
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_initialize_provides_a_body_accessor
|
|
40
|
+
assert_instance_of HTTP::Request::Body, build_request.body
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_initialize_provides_a_uri_normalizer_accessor
|
|
44
|
+
assert_equal HTTP::URI::NORMALIZER, build_request.uri_normalizer
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def test_initialize_stores_a_custom_uri_normalizer
|
|
48
|
+
custom = ->(uri) { HTTP::URI.parse(uri) }
|
|
49
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/", uri_normalizer: custom)
|
|
50
|
+
|
|
51
|
+
assert_equal custom, req.uri_normalizer
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_initialize_stores_a_custom_version
|
|
55
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/", version: "2.0")
|
|
56
|
+
|
|
57
|
+
assert_equal "2.0", req.version
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_initialize_stores_the_proxy_hash
|
|
61
|
+
p = { proxy_address: "proxy.example.com", proxy_port: 8080 }
|
|
62
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/", proxy: p)
|
|
63
|
+
|
|
64
|
+
assert_equal p, req.proxy
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def test_initialize_downcases_and_symbolizes_the_verb
|
|
68
|
+
req = HTTP::Request.new(verb: "POST", uri: "http://example.com/")
|
|
69
|
+
|
|
70
|
+
assert_equal :post, req.verb
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def test_initialize_downcases_the_scheme
|
|
74
|
+
req = HTTP::Request.new(verb: :get, uri: "HTTP://example.com/")
|
|
75
|
+
|
|
76
|
+
assert_equal :http, req.scheme
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def test_initialize_accepts_https_scheme
|
|
80
|
+
req = HTTP::Request.new(verb: :get, uri: "https://example.com/")
|
|
81
|
+
|
|
82
|
+
assert_equal :https, req.scheme
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def test_initialize_accepts_ws_scheme
|
|
86
|
+
req = HTTP::Request.new(verb: :get, uri: "ws://example.com/")
|
|
87
|
+
|
|
88
|
+
assert_equal :ws, req.scheme
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def test_initialize_accepts_wss_scheme
|
|
92
|
+
req = HTTP::Request.new(verb: :get, uri: "wss://example.com/")
|
|
93
|
+
|
|
94
|
+
assert_equal :wss, req.scheme
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def test_initialize_stores_body_source
|
|
98
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/", body: "hello")
|
|
99
|
+
|
|
100
|
+
assert_equal "hello", req.body.source
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def test_initialize_wraps_non_body_body_in_body_object
|
|
104
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/", body: "hello")
|
|
105
|
+
|
|
106
|
+
assert_instance_of HTTP::Request::Body, req.body
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def test_initialize_passes_through_an_existing_body_object
|
|
110
|
+
existing_body = HTTP::Request::Body.new("hello")
|
|
111
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/", body: existing_body)
|
|
112
|
+
|
|
113
|
+
assert_same existing_body, req.body
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def test_initialize_passes_through_a_body_subclass
|
|
117
|
+
subclass_body = Class.new(HTTP::Request::Body).new("hello")
|
|
118
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/", body: subclass_body)
|
|
119
|
+
|
|
120
|
+
assert_same subclass_body, req.body
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_initialize_sets_given_headers
|
|
124
|
+
assert_equal "text/html", build_request.headers["Accept"]
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_initialize_raises_invalid_error_for_uri_without_scheme
|
|
128
|
+
err = assert_raises(HTTP::URI::InvalidError) do
|
|
129
|
+
HTTP::Request.new(verb: :get, uri: "example.com/")
|
|
130
|
+
end
|
|
131
|
+
assert_match(/invalid URI/, err.message)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def test_initialize_raises_argument_error_for_nil_uri
|
|
135
|
+
err = assert_raises(ArgumentError) do
|
|
136
|
+
HTTP::Request.new(verb: :get, uri: nil)
|
|
137
|
+
end
|
|
138
|
+
assert_equal "uri is nil", err.message
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def test_initialize_raises_argument_error_for_empty_string_uri
|
|
142
|
+
err = assert_raises(ArgumentError) do
|
|
143
|
+
HTTP::Request.new(verb: :get, uri: "")
|
|
144
|
+
end
|
|
145
|
+
assert_equal "uri is empty", err.message
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
def test_initialize_does_not_raise_for_non_string_non_empty_uri_like_objects
|
|
149
|
+
uri = HTTP::URI.parse("http://example.com/")
|
|
150
|
+
req = HTTP::Request.new(verb: :get, uri: uri)
|
|
151
|
+
|
|
152
|
+
assert_equal :http, req.scheme
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def test_initialize_raises_invalid_error_for_malformed_uri
|
|
156
|
+
err = assert_raises(HTTP::URI::InvalidError) do
|
|
157
|
+
HTTP::Request.new(verb: :get, uri: ":")
|
|
158
|
+
end
|
|
159
|
+
assert_match(/invalid URI/, err.message)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
def test_initialize_raises_unsupported_scheme_error_for_unsupported_scheme
|
|
163
|
+
err = assert_raises(HTTP::Request::UnsupportedSchemeError) do
|
|
164
|
+
HTTP::Request.new(verb: :get, uri: "ftp://example.com/")
|
|
165
|
+
end
|
|
166
|
+
assert_match(/unknown scheme/, err.message)
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
def test_initialize_raises_unsupported_method_error_for_unknown_verbs
|
|
170
|
+
err = assert_raises(HTTP::Request::UnsupportedMethodError) do
|
|
171
|
+
HTTP::Request.new(verb: :foobar, uri: "http://example.com/")
|
|
172
|
+
end
|
|
173
|
+
assert_match(/unknown method/, err.message)
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def test_initialize_includes_verb_in_unsupported_method_error_message
|
|
177
|
+
err = assert_raises(HTTP::Request::UnsupportedMethodError) do
|
|
178
|
+
HTTP::Request.new(verb: :foobar, uri: "http://example.com/")
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
assert_includes err.message, "foobar"
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
def test_initialize_includes_uri_in_invalid_error_message_for_missing_scheme
|
|
185
|
+
err = assert_raises(HTTP::URI::InvalidError) do
|
|
186
|
+
HTTP::Request.new(verb: :get, uri: "example.com/")
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
assert_includes err.message, "example.com/"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_initialize_includes_scheme_in_unsupported_scheme_error_message
|
|
193
|
+
err = assert_raises(HTTP::Request::UnsupportedSchemeError) do
|
|
194
|
+
HTTP::Request.new(verb: :get, uri: "ftp://example.com/")
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
assert_includes err.message, "ftp"
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def test_initialize_defaults_proxy_to_an_empty_hash
|
|
201
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/")
|
|
202
|
+
|
|
203
|
+
assert_equal({}, req.proxy)
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def test_initialize_sets_default_headers_when_headers_arg_is_nil
|
|
207
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/")
|
|
208
|
+
|
|
209
|
+
assert_equal "example.com", req.headers["Host"]
|
|
210
|
+
assert_equal HTTP::Request::USER_AGENT, req.headers["User-Agent"]
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
# Host header
|
|
214
|
+
|
|
215
|
+
def test_host_header_defaults_to_the_host_from_the_uri
|
|
216
|
+
assert_equal "example.com", build_request.headers["Host"]
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def test_host_header_with_non_standard_port_includes_the_port
|
|
220
|
+
request = build_request(uri: "http://example.com:3000/")
|
|
221
|
+
|
|
222
|
+
assert_equal "example.com:3000", request.headers["Host"]
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def test_host_header_with_standard_https_port_omits_the_port
|
|
226
|
+
request = build_request(uri: "https://example.com/")
|
|
227
|
+
|
|
228
|
+
assert_equal "example.com", request.headers["Host"]
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def test_host_header_with_non_standard_https_port_includes_the_port
|
|
232
|
+
request = build_request(uri: "https://example.com:8443/")
|
|
233
|
+
|
|
234
|
+
assert_equal "example.com:8443", request.headers["Host"]
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
def test_host_header_when_explicitly_given_uses_the_given_host
|
|
238
|
+
request = build_request(headers: { accept: "text/html", host: "github.com" })
|
|
239
|
+
|
|
240
|
+
assert_equal "github.com", request.headers["Host"]
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def test_host_header_when_host_contains_whitespace_raises_request_error
|
|
244
|
+
normalizer = lambda { |uri|
|
|
245
|
+
u = HTTP::URI.parse(uri)
|
|
246
|
+
u.host = "exam ple.com"
|
|
247
|
+
u
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
assert_raises(HTTP::RequestError) do
|
|
251
|
+
HTTP::Request.new(verb: :get, uri: "http://example.com/", uri_normalizer: normalizer)
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
|
|
255
|
+
def test_host_header_when_host_contains_whitespace_includes_invalid_host_in_error
|
|
256
|
+
normalizer = lambda { |uri|
|
|
257
|
+
u = HTTP::URI.parse(uri)
|
|
258
|
+
u.host = "exam ple.com"
|
|
259
|
+
u
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
err = assert_raises(HTTP::RequestError) do
|
|
263
|
+
HTTP::Request.new(verb: :get, uri: "http://example.com/", uri_normalizer: normalizer)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
assert_includes err.message, "exam ple.com".inspect
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# User-Agent header
|
|
270
|
+
|
|
271
|
+
def test_user_agent_header_defaults_to_http_request_user_agent
|
|
272
|
+
assert_equal HTTP::Request::USER_AGENT, build_request.headers["User-Agent"]
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def test_user_agent_header_when_explicitly_given_uses_it
|
|
276
|
+
request = build_request(headers: { accept: "text/html", user_agent: "MrCrawly/123" })
|
|
277
|
+
|
|
278
|
+
assert_equal "MrCrawly/123", request.headers["User-Agent"]
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
# #using_proxy?
|
|
282
|
+
|
|
283
|
+
def test_using_proxy_with_empty_proxy_hash_returns_false
|
|
284
|
+
refute_predicate build_request(proxy: {}), :using_proxy?
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def test_using_proxy_with_one_key_in_proxy_returns_false
|
|
288
|
+
refute_predicate build_request(proxy: { proxy_address: "proxy.example.com" }), :using_proxy?
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
def test_using_proxy_with_two_keys_in_proxy_returns_true
|
|
292
|
+
assert_predicate build_request(proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 }), :using_proxy?
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
def test_using_proxy_with_four_keys_in_proxy_returns_true
|
|
296
|
+
proxy = { proxy_address: "proxy.example.com", proxy_port: 8080,
|
|
297
|
+
proxy_username: "user", proxy_password: "pass" }
|
|
298
|
+
|
|
299
|
+
assert_predicate build_request(proxy: proxy), :using_proxy?
|
|
300
|
+
end
|
|
301
|
+
|
|
302
|
+
# #using_authenticated_proxy?
|
|
303
|
+
|
|
304
|
+
def test_using_authenticated_proxy_with_empty_proxy_hash_returns_false
|
|
305
|
+
refute_predicate build_request(proxy: {}), :using_authenticated_proxy?
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def test_using_authenticated_proxy_with_two_keys_returns_false
|
|
309
|
+
refute_predicate build_request(proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 }),
|
|
310
|
+
:using_authenticated_proxy?
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def test_using_authenticated_proxy_with_three_keys_returns_false
|
|
314
|
+
proxy = { proxy_address: "proxy.example.com", proxy_port: 8080, proxy_username: "user" }
|
|
315
|
+
|
|
316
|
+
refute_predicate build_request(proxy: proxy), :using_authenticated_proxy?
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def test_using_authenticated_proxy_with_four_keys_returns_true
|
|
320
|
+
proxy = { proxy_address: "proxy.example.com", proxy_port: 8080,
|
|
321
|
+
proxy_username: "user", proxy_password: "pass" }
|
|
322
|
+
|
|
323
|
+
assert_predicate build_request(proxy: proxy), :using_authenticated_proxy?
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# #redirect
|
|
327
|
+
|
|
328
|
+
def test_redirect_has_correct_uri
|
|
329
|
+
request = build_request(
|
|
330
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
331
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
332
|
+
)
|
|
333
|
+
redirected = request.redirect("http://blog.example.com/")
|
|
334
|
+
|
|
335
|
+
assert_equal HTTP::URI.parse("http://blog.example.com/"), redirected.uri
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def test_redirect_has_correct_verb
|
|
339
|
+
request = build_request(
|
|
340
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
341
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
342
|
+
)
|
|
343
|
+
redirected = request.redirect("http://blog.example.com/")
|
|
344
|
+
|
|
345
|
+
assert_equal request.verb, redirected.verb
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
def test_redirect_has_correct_body
|
|
349
|
+
request = build_request(
|
|
350
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
351
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
352
|
+
)
|
|
353
|
+
redirected = request.redirect("http://blog.example.com/")
|
|
354
|
+
|
|
355
|
+
assert_equal request.body, redirected.body
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
def test_redirect_has_correct_proxy
|
|
359
|
+
request = build_request(
|
|
360
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
361
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
362
|
+
)
|
|
363
|
+
redirected = request.redirect("http://blog.example.com/")
|
|
364
|
+
|
|
365
|
+
assert_equal request.proxy, redirected.proxy
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def test_redirect_presets_new_host_header
|
|
369
|
+
request = build_request(
|
|
370
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
371
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
372
|
+
)
|
|
373
|
+
redirected = request.redirect("http://blog.example.com/")
|
|
374
|
+
|
|
375
|
+
assert_equal "blog.example.com", redirected.headers["Host"]
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
def test_redirect_preserves_version
|
|
379
|
+
req = HTTP::Request.new(
|
|
380
|
+
verb: :post, uri: "http://example.com/", body: "The Ultimate Question", version: "2.0"
|
|
381
|
+
)
|
|
382
|
+
redir = req.redirect("http://blog.example.com/")
|
|
383
|
+
|
|
384
|
+
assert_equal "2.0", redir.version
|
|
385
|
+
end
|
|
386
|
+
|
|
387
|
+
def test_redirect_preserves_uri_normalizer
|
|
388
|
+
custom = ->(uri) { HTTP::URI.parse(uri) }
|
|
389
|
+
req = HTTP::Request.new(
|
|
390
|
+
verb: :post, uri: "http://example.com/", body: "The Ultimate Question", uri_normalizer: custom
|
|
391
|
+
)
|
|
392
|
+
redir = req.redirect("http://blog.example.com/")
|
|
393
|
+
|
|
394
|
+
assert_equal custom, redir.uri_normalizer
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
def test_redirect_preserves_accept_header
|
|
398
|
+
request = build_request(
|
|
399
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
400
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
401
|
+
)
|
|
402
|
+
redirected = request.redirect("http://blog.example.com/")
|
|
403
|
+
|
|
404
|
+
assert_equal "text/html", redirected.headers["Accept"]
|
|
405
|
+
end
|
|
406
|
+
|
|
407
|
+
# redirect with non-standard port
|
|
408
|
+
|
|
409
|
+
def test_redirect_with_non_standard_port_has_correct_uri
|
|
410
|
+
request = build_request(
|
|
411
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
412
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
413
|
+
)
|
|
414
|
+
redirected = request.redirect("http://example.com:8080")
|
|
415
|
+
|
|
416
|
+
assert_equal HTTP::URI.parse("http://example.com:8080"), redirected.uri
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def test_redirect_with_non_standard_port_has_correct_verb
|
|
420
|
+
request = build_request(
|
|
421
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
422
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
423
|
+
)
|
|
424
|
+
redirected = request.redirect("http://example.com:8080")
|
|
425
|
+
|
|
426
|
+
assert_equal request.verb, redirected.verb
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
def test_redirect_with_non_standard_port_has_correct_body
|
|
430
|
+
request = build_request(
|
|
431
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
432
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
433
|
+
)
|
|
434
|
+
redirected = request.redirect("http://example.com:8080")
|
|
435
|
+
|
|
436
|
+
assert_equal request.body, redirected.body
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def test_redirect_with_non_standard_port_has_correct_proxy
|
|
440
|
+
request = build_request(
|
|
441
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
442
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
443
|
+
)
|
|
444
|
+
redirected = request.redirect("http://example.com:8080")
|
|
445
|
+
|
|
446
|
+
assert_equal request.proxy, redirected.proxy
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def test_redirect_with_non_standard_port_presets_new_host_header
|
|
450
|
+
request = build_request(
|
|
451
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
452
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
453
|
+
)
|
|
454
|
+
redirected = request.redirect("http://example.com:8080")
|
|
455
|
+
|
|
456
|
+
assert_equal "example.com:8080", redirected.headers["Host"]
|
|
457
|
+
end
|
|
458
|
+
|
|
459
|
+
# redirect with schema-less absolute URL
|
|
460
|
+
|
|
461
|
+
def test_redirect_with_schema_less_absolute_url_has_correct_uri
|
|
462
|
+
request = build_request(
|
|
463
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
464
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
465
|
+
)
|
|
466
|
+
redirected = request.redirect("//another.example.com/blog")
|
|
467
|
+
|
|
468
|
+
assert_equal HTTP::URI.parse("http://another.example.com/blog"), redirected.uri
|
|
469
|
+
end
|
|
470
|
+
|
|
471
|
+
def test_redirect_with_schema_less_absolute_url_has_correct_verb
|
|
472
|
+
request = build_request(
|
|
473
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
474
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
475
|
+
)
|
|
476
|
+
redirected = request.redirect("//another.example.com/blog")
|
|
477
|
+
|
|
478
|
+
assert_equal request.verb, redirected.verb
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
def test_redirect_with_schema_less_absolute_url_has_correct_body
|
|
482
|
+
request = build_request(
|
|
483
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
484
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
485
|
+
)
|
|
486
|
+
redirected = request.redirect("//another.example.com/blog")
|
|
487
|
+
|
|
488
|
+
assert_equal request.body, redirected.body
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
def test_redirect_with_schema_less_absolute_url_has_correct_proxy
|
|
492
|
+
request = build_request(
|
|
493
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
494
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
495
|
+
)
|
|
496
|
+
redirected = request.redirect("//another.example.com/blog")
|
|
497
|
+
|
|
498
|
+
assert_equal request.proxy, redirected.proxy
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def test_redirect_with_schema_less_absolute_url_presets_new_host_header
|
|
502
|
+
request = build_request(
|
|
503
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
504
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
505
|
+
)
|
|
506
|
+
redirected = request.redirect("//another.example.com/blog")
|
|
507
|
+
|
|
508
|
+
assert_equal "another.example.com", redirected.headers["Host"]
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
# redirect with relative URL
|
|
512
|
+
|
|
513
|
+
def test_redirect_with_relative_url_has_correct_uri
|
|
514
|
+
request = build_request(
|
|
515
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
516
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
517
|
+
)
|
|
518
|
+
redirected = request.redirect("/blog")
|
|
519
|
+
|
|
520
|
+
assert_equal HTTP::URI.parse("http://example.com/blog"), redirected.uri
|
|
521
|
+
end
|
|
522
|
+
|
|
523
|
+
def test_redirect_with_relative_url_has_correct_verb
|
|
524
|
+
request = build_request(
|
|
525
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
526
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
527
|
+
)
|
|
528
|
+
redirected = request.redirect("/blog")
|
|
529
|
+
|
|
530
|
+
assert_equal request.verb, redirected.verb
|
|
531
|
+
end
|
|
532
|
+
|
|
533
|
+
def test_redirect_with_relative_url_has_correct_body
|
|
534
|
+
request = build_request(
|
|
535
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
536
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
537
|
+
)
|
|
538
|
+
redirected = request.redirect("/blog")
|
|
539
|
+
|
|
540
|
+
assert_equal request.body, redirected.body
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
def test_redirect_with_relative_url_has_correct_proxy
|
|
544
|
+
request = build_request(
|
|
545
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
546
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
547
|
+
)
|
|
548
|
+
redirected = request.redirect("/blog")
|
|
549
|
+
|
|
550
|
+
assert_equal request.proxy, redirected.proxy
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def test_redirect_with_relative_url_keeps_host_header
|
|
554
|
+
request = build_request(
|
|
555
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
556
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
557
|
+
)
|
|
558
|
+
redirected = request.redirect("/blog")
|
|
559
|
+
|
|
560
|
+
assert_equal "example.com", redirected.headers["Host"]
|
|
561
|
+
end
|
|
562
|
+
|
|
563
|
+
def test_redirect_with_relative_url_and_non_standard_port_has_correct_uri
|
|
564
|
+
request = HTTP::Request.new(
|
|
565
|
+
verb: :post, uri: "http://example.com:8080/",
|
|
566
|
+
headers: { accept: "text/html" },
|
|
567
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" },
|
|
568
|
+
body: "The Ultimate Question"
|
|
569
|
+
)
|
|
570
|
+
redirected = request.redirect("/blog")
|
|
571
|
+
|
|
572
|
+
assert_equal HTTP::URI.parse("http://example.com:8080/blog"), redirected.uri
|
|
573
|
+
end
|
|
574
|
+
|
|
575
|
+
# redirect with relative URL missing leading slash
|
|
576
|
+
|
|
577
|
+
def test_redirect_with_relative_url_missing_leading_slash_has_correct_uri
|
|
578
|
+
request = build_request(
|
|
579
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
580
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
581
|
+
)
|
|
582
|
+
redirected = request.redirect("blog")
|
|
583
|
+
|
|
584
|
+
assert_equal HTTP::URI.parse("http://example.com/blog"), redirected.uri
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
def test_redirect_with_relative_url_missing_leading_slash_has_correct_verb
|
|
588
|
+
request = build_request(
|
|
589
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
590
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
591
|
+
)
|
|
592
|
+
redirected = request.redirect("blog")
|
|
593
|
+
|
|
594
|
+
assert_equal request.verb, redirected.verb
|
|
595
|
+
end
|
|
596
|
+
|
|
597
|
+
def test_redirect_with_relative_url_missing_leading_slash_has_correct_body
|
|
598
|
+
request = build_request(
|
|
599
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
600
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
601
|
+
)
|
|
602
|
+
redirected = request.redirect("blog")
|
|
603
|
+
|
|
604
|
+
assert_equal request.body, redirected.body
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
def test_redirect_with_relative_url_missing_leading_slash_has_correct_proxy
|
|
608
|
+
request = build_request(
|
|
609
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
610
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
611
|
+
)
|
|
612
|
+
redirected = request.redirect("blog")
|
|
613
|
+
|
|
614
|
+
assert_equal request.proxy, redirected.proxy
|
|
615
|
+
end
|
|
616
|
+
|
|
617
|
+
def test_redirect_with_relative_url_missing_leading_slash_keeps_host_header
|
|
618
|
+
request = build_request(
|
|
619
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
620
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
621
|
+
)
|
|
622
|
+
redirected = request.redirect("blog")
|
|
623
|
+
|
|
624
|
+
assert_equal "example.com", redirected.headers["Host"]
|
|
625
|
+
end
|
|
626
|
+
|
|
627
|
+
def test_redirect_with_relative_url_missing_leading_slash_and_non_standard_port
|
|
628
|
+
request = HTTP::Request.new(
|
|
629
|
+
verb: :post, uri: "http://example.com:8080/",
|
|
630
|
+
headers: { accept: "text/html" },
|
|
631
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" },
|
|
632
|
+
body: "The Ultimate Question"
|
|
633
|
+
)
|
|
634
|
+
redirected = request.redirect("blog")
|
|
635
|
+
|
|
636
|
+
assert_equal HTTP::URI.parse("http://example.com:8080/blog"), redirected.uri
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
# redirect with new verb
|
|
640
|
+
|
|
641
|
+
def test_redirect_with_new_verb_has_correct_verb
|
|
642
|
+
request = build_request(
|
|
643
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
644
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
645
|
+
)
|
|
646
|
+
redirected = request.redirect("http://blog.example.com/", :get)
|
|
647
|
+
|
|
648
|
+
assert_equal :get, redirected.verb
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
def test_redirect_with_new_verb_sets_body_to_nil_for_get_redirect
|
|
652
|
+
request = build_request(
|
|
653
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
654
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
655
|
+
)
|
|
656
|
+
redirected = request.redirect("http://blog.example.com/", :get)
|
|
657
|
+
|
|
658
|
+
assert_nil redirected.body.source
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
def test_redirect_with_verb_changed_to_non_get_preserves_body
|
|
662
|
+
request = build_request(
|
|
663
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
664
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
665
|
+
)
|
|
666
|
+
redir = request.redirect("http://blog.example.com/", :put)
|
|
667
|
+
|
|
668
|
+
assert_equal "The Ultimate Question", redir.body.source
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
# redirect with sensitive headers - same origin
|
|
672
|
+
|
|
673
|
+
def test_redirect_same_origin_preserves_authorization_header
|
|
674
|
+
request = build_request(
|
|
675
|
+
verb: :post, uri: "http://example.com/",
|
|
676
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
677
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
678
|
+
)
|
|
679
|
+
redirected = request.redirect("/other-path")
|
|
680
|
+
|
|
681
|
+
assert_equal "Bearer token123", redirected.headers["Authorization"]
|
|
682
|
+
end
|
|
683
|
+
|
|
684
|
+
def test_redirect_same_origin_preserves_cookie_header
|
|
685
|
+
request = build_request(
|
|
686
|
+
verb: :post, uri: "http://example.com/",
|
|
687
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
688
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
689
|
+
)
|
|
690
|
+
redirected = request.redirect("/other-path")
|
|
691
|
+
|
|
692
|
+
assert_equal "session=abc", redirected.headers["Cookie"]
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
# redirect with sensitive headers - different host
|
|
696
|
+
|
|
697
|
+
def test_redirect_different_host_strips_authorization_header
|
|
698
|
+
request = build_request(
|
|
699
|
+
verb: :post, uri: "http://example.com/",
|
|
700
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
701
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
702
|
+
)
|
|
703
|
+
redirected = request.redirect("http://other.example.com/")
|
|
704
|
+
|
|
705
|
+
assert_nil redirected.headers["Authorization"]
|
|
706
|
+
end
|
|
707
|
+
|
|
708
|
+
def test_redirect_different_host_strips_cookie_header
|
|
709
|
+
request = build_request(
|
|
710
|
+
verb: :post, uri: "http://example.com/",
|
|
711
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
712
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
713
|
+
)
|
|
714
|
+
redirected = request.redirect("http://other.example.com/")
|
|
715
|
+
|
|
716
|
+
assert_nil redirected.headers["Cookie"]
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
# redirect with sensitive headers - different scheme
|
|
720
|
+
|
|
721
|
+
def test_redirect_different_scheme_strips_authorization_header
|
|
722
|
+
request = build_request(
|
|
723
|
+
verb: :post, uri: "http://example.com/",
|
|
724
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
725
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
726
|
+
)
|
|
727
|
+
redirected = request.redirect("https://example.com/")
|
|
728
|
+
|
|
729
|
+
assert_nil redirected.headers["Authorization"]
|
|
730
|
+
end
|
|
731
|
+
|
|
732
|
+
def test_redirect_different_scheme_strips_cookie_header
|
|
733
|
+
request = build_request(
|
|
734
|
+
verb: :post, uri: "http://example.com/",
|
|
735
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
736
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
737
|
+
)
|
|
738
|
+
redirected = request.redirect("https://example.com/")
|
|
739
|
+
|
|
740
|
+
assert_nil redirected.headers["Cookie"]
|
|
741
|
+
end
|
|
742
|
+
|
|
743
|
+
# redirect with sensitive headers - different port
|
|
744
|
+
|
|
745
|
+
def test_redirect_different_port_strips_authorization_header
|
|
746
|
+
request = build_request(
|
|
747
|
+
verb: :post, uri: "http://example.com/",
|
|
748
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
749
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
750
|
+
)
|
|
751
|
+
redirected = request.redirect("http://example.com:8080/")
|
|
752
|
+
|
|
753
|
+
assert_nil redirected.headers["Authorization"]
|
|
754
|
+
end
|
|
755
|
+
|
|
756
|
+
def test_redirect_different_port_strips_cookie_header
|
|
757
|
+
request = build_request(
|
|
758
|
+
verb: :post, uri: "http://example.com/",
|
|
759
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
760
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
761
|
+
)
|
|
762
|
+
redirected = request.redirect("http://example.com:8080/")
|
|
763
|
+
|
|
764
|
+
assert_nil redirected.headers["Cookie"]
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
# redirect with sensitive headers - schema-less URL with different host
|
|
768
|
+
|
|
769
|
+
def test_redirect_schema_less_different_host_strips_authorization_header
|
|
770
|
+
request = build_request(
|
|
771
|
+
verb: :post, uri: "http://example.com/",
|
|
772
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
773
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
774
|
+
)
|
|
775
|
+
redirected = request.redirect("//other.example.com/path")
|
|
776
|
+
|
|
777
|
+
assert_nil redirected.headers["Authorization"]
|
|
778
|
+
end
|
|
779
|
+
|
|
780
|
+
def test_redirect_schema_less_different_host_strips_cookie_header
|
|
781
|
+
request = build_request(
|
|
782
|
+
verb: :post, uri: "http://example.com/",
|
|
783
|
+
headers: { accept: "text/html", authorization: "Bearer token123", cookie: "session=abc" },
|
|
784
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
785
|
+
)
|
|
786
|
+
redirected = request.redirect("//other.example.com/path")
|
|
787
|
+
|
|
788
|
+
assert_nil redirected.headers["Cookie"]
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
# redirect with Content-Type header
|
|
792
|
+
|
|
793
|
+
def test_redirect_post_preserves_content_type
|
|
794
|
+
request = build_request(
|
|
795
|
+
verb: :post, uri: "http://example.com/",
|
|
796
|
+
headers: { accept: "text/html", content_type: "application/json" },
|
|
797
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
798
|
+
)
|
|
799
|
+
redir = request.redirect("http://blog.example.com/")
|
|
800
|
+
|
|
801
|
+
assert_equal "application/json", redir.headers["Content-Type"]
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
def test_redirect_to_get_strips_content_type
|
|
805
|
+
request = build_request(
|
|
806
|
+
verb: :post, uri: "http://example.com/",
|
|
807
|
+
headers: { accept: "text/html", content_type: "application/json" },
|
|
808
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
809
|
+
)
|
|
810
|
+
redir = request.redirect("http://blog.example.com/", :get)
|
|
811
|
+
|
|
812
|
+
assert_nil redir.headers["Content-Type"]
|
|
813
|
+
end
|
|
814
|
+
|
|
815
|
+
def test_redirect_always_strips_host_header_before_redirect
|
|
816
|
+
request = build_request(
|
|
817
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
818
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
819
|
+
)
|
|
820
|
+
redir = request.redirect("/other-path")
|
|
821
|
+
|
|
822
|
+
assert_equal "example.com", redir.headers["Host"]
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
def test_redirect_does_not_mutate_original_request_headers
|
|
826
|
+
request = build_request(
|
|
827
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
828
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
829
|
+
)
|
|
830
|
+
original_accept = request.headers["Accept"]
|
|
831
|
+
request.redirect("http://other.example.com/", :get)
|
|
832
|
+
|
|
833
|
+
assert_equal original_accept, request.headers["Accept"]
|
|
834
|
+
assert_equal "example.com", request.headers["Host"]
|
|
835
|
+
end
|
|
836
|
+
|
|
837
|
+
def test_redirect_preserves_body_source_on_non_get_redirect
|
|
838
|
+
request = build_request(
|
|
839
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
840
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
841
|
+
)
|
|
842
|
+
redir = request.redirect("http://blog.example.com/")
|
|
843
|
+
|
|
844
|
+
assert_equal "The Ultimate Question", redir.body.source
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
def test_redirect_creates_a_new_body_object
|
|
848
|
+
request = build_request(
|
|
849
|
+
verb: :post, uri: "http://example.com/", headers: { accept: "text/html" },
|
|
850
|
+
proxy: { proxy_username: "douglas", proxy_password: "adams" }, body: "The Ultimate Question"
|
|
851
|
+
)
|
|
852
|
+
redir = request.redirect("http://blog.example.com/")
|
|
853
|
+
|
|
854
|
+
refute_same request.body, redir.body
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
# #headline
|
|
858
|
+
|
|
859
|
+
def test_headline_returns_the_request_line
|
|
860
|
+
assert_equal "GET /foo?bar=baz HTTP/1.1", build_request.headline
|
|
861
|
+
end
|
|
862
|
+
|
|
863
|
+
def test_headline_with_encoded_query_does_not_unencode_query_part
|
|
864
|
+
encoded_query = "t=1970-01-01T01%3A00%3A00%2B01%3A00"
|
|
865
|
+
request = build_request(uri: "http://example.com/foo/?#{encoded_query}")
|
|
866
|
+
|
|
867
|
+
assert_equal "GET /foo/?#{encoded_query} HTTP/1.1", request.headline
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
def test_headline_with_non_ascii_path_encodes_non_ascii_part
|
|
871
|
+
request = build_request(uri: "http://example.com/\u30AD\u30E7")
|
|
872
|
+
|
|
873
|
+
assert_equal "GET /%E3%82%AD%E3%83%A7 HTTP/1.1", request.headline
|
|
874
|
+
end
|
|
875
|
+
|
|
876
|
+
def test_headline_with_fragment_omits_fragment_part
|
|
877
|
+
request = build_request(uri: "http://example.com/foo#bar")
|
|
878
|
+
|
|
879
|
+
assert_equal "GET /foo HTTP/1.1", request.headline
|
|
880
|
+
end
|
|
881
|
+
|
|
882
|
+
def test_headline_with_proxy_uses_absolute_uri_in_request_line
|
|
883
|
+
request = build_request(proxy: { user: "user", pass: "pass" })
|
|
884
|
+
|
|
885
|
+
assert_equal "GET http://example.com/foo?bar=baz HTTP/1.1", request.headline
|
|
886
|
+
end
|
|
887
|
+
|
|
888
|
+
def test_headline_with_proxy_and_fragment_omits_fragment
|
|
889
|
+
request = build_request(uri: "http://example.com/foo#bar", proxy: { user: "user", pass: "pass" })
|
|
890
|
+
|
|
891
|
+
assert_equal "GET http://example.com/foo HTTP/1.1", request.headline
|
|
892
|
+
end
|
|
893
|
+
|
|
894
|
+
def test_headline_with_proxy_and_https_uses_relative_uri
|
|
895
|
+
request = build_request(uri: "https://example.com/foo?bar=baz", proxy: { user: "user", pass: "pass" })
|
|
896
|
+
|
|
897
|
+
assert_equal "GET /foo?bar=baz HTTP/1.1", request.headline
|
|
898
|
+
end
|
|
899
|
+
|
|
900
|
+
def test_headline_with_custom_version_includes_version
|
|
901
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/", version: "2.0")
|
|
902
|
+
|
|
903
|
+
assert_equal "GET / HTTP/2.0", req.headline
|
|
904
|
+
end
|
|
905
|
+
|
|
906
|
+
def test_headline_with_non_get_verb_upcases_the_verb
|
|
907
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/")
|
|
908
|
+
|
|
909
|
+
assert_equal "POST / HTTP/1.1", req.headline
|
|
910
|
+
end
|
|
911
|
+
|
|
912
|
+
def test_headline_with_uri_containing_whitespace_raises_request_error
|
|
913
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/foo")
|
|
914
|
+
req.uri.path = "/foo bar"
|
|
915
|
+
|
|
916
|
+
err = assert_raises(HTTP::RequestError) { req.headline }
|
|
917
|
+
|
|
918
|
+
assert_includes err.message, "Invalid request URI"
|
|
919
|
+
assert_includes err.message, "/foo bar".inspect
|
|
920
|
+
end
|
|
921
|
+
|
|
922
|
+
# #socket_host
|
|
923
|
+
|
|
924
|
+
def test_socket_host_without_proxy_returns_uri_host
|
|
925
|
+
assert_equal "example.com", build_request(proxy: {}).socket_host
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
def test_socket_host_with_proxy_returns_proxy_address
|
|
929
|
+
request = build_request(proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 })
|
|
930
|
+
|
|
931
|
+
assert_equal "proxy.example.com", request.socket_host
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
# #socket_port
|
|
935
|
+
|
|
936
|
+
def test_socket_port_without_proxy_returns_uri_port
|
|
937
|
+
assert_equal 80, build_request(proxy: {}).socket_port
|
|
938
|
+
end
|
|
939
|
+
|
|
940
|
+
def test_socket_port_without_proxy_with_explicit_port_returns_explicit_port
|
|
941
|
+
request = build_request(uri: "http://example.com:3000/", proxy: {})
|
|
942
|
+
|
|
943
|
+
assert_equal 3000, request.socket_port
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
def test_socket_port_without_proxy_with_https_returns_443
|
|
947
|
+
request = build_request(uri: "https://example.com/", proxy: {})
|
|
948
|
+
|
|
949
|
+
assert_equal 443, request.socket_port
|
|
950
|
+
end
|
|
951
|
+
|
|
952
|
+
def test_socket_port_with_proxy_returns_proxy_port
|
|
953
|
+
request = build_request(proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 })
|
|
954
|
+
|
|
955
|
+
assert_equal 8080, request.socket_port
|
|
956
|
+
end
|
|
957
|
+
|
|
958
|
+
# #stream
|
|
959
|
+
|
|
960
|
+
def test_stream_without_proxy_writes_request_to_socket
|
|
961
|
+
io = StringIO.new
|
|
962
|
+
build_request(proxy: {}).stream(io)
|
|
963
|
+
|
|
964
|
+
assert_includes io.string, "GET /foo?bar=baz HTTP/1.1"
|
|
965
|
+
end
|
|
966
|
+
|
|
967
|
+
def test_stream_without_proxy_does_not_include_proxy_headers
|
|
968
|
+
io = StringIO.new
|
|
969
|
+
build_request(proxy: {}).stream(io)
|
|
970
|
+
|
|
971
|
+
refute_includes io.string, "Proxy-Authorization"
|
|
972
|
+
end
|
|
973
|
+
|
|
974
|
+
def test_stream_with_proxy_headers_but_not_using_proxy_does_not_include_them
|
|
975
|
+
io = StringIO.new
|
|
976
|
+
build_request(proxy: { proxy_headers: { "X-Leak" => "nope" } }).stream(io)
|
|
977
|
+
|
|
978
|
+
refute_includes io.string, "X-Leak"
|
|
979
|
+
end
|
|
980
|
+
|
|
981
|
+
def test_stream_with_http_proxy_merges_proxy_headers
|
|
982
|
+
io = StringIO.new
|
|
983
|
+
request = build_request(proxy: {
|
|
984
|
+
proxy_address: "proxy.example.com",
|
|
985
|
+
proxy_port: 8080,
|
|
986
|
+
proxy_headers: { "X-Proxy" => "value" }
|
|
987
|
+
})
|
|
988
|
+
request.stream(io)
|
|
989
|
+
|
|
990
|
+
assert_includes io.string, "X-Proxy: value"
|
|
991
|
+
end
|
|
992
|
+
|
|
993
|
+
def test_stream_with_https_proxy_and_proxy_headers_does_not_merge
|
|
994
|
+
io = StringIO.new
|
|
995
|
+
request = build_request(
|
|
996
|
+
uri: "https://example.com/foo",
|
|
997
|
+
proxy: {
|
|
998
|
+
proxy_address: "proxy.example.com",
|
|
999
|
+
proxy_port: 8080,
|
|
1000
|
+
proxy_username: "user",
|
|
1001
|
+
proxy_password: "pass",
|
|
1002
|
+
proxy_headers: { "X-Proxy" => "nope" }
|
|
1003
|
+
}
|
|
1004
|
+
)
|
|
1005
|
+
request.stream(io)
|
|
1006
|
+
output = io.string
|
|
1007
|
+
|
|
1008
|
+
refute_includes output, "X-Proxy"
|
|
1009
|
+
refute_includes output, "Proxy-Authorization"
|
|
1010
|
+
end
|
|
1011
|
+
|
|
1012
|
+
def test_stream_with_authenticated_http_proxy_includes_proxy_authorization
|
|
1013
|
+
io = StringIO.new
|
|
1014
|
+
request = build_request(proxy: {
|
|
1015
|
+
proxy_address: "proxy.example.com",
|
|
1016
|
+
proxy_port: 8080,
|
|
1017
|
+
proxy_username: "user",
|
|
1018
|
+
proxy_password: "pass"
|
|
1019
|
+
})
|
|
1020
|
+
request.stream(io)
|
|
1021
|
+
|
|
1022
|
+
assert_includes io.string, "Proxy-Authorization: Basic"
|
|
1023
|
+
end
|
|
1024
|
+
|
|
1025
|
+
# #connect_using_proxy
|
|
1026
|
+
|
|
1027
|
+
def test_connect_using_proxy_writes_a_connect_request
|
|
1028
|
+
io = StringIO.new
|
|
1029
|
+
request = build_request(
|
|
1030
|
+
uri: "https://example.com/foo",
|
|
1031
|
+
proxy: {
|
|
1032
|
+
proxy_address: "proxy.example.com",
|
|
1033
|
+
proxy_port: 8080,
|
|
1034
|
+
proxy_username: "user",
|
|
1035
|
+
proxy_password: "pass"
|
|
1036
|
+
}
|
|
1037
|
+
)
|
|
1038
|
+
request.connect_using_proxy(io)
|
|
1039
|
+
output = io.string
|
|
1040
|
+
|
|
1041
|
+
assert_includes output, "CONNECT example.com:443 HTTP/1.1"
|
|
1042
|
+
end
|
|
1043
|
+
|
|
1044
|
+
def test_connect_using_proxy_includes_proxy_auth_headers
|
|
1045
|
+
io = StringIO.new
|
|
1046
|
+
request = build_request(
|
|
1047
|
+
uri: "https://example.com/foo",
|
|
1048
|
+
proxy: {
|
|
1049
|
+
proxy_address: "proxy.example.com",
|
|
1050
|
+
proxy_port: 8080,
|
|
1051
|
+
proxy_username: "user",
|
|
1052
|
+
proxy_password: "pass"
|
|
1053
|
+
}
|
|
1054
|
+
)
|
|
1055
|
+
request.connect_using_proxy(io)
|
|
1056
|
+
output = io.string
|
|
1057
|
+
|
|
1058
|
+
assert_includes output, "Proxy-Authorization: Basic"
|
|
1059
|
+
end
|
|
1060
|
+
|
|
1061
|
+
def test_connect_using_proxy_includes_host_header
|
|
1062
|
+
io = StringIO.new
|
|
1063
|
+
request = build_request(
|
|
1064
|
+
uri: "https://example.com/foo",
|
|
1065
|
+
proxy: {
|
|
1066
|
+
proxy_address: "proxy.example.com",
|
|
1067
|
+
proxy_port: 8080,
|
|
1068
|
+
proxy_username: "user",
|
|
1069
|
+
proxy_password: "pass"
|
|
1070
|
+
}
|
|
1071
|
+
)
|
|
1072
|
+
request.connect_using_proxy(io)
|
|
1073
|
+
output = io.string
|
|
1074
|
+
|
|
1075
|
+
assert_includes output, "Host: example.com"
|
|
1076
|
+
end
|
|
1077
|
+
|
|
1078
|
+
def test_connect_using_proxy_includes_user_agent_header
|
|
1079
|
+
io = StringIO.new
|
|
1080
|
+
request = build_request(
|
|
1081
|
+
uri: "https://example.com/foo",
|
|
1082
|
+
proxy: {
|
|
1083
|
+
proxy_address: "proxy.example.com",
|
|
1084
|
+
proxy_port: 8080,
|
|
1085
|
+
proxy_username: "user",
|
|
1086
|
+
proxy_password: "pass"
|
|
1087
|
+
}
|
|
1088
|
+
)
|
|
1089
|
+
request.connect_using_proxy(io)
|
|
1090
|
+
output = io.string
|
|
1091
|
+
|
|
1092
|
+
assert_includes output, "User-Agent:"
|
|
1093
|
+
end
|
|
1094
|
+
|
|
1095
|
+
# #proxy_connect_header
|
|
1096
|
+
|
|
1097
|
+
def test_proxy_connect_header_returns_connect_headline
|
|
1098
|
+
request = build_request(uri: "https://example.com/")
|
|
1099
|
+
|
|
1100
|
+
assert_equal "CONNECT example.com:443 HTTP/1.1", request.proxy_connect_header
|
|
1101
|
+
end
|
|
1102
|
+
|
|
1103
|
+
def test_proxy_connect_header_with_non_standard_port_includes_the_port
|
|
1104
|
+
request = build_request(uri: "https://example.com:8443/")
|
|
1105
|
+
|
|
1106
|
+
assert_equal "CONNECT example.com:8443 HTTP/1.1", request.proxy_connect_header
|
|
1107
|
+
end
|
|
1108
|
+
|
|
1109
|
+
def test_proxy_connect_header_with_custom_version_includes_the_version
|
|
1110
|
+
req = HTTP::Request.new(verb: :get, uri: "https://example.com/", version: "2.0")
|
|
1111
|
+
|
|
1112
|
+
assert_equal "CONNECT example.com:443 HTTP/2.0", req.proxy_connect_header
|
|
1113
|
+
end
|
|
1114
|
+
|
|
1115
|
+
# #proxy_connect_headers
|
|
1116
|
+
|
|
1117
|
+
def test_proxy_connect_headers_with_authenticated_proxy_includes_proxy_authorization
|
|
1118
|
+
request = build_request(
|
|
1119
|
+
uri: "https://example.com/",
|
|
1120
|
+
proxy: {
|
|
1121
|
+
proxy_address: "proxy.example.com",
|
|
1122
|
+
proxy_port: 8080,
|
|
1123
|
+
proxy_username: "user",
|
|
1124
|
+
proxy_password: "pass"
|
|
1125
|
+
}
|
|
1126
|
+
)
|
|
1127
|
+
hdrs = request.proxy_connect_headers
|
|
1128
|
+
|
|
1129
|
+
assert_match(/^Basic /, hdrs["Proxy-Authorization"])
|
|
1130
|
+
end
|
|
1131
|
+
|
|
1132
|
+
def test_proxy_connect_headers_with_authenticated_proxy_includes_host_header
|
|
1133
|
+
request = build_request(
|
|
1134
|
+
uri: "https://example.com/",
|
|
1135
|
+
proxy: {
|
|
1136
|
+
proxy_address: "proxy.example.com",
|
|
1137
|
+
proxy_port: 8080,
|
|
1138
|
+
proxy_username: "user",
|
|
1139
|
+
proxy_password: "pass"
|
|
1140
|
+
}
|
|
1141
|
+
)
|
|
1142
|
+
hdrs = request.proxy_connect_headers
|
|
1143
|
+
|
|
1144
|
+
assert_equal "example.com", hdrs["Host"]
|
|
1145
|
+
end
|
|
1146
|
+
|
|
1147
|
+
def test_proxy_connect_headers_with_authenticated_proxy_includes_user_agent
|
|
1148
|
+
request = build_request(
|
|
1149
|
+
uri: "https://example.com/",
|
|
1150
|
+
proxy: {
|
|
1151
|
+
proxy_address: "proxy.example.com",
|
|
1152
|
+
proxy_port: 8080,
|
|
1153
|
+
proxy_username: "user",
|
|
1154
|
+
proxy_password: "pass"
|
|
1155
|
+
}
|
|
1156
|
+
)
|
|
1157
|
+
hdrs = request.proxy_connect_headers
|
|
1158
|
+
|
|
1159
|
+
assert_equal HTTP::Request::USER_AGENT, hdrs["User-Agent"]
|
|
1160
|
+
end
|
|
1161
|
+
|
|
1162
|
+
def test_proxy_connect_headers_with_unauthenticated_proxy_no_proxy_authorization
|
|
1163
|
+
request = build_request(
|
|
1164
|
+
uri: "https://example.com/",
|
|
1165
|
+
proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 }
|
|
1166
|
+
)
|
|
1167
|
+
hdrs = request.proxy_connect_headers
|
|
1168
|
+
|
|
1169
|
+
assert_nil hdrs["Proxy-Authorization"]
|
|
1170
|
+
end
|
|
1171
|
+
|
|
1172
|
+
def test_proxy_connect_headers_with_unauthenticated_proxy_includes_host
|
|
1173
|
+
request = build_request(
|
|
1174
|
+
uri: "https://example.com/",
|
|
1175
|
+
proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 }
|
|
1176
|
+
)
|
|
1177
|
+
hdrs = request.proxy_connect_headers
|
|
1178
|
+
|
|
1179
|
+
assert_equal "example.com", hdrs["Host"]
|
|
1180
|
+
end
|
|
1181
|
+
|
|
1182
|
+
def test_proxy_connect_headers_with_unauthenticated_proxy_includes_user_agent
|
|
1183
|
+
request = build_request(
|
|
1184
|
+
uri: "https://example.com/",
|
|
1185
|
+
proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 }
|
|
1186
|
+
)
|
|
1187
|
+
hdrs = request.proxy_connect_headers
|
|
1188
|
+
|
|
1189
|
+
assert_equal HTTP::Request::USER_AGENT, hdrs["User-Agent"]
|
|
1190
|
+
end
|
|
1191
|
+
|
|
1192
|
+
def test_proxy_connect_headers_with_proxy_headers_includes_custom_headers
|
|
1193
|
+
request = build_request(
|
|
1194
|
+
uri: "https://example.com/",
|
|
1195
|
+
proxy: {
|
|
1196
|
+
proxy_address: "proxy.example.com",
|
|
1197
|
+
proxy_port: 8080,
|
|
1198
|
+
proxy_headers: { "X-Custom" => "value" }
|
|
1199
|
+
}
|
|
1200
|
+
)
|
|
1201
|
+
hdrs = request.proxy_connect_headers
|
|
1202
|
+
|
|
1203
|
+
assert_equal "value", hdrs["X-Custom"]
|
|
1204
|
+
end
|
|
1205
|
+
|
|
1206
|
+
def test_proxy_connect_headers_without_proxy_headers_key_only_includes_host_and_user_agent
|
|
1207
|
+
request = build_request(
|
|
1208
|
+
uri: "https://example.com/",
|
|
1209
|
+
proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 }
|
|
1210
|
+
)
|
|
1211
|
+
hdrs = request.proxy_connect_headers
|
|
1212
|
+
|
|
1213
|
+
assert_instance_of HTTP::Headers, hdrs
|
|
1214
|
+
assert_equal %w[Host User-Agent], hdrs.keys
|
|
1215
|
+
end
|
|
1216
|
+
|
|
1217
|
+
# #include_proxy_headers
|
|
1218
|
+
|
|
1219
|
+
def test_include_proxy_headers_with_proxy_headers_and_authenticated_proxy_merges
|
|
1220
|
+
request = build_request(proxy: {
|
|
1221
|
+
proxy_address: "proxy.example.com",
|
|
1222
|
+
proxy_port: 8080,
|
|
1223
|
+
proxy_username: "user",
|
|
1224
|
+
proxy_password: "pass",
|
|
1225
|
+
proxy_headers: { "X-Proxy" => "value" }
|
|
1226
|
+
})
|
|
1227
|
+
request.include_proxy_headers
|
|
1228
|
+
|
|
1229
|
+
assert_equal "value", request.headers["X-Proxy"]
|
|
1230
|
+
end
|
|
1231
|
+
|
|
1232
|
+
def test_include_proxy_headers_with_proxy_headers_and_authenticated_proxy_adds_auth
|
|
1233
|
+
request = build_request(proxy: {
|
|
1234
|
+
proxy_address: "proxy.example.com",
|
|
1235
|
+
proxy_port: 8080,
|
|
1236
|
+
proxy_username: "user",
|
|
1237
|
+
proxy_password: "pass",
|
|
1238
|
+
proxy_headers: { "X-Proxy" => "value" }
|
|
1239
|
+
})
|
|
1240
|
+
request.include_proxy_headers
|
|
1241
|
+
|
|
1242
|
+
assert_match(/^Basic /, request.headers["Proxy-Authorization"])
|
|
1243
|
+
end
|
|
1244
|
+
|
|
1245
|
+
def test_include_proxy_headers_with_proxy_headers_but_unauthenticated_merges
|
|
1246
|
+
request = build_request(proxy: {
|
|
1247
|
+
proxy_address: "proxy.example.com",
|
|
1248
|
+
proxy_port: 8080,
|
|
1249
|
+
proxy_headers: { "X-Proxy" => "value" }
|
|
1250
|
+
})
|
|
1251
|
+
request.include_proxy_headers
|
|
1252
|
+
|
|
1253
|
+
assert_equal "value", request.headers["X-Proxy"]
|
|
1254
|
+
end
|
|
1255
|
+
|
|
1256
|
+
def test_include_proxy_headers_with_proxy_headers_but_unauthenticated_no_auth
|
|
1257
|
+
request = build_request(proxy: {
|
|
1258
|
+
proxy_address: "proxy.example.com",
|
|
1259
|
+
proxy_port: 8080,
|
|
1260
|
+
proxy_headers: { "X-Proxy" => "value" }
|
|
1261
|
+
})
|
|
1262
|
+
request.include_proxy_headers
|
|
1263
|
+
|
|
1264
|
+
assert_nil request.headers["Proxy-Authorization"]
|
|
1265
|
+
end
|
|
1266
|
+
|
|
1267
|
+
def test_include_proxy_headers_without_proxy_headers_key_still_adds_auth
|
|
1268
|
+
request = build_request(proxy: {
|
|
1269
|
+
proxy_address: "proxy.example.com",
|
|
1270
|
+
proxy_port: 8080,
|
|
1271
|
+
proxy_username: "user",
|
|
1272
|
+
proxy_password: "pass"
|
|
1273
|
+
})
|
|
1274
|
+
request.include_proxy_headers
|
|
1275
|
+
|
|
1276
|
+
assert_match(/^Basic /, request.headers["Proxy-Authorization"])
|
|
1277
|
+
end
|
|
1278
|
+
|
|
1279
|
+
def test_include_proxy_headers_without_proxy_headers_key_does_not_raise
|
|
1280
|
+
request = build_request(proxy: {
|
|
1281
|
+
proxy_address: "proxy.example.com",
|
|
1282
|
+
proxy_port: 8080,
|
|
1283
|
+
proxy_username: "user",
|
|
1284
|
+
proxy_password: "pass"
|
|
1285
|
+
})
|
|
1286
|
+
headers_before = request.headers.to_h.except("Proxy-Authorization")
|
|
1287
|
+
request.include_proxy_headers
|
|
1288
|
+
headers_after = request.headers.to_h.except("Proxy-Authorization")
|
|
1289
|
+
|
|
1290
|
+
assert_equal headers_before, headers_after
|
|
1291
|
+
end
|
|
1292
|
+
|
|
1293
|
+
# #include_proxy_authorization_header
|
|
1294
|
+
|
|
1295
|
+
def test_include_proxy_authorization_header_sets_header
|
|
1296
|
+
request = build_request(proxy: {
|
|
1297
|
+
proxy_address: "proxy.example.com",
|
|
1298
|
+
proxy_port: 8080,
|
|
1299
|
+
proxy_username: "user",
|
|
1300
|
+
proxy_password: "pass"
|
|
1301
|
+
})
|
|
1302
|
+
request.include_proxy_authorization_header
|
|
1303
|
+
|
|
1304
|
+
assert_equal request.proxy_authorization_header, request.headers["Proxy-Authorization"]
|
|
1305
|
+
end
|
|
1306
|
+
|
|
1307
|
+
# #proxy_authorization_header
|
|
1308
|
+
|
|
1309
|
+
def test_proxy_authorization_header_returns_basic_auth_header
|
|
1310
|
+
request = build_request(proxy: {
|
|
1311
|
+
proxy_address: "proxy.example.com",
|
|
1312
|
+
proxy_port: 8080,
|
|
1313
|
+
proxy_username: "user",
|
|
1314
|
+
proxy_password: "pass"
|
|
1315
|
+
})
|
|
1316
|
+
|
|
1317
|
+
assert request.proxy_authorization_header.start_with?("Basic ")
|
|
1318
|
+
end
|
|
1319
|
+
|
|
1320
|
+
def test_proxy_authorization_header_encodes_username_and_password
|
|
1321
|
+
request = build_request(proxy: {
|
|
1322
|
+
proxy_address: "proxy.example.com",
|
|
1323
|
+
proxy_port: 8080,
|
|
1324
|
+
proxy_username: "user",
|
|
1325
|
+
proxy_password: "pass"
|
|
1326
|
+
})
|
|
1327
|
+
expected_digest = ["user:pass"].pack("m0")
|
|
1328
|
+
|
|
1329
|
+
assert_equal "Basic #{expected_digest}", request.proxy_authorization_header
|
|
1330
|
+
end
|
|
1331
|
+
|
|
1332
|
+
# #inspect
|
|
1333
|
+
|
|
1334
|
+
def test_inspect_returns_a_useful_string_representation
|
|
1335
|
+
request_uri = "http://example.com/foo?bar=baz"
|
|
1336
|
+
|
|
1337
|
+
assert_equal "#<HTTP::Request/1.1 GET #{request_uri}>", build_request(uri: request_uri).inspect
|
|
1338
|
+
end
|
|
1339
|
+
|
|
1340
|
+
def test_inspect_includes_the_class_name
|
|
1341
|
+
assert_includes build_request.inspect, "HTTP::Request"
|
|
1342
|
+
end
|
|
1343
|
+
|
|
1344
|
+
def test_inspect_includes_the_version
|
|
1345
|
+
assert_includes build_request.inspect, "1.1"
|
|
1346
|
+
end
|
|
1347
|
+
|
|
1348
|
+
def test_inspect_includes_the_uppercased_verb
|
|
1349
|
+
assert_includes build_request.inspect, "GET"
|
|
1350
|
+
end
|
|
1351
|
+
|
|
1352
|
+
def test_inspect_includes_the_uri
|
|
1353
|
+
request_uri = "http://example.com/foo?bar=baz"
|
|
1354
|
+
|
|
1355
|
+
assert_includes build_request(uri: request_uri).inspect, request_uri
|
|
1356
|
+
end
|
|
1357
|
+
|
|
1358
|
+
def test_inspect_with_post_verb_shows_post
|
|
1359
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/")
|
|
1360
|
+
|
|
1361
|
+
assert_includes req.inspect, "POST"
|
|
1362
|
+
end
|
|
1363
|
+
|
|
1364
|
+
def test_inspect_works_when_verb_is_a_symbol
|
|
1365
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/")
|
|
1366
|
+
|
|
1367
|
+
assert_includes req.inspect, "GET"
|
|
1368
|
+
assert_equal "#<HTTP::Request/1.1 GET http://example.com/>", req.inspect
|
|
1369
|
+
end
|
|
1370
|
+
|
|
1371
|
+
# #port (private)
|
|
1372
|
+
|
|
1373
|
+
def test_port_returns_the_default_port_when_uri_has_no_explicit_port
|
|
1374
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/")
|
|
1375
|
+
|
|
1376
|
+
assert_equal 80, req.socket_port
|
|
1377
|
+
end
|
|
1378
|
+
|
|
1379
|
+
def test_port_returns_the_explicit_port_when_uri_specifies_one
|
|
1380
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com:9292/")
|
|
1381
|
+
|
|
1382
|
+
assert_equal 9292, req.socket_port
|
|
1383
|
+
end
|
|
1384
|
+
|
|
1385
|
+
def test_port_returns_https_default_port
|
|
1386
|
+
req = HTTP::Request.new(verb: :get, uri: "https://example.com/")
|
|
1387
|
+
|
|
1388
|
+
assert_equal 443, req.socket_port
|
|
1389
|
+
end
|
|
1390
|
+
|
|
1391
|
+
def test_port_returns_ws_default_port
|
|
1392
|
+
req = HTTP::Request.new(verb: :get, uri: "ws://example.com/")
|
|
1393
|
+
|
|
1394
|
+
assert_equal 80, req.socket_port
|
|
1395
|
+
end
|
|
1396
|
+
|
|
1397
|
+
def test_port_returns_wss_default_port
|
|
1398
|
+
req = HTTP::Request.new(verb: :get, uri: "wss://example.com/")
|
|
1399
|
+
|
|
1400
|
+
assert_equal 443, req.socket_port
|
|
1401
|
+
end
|
|
1402
|
+
|
|
1403
|
+
# #default_host_header_value (private)
|
|
1404
|
+
|
|
1405
|
+
def test_default_host_header_value_omits_port_for_standard_http
|
|
1406
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/")
|
|
1407
|
+
|
|
1408
|
+
assert_equal "example.com", req.headers["Host"]
|
|
1409
|
+
end
|
|
1410
|
+
|
|
1411
|
+
def test_default_host_header_value_omits_port_for_standard_ws
|
|
1412
|
+
req = HTTP::Request.new(verb: :get, uri: "ws://example.com/")
|
|
1413
|
+
|
|
1414
|
+
assert_equal "example.com", req.headers["Host"]
|
|
1415
|
+
end
|
|
1416
|
+
|
|
1417
|
+
def test_default_host_header_value_omits_port_for_standard_wss
|
|
1418
|
+
req = HTTP::Request.new(verb: :get, uri: "wss://example.com/")
|
|
1419
|
+
|
|
1420
|
+
assert_equal "example.com", req.headers["Host"]
|
|
1421
|
+
end
|
|
1422
|
+
|
|
1423
|
+
def test_default_host_header_value_includes_port_for_non_standard_ws
|
|
1424
|
+
req = HTTP::Request.new(verb: :get, uri: "ws://example.com:8080/")
|
|
1425
|
+
|
|
1426
|
+
assert_equal "example.com:8080", req.headers["Host"]
|
|
1427
|
+
end
|
|
1428
|
+
|
|
1429
|
+
# #parse_uri! (private)
|
|
1430
|
+
|
|
1431
|
+
def test_parse_uri_raises_argument_error_for_empty_string_subclass
|
|
1432
|
+
string_subclass = Class.new(String)
|
|
1433
|
+
err = assert_raises(ArgumentError) do
|
|
1434
|
+
HTTP::Request.new(verb: :get, uri: string_subclass.new(""))
|
|
1435
|
+
end
|
|
1436
|
+
assert_equal "uri is empty", err.message
|
|
1437
|
+
end
|
|
1438
|
+
|
|
1439
|
+
def test_parse_uri_normalizes_uppercase_scheme_to_lowercase_symbol
|
|
1440
|
+
req = HTTP::Request.new(verb: :get, uri: "HTTP://example.com/")
|
|
1441
|
+
|
|
1442
|
+
assert_equal :http, req.scheme
|
|
1443
|
+
end
|
|
1444
|
+
|
|
1445
|
+
def test_parse_uri_normalizes_mixed_case_scheme
|
|
1446
|
+
req = HTTP::Request.new(verb: :get, uri: "HtTpS://example.com/")
|
|
1447
|
+
|
|
1448
|
+
assert_equal :https, req.scheme
|
|
1449
|
+
end
|
|
1450
|
+
|
|
1451
|
+
# #prepare_headers (private)
|
|
1452
|
+
|
|
1453
|
+
def test_prepare_headers_sets_default_host_and_user_agent_when_headers_nil
|
|
1454
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/")
|
|
1455
|
+
|
|
1456
|
+
assert_equal "example.com", req.headers["Host"]
|
|
1457
|
+
assert_equal HTTP::Request::USER_AGENT, req.headers["User-Agent"]
|
|
1458
|
+
end
|
|
1459
|
+
|
|
1460
|
+
# #prepare_body (private)
|
|
1461
|
+
|
|
1462
|
+
def test_prepare_body_wraps_a_string_body_in_request_body
|
|
1463
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/", body: "test")
|
|
1464
|
+
|
|
1465
|
+
assert_instance_of HTTP::Request::Body, req.body
|
|
1466
|
+
assert_equal "test", req.body.source
|
|
1467
|
+
end
|
|
1468
|
+
|
|
1469
|
+
# #validate_method_and_scheme! (private)
|
|
1470
|
+
|
|
1471
|
+
def test_validate_method_and_scheme_raises_http_uri_invalid_error_for_missing_scheme
|
|
1472
|
+
err = assert_raises(HTTP::URI::InvalidError) do
|
|
1473
|
+
HTTP::Request.new(verb: :get, uri: "example.com/")
|
|
1474
|
+
end
|
|
1475
|
+
assert_kind_of HTTP::URI::InvalidError, err
|
|
1476
|
+
end
|
|
1477
|
+
|
|
1478
|
+
# #redirect (additional mutation killing tests)
|
|
1479
|
+
|
|
1480
|
+
def test_redirect_post_to_get_sets_body_source_to_nil
|
|
1481
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/", body: "data")
|
|
1482
|
+
redir = req.redirect("http://other.com/", :get)
|
|
1483
|
+
|
|
1484
|
+
assert_nil redir.body.source
|
|
1485
|
+
end
|
|
1486
|
+
|
|
1487
|
+
def test_redirect_post_to_post_preserves_body_source
|
|
1488
|
+
req = HTTP::Request.new(verb: :post, uri: "http://example.com/", body: "data")
|
|
1489
|
+
redir = req.redirect("http://other.com/", :post)
|
|
1490
|
+
|
|
1491
|
+
assert_equal "data", redir.body.source
|
|
1492
|
+
end
|
|
1493
|
+
|
|
1494
|
+
# #redirect_headers (private)
|
|
1495
|
+
|
|
1496
|
+
def test_redirect_headers_include_original_non_stripped_headers
|
|
1497
|
+
req = HTTP::Request.new(
|
|
1498
|
+
verb: :post,
|
|
1499
|
+
uri: "http://example.com/",
|
|
1500
|
+
headers: { accept: "text/html", "X-Custom" => "val" }
|
|
1501
|
+
)
|
|
1502
|
+
redir = req.redirect("/other")
|
|
1503
|
+
|
|
1504
|
+
assert_equal "text/html", redir.headers["Accept"]
|
|
1505
|
+
assert_equal "val", redir.headers["X-Custom"]
|
|
1506
|
+
end
|
|
1507
|
+
|
|
1508
|
+
# #headline (additional mutation killing tests)
|
|
1509
|
+
|
|
1510
|
+
def test_headline_returns_a_string
|
|
1511
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/path")
|
|
1512
|
+
headline = req.headline
|
|
1513
|
+
|
|
1514
|
+
assert_instance_of String, headline
|
|
1515
|
+
assert_equal "GET /path HTTP/1.1", headline
|
|
1516
|
+
end
|
|
1517
|
+
|
|
1518
|
+
def test_headline_converts_symbol_verb_to_uppercase_string
|
|
1519
|
+
req = HTTP::Request.new(verb: :delete, uri: "http://example.com/")
|
|
1520
|
+
|
|
1521
|
+
assert_equal "DELETE / HTTP/1.1", req.headline
|
|
1522
|
+
end
|
|
1523
|
+
|
|
1524
|
+
# #initialize (additional mutation killing tests)
|
|
1525
|
+
|
|
1526
|
+
def test_initialize_uses_http_uri_normalizer_by_default
|
|
1527
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/")
|
|
1528
|
+
|
|
1529
|
+
assert_equal HTTP::URI::NORMALIZER, req.uri_normalizer
|
|
1530
|
+
end
|
|
1531
|
+
|
|
1532
|
+
def test_initialize_converts_string_verb_via_to_s_before_downcase
|
|
1533
|
+
req = HTTP::Request.new(verb: "GET", uri: "http://example.com/")
|
|
1534
|
+
|
|
1535
|
+
assert_equal :get, req.verb
|
|
1536
|
+
end
|
|
1537
|
+
|
|
1538
|
+
# #stream (additional mutation killing tests)
|
|
1539
|
+
|
|
1540
|
+
def test_stream_creates_a_writer_and_streams_to_socket
|
|
1541
|
+
io = StringIO.new
|
|
1542
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/path")
|
|
1543
|
+
req.stream(io)
|
|
1544
|
+
|
|
1545
|
+
assert_match(%r{^GET /path HTTP/1\.1\r\n}, io.string)
|
|
1546
|
+
assert_includes io.string, "Host: example.com"
|
|
1547
|
+
end
|
|
1548
|
+
|
|
1549
|
+
# #socket_host (additional mutation killing tests)
|
|
1550
|
+
|
|
1551
|
+
def test_socket_host_with_proxy_that_has_proxy_address_returns_value
|
|
1552
|
+
request = build_request(proxy: { proxy_address: "myproxy.com", proxy_port: 3128 })
|
|
1553
|
+
|
|
1554
|
+
assert_equal "myproxy.com", request.socket_host
|
|
1555
|
+
end
|
|
1556
|
+
|
|
1557
|
+
# #socket_port (additional mutation killing tests)
|
|
1558
|
+
|
|
1559
|
+
def test_socket_port_with_proxy_that_has_proxy_port_returns_value
|
|
1560
|
+
request = build_request(proxy: { proxy_address: "myproxy.com", proxy_port: 3128 })
|
|
1561
|
+
|
|
1562
|
+
assert_equal 3128, request.socket_port
|
|
1563
|
+
end
|
|
1564
|
+
|
|
1565
|
+
# #using_proxy? (additional mutation killing tests)
|
|
1566
|
+
|
|
1567
|
+
def test_using_proxy_with_nil_proxy_returns_false
|
|
1568
|
+
req = HTTP::Request.new(verb: :get, uri: "http://example.com/", proxy: {})
|
|
1569
|
+
|
|
1570
|
+
refute_predicate req, :using_proxy?
|
|
1571
|
+
end
|
|
1572
|
+
|
|
1573
|
+
def test_using_proxy_with_exactly_two_keys_returns_true
|
|
1574
|
+
request = build_request(proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 })
|
|
1575
|
+
|
|
1576
|
+
assert_predicate request, :using_proxy?
|
|
1577
|
+
end
|
|
1578
|
+
|
|
1579
|
+
def test_using_proxy_with_three_keys_returns_true
|
|
1580
|
+
request = build_request(proxy: { proxy_address: "proxy.example.com", proxy_port: 8080, extra: "x" })
|
|
1581
|
+
|
|
1582
|
+
assert_predicate request, :using_proxy?
|
|
1583
|
+
end
|
|
1584
|
+
|
|
1585
|
+
# #using_authenticated_proxy? (additional mutation killing tests)
|
|
1586
|
+
|
|
1587
|
+
def test_using_authenticated_proxy_with_exactly_four_keys_returns_true
|
|
1588
|
+
proxy = { proxy_address: "proxy.example.com", proxy_port: 8080,
|
|
1589
|
+
proxy_username: "user", proxy_password: "pass" }
|
|
1590
|
+
request = build_request(proxy: proxy)
|
|
1591
|
+
|
|
1592
|
+
assert_predicate request, :using_authenticated_proxy?
|
|
1593
|
+
end
|
|
1594
|
+
|
|
1595
|
+
def test_using_authenticated_proxy_with_five_keys_returns_true
|
|
1596
|
+
proxy = { proxy_address: "proxy.example.com", proxy_port: 8080,
|
|
1597
|
+
proxy_username: "user", proxy_password: "pass", extra: "x" }
|
|
1598
|
+
request = build_request(proxy: proxy)
|
|
1599
|
+
|
|
1600
|
+
assert_predicate request, :using_authenticated_proxy?
|
|
1601
|
+
end
|
|
1602
|
+
|
|
1603
|
+
# #include_proxy_headers (additional mutation killing tests)
|
|
1604
|
+
|
|
1605
|
+
def test_include_proxy_headers_authenticated_no_proxy_headers_key_does_not_merge_nil
|
|
1606
|
+
request = build_request(proxy: {
|
|
1607
|
+
proxy_address: "proxy.example.com",
|
|
1608
|
+
proxy_port: 8080,
|
|
1609
|
+
proxy_username: "user",
|
|
1610
|
+
proxy_password: "pass"
|
|
1611
|
+
})
|
|
1612
|
+
header_count_before = request.headers.to_h.except("Proxy-Authorization").size
|
|
1613
|
+
request.include_proxy_headers
|
|
1614
|
+
header_count_after = request.headers.to_h.except("Proxy-Authorization").size
|
|
1615
|
+
|
|
1616
|
+
assert_equal header_count_before, header_count_after
|
|
1617
|
+
end
|
|
1618
|
+
|
|
1619
|
+
def test_include_proxy_headers_authenticated_no_proxy_headers_key_does_not_raise
|
|
1620
|
+
request = build_request(proxy: {
|
|
1621
|
+
proxy_address: "proxy.example.com",
|
|
1622
|
+
proxy_port: 8080,
|
|
1623
|
+
proxy_username: "user",
|
|
1624
|
+
proxy_password: "pass"
|
|
1625
|
+
})
|
|
1626
|
+
request.include_proxy_headers
|
|
1627
|
+
|
|
1628
|
+
assert_match(/^Basic /, request.headers["Proxy-Authorization"])
|
|
1629
|
+
end
|
|
1630
|
+
|
|
1631
|
+
# #proxy_authorization_header (additional mutation killing tests)
|
|
1632
|
+
|
|
1633
|
+
def test_proxy_authorization_header_encodes_correct_username_and_password
|
|
1634
|
+
request = build_request(proxy: {
|
|
1635
|
+
proxy_address: "proxy.example.com",
|
|
1636
|
+
proxy_port: 8080,
|
|
1637
|
+
proxy_username: "alice",
|
|
1638
|
+
proxy_password: "secret"
|
|
1639
|
+
})
|
|
1640
|
+
expected = "Basic #{['alice:secret'].pack('m0')}"
|
|
1641
|
+
|
|
1642
|
+
assert_equal expected, request.proxy_authorization_header
|
|
1643
|
+
end
|
|
1644
|
+
|
|
1645
|
+
# #proxy_connect_headers (additional mutation killing tests)
|
|
1646
|
+
|
|
1647
|
+
def test_proxy_connect_headers_authenticated_no_proxy_headers_returns_http_headers
|
|
1648
|
+
request = build_request(
|
|
1649
|
+
uri: "https://example.com/",
|
|
1650
|
+
proxy: {
|
|
1651
|
+
proxy_address: "proxy.example.com",
|
|
1652
|
+
proxy_port: 8080,
|
|
1653
|
+
proxy_username: "user",
|
|
1654
|
+
proxy_password: "pass"
|
|
1655
|
+
}
|
|
1656
|
+
)
|
|
1657
|
+
hdrs = request.proxy_connect_headers
|
|
1658
|
+
|
|
1659
|
+
assert_instance_of HTTP::Headers, hdrs
|
|
1660
|
+
end
|
|
1661
|
+
|
|
1662
|
+
def test_proxy_connect_headers_authenticated_no_proxy_headers_does_not_include_nil
|
|
1663
|
+
request = build_request(
|
|
1664
|
+
uri: "https://example.com/",
|
|
1665
|
+
proxy: {
|
|
1666
|
+
proxy_address: "proxy.example.com",
|
|
1667
|
+
proxy_port: 8080,
|
|
1668
|
+
proxy_username: "user",
|
|
1669
|
+
proxy_password: "pass"
|
|
1670
|
+
}
|
|
1671
|
+
)
|
|
1672
|
+
hdrs = request.proxy_connect_headers
|
|
1673
|
+
|
|
1674
|
+
assert_equal %w[Host User-Agent Proxy-Authorization], hdrs.keys
|
|
1675
|
+
end
|
|
1676
|
+
|
|
1677
|
+
def test_proxy_connect_headers_unauthenticated_with_proxy_headers_includes_custom
|
|
1678
|
+
request = build_request(
|
|
1679
|
+
uri: "https://example.com/",
|
|
1680
|
+
proxy: {
|
|
1681
|
+
proxy_address: "proxy.example.com",
|
|
1682
|
+
proxy_port: 8080,
|
|
1683
|
+
proxy_headers: { "X-Custom" => "val" }
|
|
1684
|
+
}
|
|
1685
|
+
)
|
|
1686
|
+
hdrs = request.proxy_connect_headers
|
|
1687
|
+
|
|
1688
|
+
assert_equal "val", hdrs["X-Custom"]
|
|
1689
|
+
end
|
|
1690
|
+
|
|
1691
|
+
def test_proxy_connect_headers_unauthenticated_with_proxy_headers_includes_host
|
|
1692
|
+
request = build_request(
|
|
1693
|
+
uri: "https://example.com/",
|
|
1694
|
+
proxy: {
|
|
1695
|
+
proxy_address: "proxy.example.com",
|
|
1696
|
+
proxy_port: 8080,
|
|
1697
|
+
proxy_headers: { "X-Custom" => "val" }
|
|
1698
|
+
}
|
|
1699
|
+
)
|
|
1700
|
+
hdrs = request.proxy_connect_headers
|
|
1701
|
+
|
|
1702
|
+
assert_equal "example.com", hdrs["Host"]
|
|
1703
|
+
end
|
|
1704
|
+
|
|
1705
|
+
def test_proxy_connect_headers_unauthenticated_no_proxy_headers_does_not_raise
|
|
1706
|
+
request = build_request(
|
|
1707
|
+
uri: "https://example.com/",
|
|
1708
|
+
proxy: { proxy_address: "proxy.example.com", proxy_port: 8080 }
|
|
1709
|
+
)
|
|
1710
|
+
hdrs = request.proxy_connect_headers
|
|
1711
|
+
|
|
1712
|
+
assert_instance_of HTTP::Headers, hdrs
|
|
1713
|
+
assert_equal %w[Host User-Agent], hdrs.keys
|
|
1714
|
+
end
|
|
1715
|
+
|
|
1716
|
+
# #connect_using_proxy (additional mutation killing tests)
|
|
1717
|
+
|
|
1718
|
+
def test_connect_using_proxy_writes_valid_connect_request_line
|
|
1719
|
+
io = StringIO.new
|
|
1720
|
+
request = build_request(
|
|
1721
|
+
uri: "https://example.com:8443/foo",
|
|
1722
|
+
proxy: {
|
|
1723
|
+
proxy_address: "proxy.example.com",
|
|
1724
|
+
proxy_port: 8080,
|
|
1725
|
+
proxy_username: "user",
|
|
1726
|
+
proxy_password: "pass"
|
|
1727
|
+
}
|
|
1728
|
+
)
|
|
1729
|
+
request.connect_using_proxy(io)
|
|
1730
|
+
|
|
1731
|
+
assert_match(%r{^CONNECT example\.com:8443 HTTP/1\.1\r\n}, io.string)
|
|
1732
|
+
end
|
|
1733
|
+
end
|