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,77 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe HTTP::Features::AutoDeflate do
|
|
4
|
-
subject { HTTP::Features::AutoDeflate.new }
|
|
5
|
-
|
|
6
|
-
it "raises error for wrong type" do
|
|
7
|
-
expect { HTTP::Features::AutoDeflate.new(:method => :wrong) }.
|
|
8
|
-
to raise_error(HTTP::Error) { |error|
|
|
9
|
-
expect(error.message).to eq("Only gzip and deflate methods are supported")
|
|
10
|
-
}
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "accepts gzip method" do
|
|
14
|
-
expect(HTTP::Features::AutoDeflate.new(:method => :gzip).method).to eq "gzip"
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it "accepts deflate method" do
|
|
18
|
-
expect(HTTP::Features::AutoDeflate.new(:method => :deflate).method).to eq "deflate"
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
it "accepts string as method" do
|
|
22
|
-
expect(HTTP::Features::AutoDeflate.new(:method => "gzip").method).to eq "gzip"
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "uses gzip by default" do
|
|
26
|
-
expect(subject.method).to eq("gzip")
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
describe "#deflated_body" do
|
|
30
|
-
let(:body) { %w[bees cows] }
|
|
31
|
-
let(:deflated_body) { subject.deflated_body(body) }
|
|
32
|
-
|
|
33
|
-
context "when method is gzip" do
|
|
34
|
-
subject { HTTP::Features::AutoDeflate.new(:method => :gzip) }
|
|
35
|
-
|
|
36
|
-
it "returns object which yields gzipped content of the given body" do
|
|
37
|
-
io = StringIO.new
|
|
38
|
-
io.set_encoding(Encoding::BINARY)
|
|
39
|
-
gzip = Zlib::GzipWriter.new(io)
|
|
40
|
-
gzip.write("beescows")
|
|
41
|
-
gzip.close
|
|
42
|
-
gzipped = io.string
|
|
43
|
-
|
|
44
|
-
expect(deflated_body.each.to_a.join).to eq gzipped
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
it "caches compressed content when size is called" do
|
|
48
|
-
io = StringIO.new
|
|
49
|
-
io.set_encoding(Encoding::BINARY)
|
|
50
|
-
gzip = Zlib::GzipWriter.new(io)
|
|
51
|
-
gzip.write("beescows")
|
|
52
|
-
gzip.close
|
|
53
|
-
gzipped = io.string
|
|
54
|
-
|
|
55
|
-
expect(deflated_body.size).to eq gzipped.bytesize
|
|
56
|
-
expect(deflated_body.each.to_a.join).to eq gzipped
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
context "when method is deflate" do
|
|
61
|
-
subject { HTTP::Features::AutoDeflate.new(:method => :deflate) }
|
|
62
|
-
|
|
63
|
-
it "returns object which yields deflated content of the given body" do
|
|
64
|
-
deflated = Zlib::Deflate.deflate("beescows")
|
|
65
|
-
|
|
66
|
-
expect(deflated_body.each.to_a.join).to eq deflated
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
it "caches compressed content when size is called" do
|
|
70
|
-
deflated = Zlib::Deflate.deflate("beescows")
|
|
71
|
-
|
|
72
|
-
expect(deflated_body.size).to eq deflated.bytesize
|
|
73
|
-
expect(deflated_body.each.to_a.join).to eq deflated
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe HTTP::Features::AutoInflate do
|
|
4
|
-
subject(:feature) { HTTP::Features::AutoInflate.new }
|
|
5
|
-
|
|
6
|
-
let(:connection) { double }
|
|
7
|
-
let(:headers) { {} }
|
|
8
|
-
|
|
9
|
-
let(:response) do
|
|
10
|
-
HTTP::Response.new(
|
|
11
|
-
:version => "1.1",
|
|
12
|
-
:status => 200,
|
|
13
|
-
:headers => headers,
|
|
14
|
-
:connection => connection,
|
|
15
|
-
:request => HTTP::Request.new(:verb => :get, :uri => "http://example.com")
|
|
16
|
-
)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
describe "#wrap_response" do
|
|
20
|
-
subject(:result) { feature.wrap_response(response) }
|
|
21
|
-
|
|
22
|
-
context "when there is no Content-Encoding header" do
|
|
23
|
-
it "returns original request" do
|
|
24
|
-
expect(result).to be response
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
context "for identity Content-Encoding header" do
|
|
29
|
-
let(:headers) { {:content_encoding => "identity"} }
|
|
30
|
-
|
|
31
|
-
it "returns original request" do
|
|
32
|
-
expect(result).to be response
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
context "for unknown Content-Encoding header" do
|
|
37
|
-
let(:headers) { {:content_encoding => "not-supported"} }
|
|
38
|
-
|
|
39
|
-
it "returns original request" do
|
|
40
|
-
expect(result).to be response
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
context "for deflate Content-Encoding header" do
|
|
45
|
-
let(:headers) { {:content_encoding => "deflate"} }
|
|
46
|
-
|
|
47
|
-
it "returns a HTTP::Response wrapping the inflated response body" do
|
|
48
|
-
expect(result.body).to be_instance_of HTTP::Response::Body
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
context "for gzip Content-Encoding header" do
|
|
53
|
-
let(:headers) { {:content_encoding => "gzip"} }
|
|
54
|
-
|
|
55
|
-
it "returns a HTTP::Response wrapping the inflated response body" do
|
|
56
|
-
expect(result.body).to be_instance_of HTTP::Response::Body
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
context "for x-gzip Content-Encoding header" do
|
|
61
|
-
let(:headers) { {:content_encoding => "x-gzip"} }
|
|
62
|
-
|
|
63
|
-
it "returns a HTTP::Response wrapping the inflated response body" do
|
|
64
|
-
expect(result.body).to be_instance_of HTTP::Response::Body
|
|
65
|
-
end
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
# TODO(ixti): We should refactor API to either make uri non-optional,
|
|
69
|
-
# or add reference to request into response object (better).
|
|
70
|
-
context "when response has uri" do
|
|
71
|
-
let(:response) do
|
|
72
|
-
HTTP::Response.new(
|
|
73
|
-
:version => "1.1",
|
|
74
|
-
:status => 200,
|
|
75
|
-
:headers => {:content_encoding => "gzip"},
|
|
76
|
-
:connection => connection,
|
|
77
|
-
:request => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
|
|
78
|
-
)
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it "preserves uri in wrapped response" do
|
|
82
|
-
expect(result.uri).to eq HTTP::URI.parse("https://example.com")
|
|
83
|
-
end
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
end
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe HTTP::Features::Instrumentation do
|
|
4
|
-
subject(:feature) { HTTP::Features::Instrumentation.new(:instrumenter => instrumenter) }
|
|
5
|
-
|
|
6
|
-
let(:instrumenter) { TestInstrumenter.new }
|
|
7
|
-
|
|
8
|
-
before do
|
|
9
|
-
test_instrumenter = Class.new(HTTP::Features::Instrumentation::NullInstrumenter) do
|
|
10
|
-
attr_reader :output
|
|
11
|
-
|
|
12
|
-
def initialize
|
|
13
|
-
@output = {}
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
def start(_name, payload)
|
|
17
|
-
output[:start] = payload
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def finish(_name, payload)
|
|
21
|
-
output[:finish] = payload
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
stub_const("TestInstrumenter", test_instrumenter)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
describe "logging the request" do
|
|
29
|
-
let(:request) do
|
|
30
|
-
HTTP::Request.new(
|
|
31
|
-
:verb => :post,
|
|
32
|
-
:uri => "https://example.com/",
|
|
33
|
-
:headers => {:accept => "application/json"},
|
|
34
|
-
:body => '{"hello": "world!"}'
|
|
35
|
-
)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it "should log the request" do
|
|
39
|
-
feature.wrap_request(request)
|
|
40
|
-
|
|
41
|
-
expect(instrumenter.output[:start]).to eq(:request => request)
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
describe "logging the response" do
|
|
46
|
-
let(:response) do
|
|
47
|
-
HTTP::Response.new(
|
|
48
|
-
:version => "1.1",
|
|
49
|
-
:status => 200,
|
|
50
|
-
:headers => {:content_type => "application/json"},
|
|
51
|
-
:body => '{"success": true}',
|
|
52
|
-
:request => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
|
|
53
|
-
)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
it "should log the response" do
|
|
57
|
-
feature.wrap_response(response)
|
|
58
|
-
|
|
59
|
-
expect(instrumenter.output[:finish]).to eq(:response => response)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
describe "logging errors" do
|
|
64
|
-
let(:request) do
|
|
65
|
-
HTTP::Request.new(
|
|
66
|
-
:verb => :post,
|
|
67
|
-
:uri => "https://example.com/",
|
|
68
|
-
:headers => {:accept => "application/json"},
|
|
69
|
-
:body => '{"hello": "world!"}'
|
|
70
|
-
)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
let(:error) { HTTP::TimeoutError.new }
|
|
74
|
-
|
|
75
|
-
it "should log the error" do
|
|
76
|
-
feature.on_error(request, error)
|
|
77
|
-
|
|
78
|
-
expect(instrumenter.output[:finish]).to eq(:request => request, :error => error)
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "logger"
|
|
4
|
-
|
|
5
|
-
RSpec.describe HTTP::Features::Logging do
|
|
6
|
-
subject(:feature) do
|
|
7
|
-
logger = Logger.new(logdev)
|
|
8
|
-
logger.formatter = ->(severity, _, _, message) { format("** %s **\n%s\n", severity, message) }
|
|
9
|
-
|
|
10
|
-
described_class.new(:logger => logger)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
let(:logdev) { StringIO.new }
|
|
14
|
-
|
|
15
|
-
describe "logging the request" do
|
|
16
|
-
let(:request) do
|
|
17
|
-
HTTP::Request.new(
|
|
18
|
-
:verb => :post,
|
|
19
|
-
:uri => "https://example.com/",
|
|
20
|
-
:headers => {:accept => "application/json"},
|
|
21
|
-
:body => '{"hello": "world!"}'
|
|
22
|
-
)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "should log the request" do
|
|
26
|
-
feature.wrap_request(request)
|
|
27
|
-
|
|
28
|
-
expect(logdev.string).to eq <<~OUTPUT
|
|
29
|
-
** INFO **
|
|
30
|
-
> POST https://example.com/
|
|
31
|
-
** DEBUG **
|
|
32
|
-
Accept: application/json
|
|
33
|
-
Host: example.com
|
|
34
|
-
User-Agent: http.rb/#{HTTP::VERSION}
|
|
35
|
-
|
|
36
|
-
{"hello": "world!"}
|
|
37
|
-
OUTPUT
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
describe "logging the response" do
|
|
42
|
-
let(:response) do
|
|
43
|
-
HTTP::Response.new(
|
|
44
|
-
:version => "1.1",
|
|
45
|
-
:status => 200,
|
|
46
|
-
:headers => {:content_type => "application/json"},
|
|
47
|
-
:body => '{"success": true}',
|
|
48
|
-
:request => HTTP::Request.new(:verb => :get, :uri => "https://example.com")
|
|
49
|
-
)
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
it "should log the response" do
|
|
53
|
-
feature.wrap_response(response)
|
|
54
|
-
|
|
55
|
-
expect(logdev.string).to eq <<~OUTPUT
|
|
56
|
-
** INFO **
|
|
57
|
-
< 200 OK
|
|
58
|
-
** DEBUG **
|
|
59
|
-
Content-Type: application/json
|
|
60
|
-
|
|
61
|
-
{"success": true}
|
|
62
|
-
OUTPUT
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
@@ -1,62 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe HTTP::Features::RaiseError do
|
|
4
|
-
subject(:feature) { described_class.new(ignore: ignore) }
|
|
5
|
-
|
|
6
|
-
let(:connection) { double }
|
|
7
|
-
let(:status) { 200 }
|
|
8
|
-
let(:ignore) { [] }
|
|
9
|
-
|
|
10
|
-
describe "#wrap_response" do
|
|
11
|
-
subject(:result) { feature.wrap_response(response) }
|
|
12
|
-
|
|
13
|
-
let(:response) do
|
|
14
|
-
HTTP::Response.new(
|
|
15
|
-
version: "1.1",
|
|
16
|
-
status: status,
|
|
17
|
-
headers: {},
|
|
18
|
-
connection: connection,
|
|
19
|
-
request: HTTP::Request.new(verb: :get, uri: "https://example.com")
|
|
20
|
-
)
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
context "when status is 200" do
|
|
24
|
-
it "returns original request" do
|
|
25
|
-
expect(result).to be response
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
context "when status is 399" do
|
|
30
|
-
let(:status) { 399 }
|
|
31
|
-
|
|
32
|
-
it "returns original request" do
|
|
33
|
-
expect(result).to be response
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
context "when status is 400" do
|
|
38
|
-
let(:status) { 400 }
|
|
39
|
-
|
|
40
|
-
it "raises" do
|
|
41
|
-
expect { result }.to raise_error(HTTP::StatusError, "Unexpected status code 400")
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
context "when status is 599" do
|
|
46
|
-
let(:status) { 599 }
|
|
47
|
-
|
|
48
|
-
it "raises" do
|
|
49
|
-
expect { result }.to raise_error(HTTP::StatusError, "Unexpected status code 599")
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
context "when error status is ignored" do
|
|
54
|
-
let(:status) { 500 }
|
|
55
|
-
let(:ignore) { [500] }
|
|
56
|
-
|
|
57
|
-
it "returns original request" do
|
|
58
|
-
expect(result).to be response
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe HTTP::Headers::Mixin do
|
|
4
|
-
let :dummy_class do
|
|
5
|
-
Class.new do
|
|
6
|
-
include HTTP::Headers::Mixin
|
|
7
|
-
|
|
8
|
-
def initialize(headers)
|
|
9
|
-
@headers = headers
|
|
10
|
-
end
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
let(:headers) { HTTP::Headers.new }
|
|
15
|
-
let(:dummy) { dummy_class.new headers }
|
|
16
|
-
|
|
17
|
-
describe "#headers" do
|
|
18
|
-
it "returns @headers instance variable" do
|
|
19
|
-
expect(dummy.headers).to be headers
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
describe "#[]" do
|
|
24
|
-
it "proxies to headers#[]" do
|
|
25
|
-
expect(headers).to receive(:[]).with(:accept)
|
|
26
|
-
dummy[:accept]
|
|
27
|
-
end
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
describe "#[]=" do
|
|
31
|
-
it "proxies to headers#[]" do
|
|
32
|
-
expect(headers).to receive(:[]=).with(:accept, "text/plain")
|
|
33
|
-
dummy[:accept] = "text/plain"
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
RSpec.describe HTTP::Headers::Normalizer do
|
|
4
|
-
subject(:normalizer) { described_class.new }
|
|
5
|
-
|
|
6
|
-
include_context RSpec::Memory
|
|
7
|
-
|
|
8
|
-
describe "#call" do
|
|
9
|
-
it "normalizes the header" do
|
|
10
|
-
expect(normalizer.call("content_type")).to eq "Content-Type"
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
it "returns a non-frozen string" do
|
|
14
|
-
expect(normalizer.call("content_type")).not_to be_frozen
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it "evicts the oldest item when cache is full" do
|
|
18
|
-
max_headers = (1..described_class::Cache::MAX_SIZE).map { |i| "Header#{i}" }
|
|
19
|
-
max_headers.each { |header| normalizer.call(header) }
|
|
20
|
-
normalizer.call("New-Header")
|
|
21
|
-
cache_store = normalizer.instance_variable_get(:@cache).instance_variable_get(:@store)
|
|
22
|
-
expect(cache_store.keys).to eq(max_headers[1..] + ["New-Header"])
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "retuns mutable strings" do
|
|
26
|
-
normalized_headers = Array.new(3) { normalizer.call("content_type") }
|
|
27
|
-
|
|
28
|
-
expect(normalized_headers)
|
|
29
|
-
.to satisfy { |arr| arr.uniq.size == 1 }
|
|
30
|
-
.and(satisfy { |arr| arr.map(&:object_id).uniq.size == normalized_headers.size })
|
|
31
|
-
.and(satisfy { |arr| arr.none?(&:frozen?) })
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
it "allocates minimal memory for normalization of the same header" do
|
|
35
|
-
normalizer.call("accept") # XXX: Ensure normalizer is pre-allocated
|
|
36
|
-
|
|
37
|
-
# On first call it is expected to allocate during normalization
|
|
38
|
-
expect { normalizer.call("content_type") }.to limit_allocations(
|
|
39
|
-
Array => 1,
|
|
40
|
-
MatchData => 1,
|
|
41
|
-
String => 6
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
# On subsequent call it is expected to only allocate copy of a cached string
|
|
45
|
-
expect { normalizer.call("content_type") }.to limit_allocations(
|
|
46
|
-
Array => 0,
|
|
47
|
-
MatchData => 0,
|
|
48
|
-
String => 1
|
|
49
|
-
)
|
|
50
|
-
end
|
|
51
|
-
end
|
|
52
|
-
end
|