http 5.0.4 → 5.1.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/.github/workflows/ci.yml +4 -4
- data/.rubocop.yml +1 -1
- data/.rubocop_todo.yml +26 -13
- data/CHANGES.md +21 -1
- data/Gemfile +1 -1
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/SECURITY.md +5 -0
- data/http.gemspec +6 -5
- data/lib/http/errors.rb +3 -0
- data/lib/http/headers.rb +1 -1
- data/lib/http/redirector.rb +49 -1
- data/lib/http/response/status.rb +1 -1
- data/lib/http/response.rb +7 -1
- data/lib/http/timeout/global.rb +1 -1
- data/lib/http/timeout/per_operation.rb +1 -1
- data/lib/http/version.rb +1 -1
- data/spec/lib/http/client_spec.rb +2 -2
- data/spec/lib/http/redirector_spec.rb +62 -3
- data/spec/lib/http/response/body_spec.rb +1 -1
- data/spec/lib/http/response_spec.rb +36 -0
- data/spec/support/http_handling_shared.rb +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3826a20981b5ed6a7e5f29fd99af814a8409dea3d556d8d4f1c1faeee0060211
|
|
4
|
+
data.tar.gz: 5f1a624d39059a53df7535df9d8094ec2eb17330ce113ee5f8201f028cb08a01
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f34965016796ff2864a48d86c45a95db18a5bd118921e9f5ab653b042d53f13332d155238b1b26d28be643b6dffea6f0bf9ac20bbc71bcab05e73e7358ca9b7d
|
|
7
|
+
data.tar.gz: dfcf6ad46848750d86cb9139b7b0ab9d4ae28624bc7c0d779450f3cfbd8de11dd6ba242855fee759210ffade294743746059157cd1eab4eb69125f644653f5e5
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -16,11 +16,11 @@ jobs:
|
|
|
16
16
|
|
|
17
17
|
strategy:
|
|
18
18
|
matrix:
|
|
19
|
-
ruby: [ ruby-2.
|
|
19
|
+
ruby: [ ruby-2.6, ruby-2.7, ruby-3.0, ruby-3.1 ]
|
|
20
20
|
os: [ ubuntu-latest ]
|
|
21
21
|
|
|
22
22
|
steps:
|
|
23
|
-
- uses: actions/checkout@
|
|
23
|
+
- uses: actions/checkout@v3
|
|
24
24
|
|
|
25
25
|
- uses: ruby/setup-ruby@v1
|
|
26
26
|
with:
|
|
@@ -52,11 +52,11 @@ jobs:
|
|
|
52
52
|
runs-on: ubuntu-latest
|
|
53
53
|
|
|
54
54
|
steps:
|
|
55
|
-
- uses: actions/checkout@
|
|
55
|
+
- uses: actions/checkout@v3
|
|
56
56
|
|
|
57
57
|
- uses: ruby/setup-ruby@v1
|
|
58
58
|
with:
|
|
59
|
-
ruby-version: 2.
|
|
59
|
+
ruby-version: 2.6
|
|
60
60
|
bundler-cache: true
|
|
61
61
|
|
|
62
62
|
- name: bundle exec rubocop
|
data/.rubocop.yml
CHANGED
data/.rubocop_todo.yml
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
# This configuration was generated by
|
|
2
|
-
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit
|
|
3
|
-
# on
|
|
2
|
+
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 100`
|
|
3
|
+
# on 2022-06-16 14:35:44 UTC using RuboCop version 1.30.1.
|
|
4
4
|
# The point is for the user to remove these configuration records
|
|
5
5
|
# one by one as the offenses are removed from the code base.
|
|
6
6
|
# Note that changes in the inspected code, or installation of new
|
|
7
7
|
# versions of RuboCop, may require this file to be generated again.
|
|
8
8
|
|
|
9
|
+
# Offense count: 1
|
|
10
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
11
|
+
# Configuration parameters: Include.
|
|
12
|
+
# Include: **/*.gemspec
|
|
13
|
+
Gemspec/DeprecatedAttributeAssignment:
|
|
14
|
+
Exclude:
|
|
15
|
+
- 'http.gemspec'
|
|
16
|
+
|
|
9
17
|
# Offense count: 53
|
|
10
|
-
#
|
|
18
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
11
19
|
# Configuration parameters: EnforcedStyle.
|
|
12
20
|
# SupportedStyles: leading, trailing
|
|
13
21
|
Layout/DotPosition:
|
|
@@ -22,8 +30,8 @@ Layout/DotPosition:
|
|
|
22
30
|
- 'spec/lib/http_spec.rb'
|
|
23
31
|
- 'spec/support/http_handling_shared.rb'
|
|
24
32
|
|
|
25
|
-
# Offense count:
|
|
26
|
-
#
|
|
33
|
+
# Offense count: 176
|
|
34
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
27
35
|
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
|
|
28
36
|
# SupportedStyles: space, no_space, compact
|
|
29
37
|
# SupportedStylesForEmptyBraces: space, no_space
|
|
@@ -66,7 +74,7 @@ Metrics/AbcSize:
|
|
|
66
74
|
- 'lib/http/request.rb'
|
|
67
75
|
- 'lib/http/response.rb'
|
|
68
76
|
|
|
69
|
-
# Offense count:
|
|
77
|
+
# Offense count: 69
|
|
70
78
|
# Configuration parameters: CountComments, Max, CountAsOne, ExcludedMethods, IgnoredMethods.
|
|
71
79
|
# IgnoredMethods: refine
|
|
72
80
|
Metrics/BlockLength:
|
|
@@ -109,7 +117,7 @@ Metrics/CyclomaticComplexity:
|
|
|
109
117
|
- 'lib/http/chainable.rb'
|
|
110
118
|
- 'lib/http/client.rb'
|
|
111
119
|
|
|
112
|
-
# Offense count:
|
|
120
|
+
# Offense count: 18
|
|
113
121
|
# Configuration parameters: CountComments, Max, CountAsOne, ExcludedMethods, IgnoredMethods.
|
|
114
122
|
Metrics/MethodLength:
|
|
115
123
|
Exclude:
|
|
@@ -132,8 +140,13 @@ Metrics/ModuleLength:
|
|
|
132
140
|
Exclude:
|
|
133
141
|
- 'lib/http/chainable.rb'
|
|
134
142
|
|
|
143
|
+
# Offense count: 1
|
|
144
|
+
Security/CompoundHash:
|
|
145
|
+
Exclude:
|
|
146
|
+
- 'lib/http/uri.rb'
|
|
147
|
+
|
|
135
148
|
# Offense count: 2
|
|
136
|
-
#
|
|
149
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
137
150
|
# Configuration parameters: EnforcedStyle.
|
|
138
151
|
# SupportedStyles: separated, grouped
|
|
139
152
|
Style/AccessorGrouping:
|
|
@@ -141,7 +154,7 @@ Style/AccessorGrouping:
|
|
|
141
154
|
- 'lib/http/request.rb'
|
|
142
155
|
|
|
143
156
|
# Offense count: 4
|
|
144
|
-
#
|
|
157
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
145
158
|
Style/EmptyCaseCondition:
|
|
146
159
|
Exclude:
|
|
147
160
|
- 'lib/http/client.rb'
|
|
@@ -150,7 +163,7 @@ Style/EmptyCaseCondition:
|
|
|
150
163
|
- 'lib/http/response/status.rb'
|
|
151
164
|
|
|
152
165
|
# Offense count: 5
|
|
153
|
-
#
|
|
166
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
154
167
|
Style/Encoding:
|
|
155
168
|
Exclude:
|
|
156
169
|
- 'spec/lib/http/client_spec.rb'
|
|
@@ -160,7 +173,7 @@ Style/Encoding:
|
|
|
160
173
|
- 'spec/support/dummy_server/servlet.rb'
|
|
161
174
|
|
|
162
175
|
# Offense count: 17
|
|
163
|
-
# Configuration parameters: SuspiciousParamNames.
|
|
176
|
+
# Configuration parameters: SuspiciousParamNames, Allowlist.
|
|
164
177
|
# SuspiciousParamNames: options, opts, args, params, parameters
|
|
165
178
|
Style/OptionHash:
|
|
166
179
|
Exclude:
|
|
@@ -183,8 +196,8 @@ Style/OptionalBooleanParameter:
|
|
|
183
196
|
- 'lib/http/uri.rb'
|
|
184
197
|
|
|
185
198
|
# Offense count: 3
|
|
186
|
-
#
|
|
187
|
-
# Configuration parameters:
|
|
199
|
+
# This cop supports safe autocorrection (--autocorrect).
|
|
200
|
+
# Configuration parameters: Max, AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns, IgnoredPatterns.
|
|
188
201
|
# URISchemes: http, https
|
|
189
202
|
Layout/LineLength:
|
|
190
203
|
Exclude:
|
data/CHANGES.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 5.1.0 (2022-06-17)
|
|
2
|
+
|
|
3
|
+
* Drop ruby-2.5 support.
|
|
4
|
+
|
|
5
|
+
* [#715](https://github.com/httprb/http/pull/715)
|
|
6
|
+
Set default encoding to UTF-8 for `application/json`.
|
|
7
|
+
([@drwl])
|
|
8
|
+
|
|
9
|
+
* [#712](https://github.com/httprb/http/pull/712)
|
|
10
|
+
Recognize cookies set by redirect.
|
|
11
|
+
([@tkellogg])
|
|
12
|
+
|
|
13
|
+
* [#707](https://github.com/httprb/http/pull/707)
|
|
14
|
+
Distinguish connection timeouts.
|
|
15
|
+
([@YuLeven])
|
|
16
|
+
|
|
1
17
|
## 5.0.4 (2021-10-07)
|
|
2
18
|
|
|
3
19
|
* [#698](https://github.com/httprb/http/pull/698)
|
|
@@ -42,7 +58,7 @@
|
|
|
42
58
|
|
|
43
59
|
* [#638](https://github.com/httprb/http/pull/638)
|
|
44
60
|
DNS failover handling.
|
|
45
|
-
([@midnight-wonderer])
|
|
61
|
+
([@midnight-wonderer])
|
|
46
62
|
|
|
47
63
|
|
|
48
64
|
## 5.0.1 (2021-06-26)
|
|
@@ -112,6 +128,7 @@
|
|
|
112
128
|
|
|
113
129
|
* [#576](https://github.com/httprb/http/pull/576)
|
|
114
130
|
[#524](https://github.com/httprb/http/issues/524)
|
|
131
|
+
**BREAKING CHANGE**
|
|
115
132
|
Preserve header names casing.
|
|
116
133
|
([@joshuaflanagan])
|
|
117
134
|
|
|
@@ -968,3 +985,6 @@ end
|
|
|
968
985
|
[@matheussilvasantos]: https://github.com/matheussilvasantos
|
|
969
986
|
[@PhilCoggins]: https://github.com/PhilCoggins
|
|
970
987
|
[@flosacca]: https://github.com/flosacca
|
|
988
|
+
[@YuLeven]: https://github.com/YuLeven
|
|
989
|
+
[@drwl]: https://github.com/drwl
|
|
990
|
+
[@tkellogg]: https://github.com/tkellogg
|
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright (c) 2011-
|
|
1
|
+
Copyright (c) 2011-2022 Tony Arcieri, Erik Michaels-Ober, Alexey V. Zapparov, Zachary Anker
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
4
|
a copy of this software and associated documentation files (the
|
data/README.md
CHANGED
|
@@ -141,7 +141,7 @@ dropped.
|
|
|
141
141
|
|
|
142
142
|
## Copyright
|
|
143
143
|
|
|
144
|
-
Copyright © 2011-
|
|
144
|
+
Copyright © 2011-2022 Tony Arcieri, Alexey V. Zapparov, Erik Michaels-Ober, Zachary Anker.
|
|
145
145
|
See LICENSE.txt for further details.
|
|
146
146
|
|
|
147
147
|
|
data/SECURITY.md
ADDED
data/http.gemspec
CHANGED
|
@@ -25,7 +25,7 @@ Gem::Specification.new do |gem|
|
|
|
25
25
|
gem.require_paths = ["lib"]
|
|
26
26
|
gem.version = HTTP::VERSION
|
|
27
27
|
|
|
28
|
-
gem.required_ruby_version = ">= 2.
|
|
28
|
+
gem.required_ruby_version = ">= 2.6"
|
|
29
29
|
|
|
30
30
|
gem.add_runtime_dependency "addressable", "~> 2.8"
|
|
31
31
|
gem.add_runtime_dependency "http-cookie", "~> 1.0"
|
|
@@ -35,9 +35,10 @@ Gem::Specification.new do |gem|
|
|
|
35
35
|
gem.add_development_dependency "bundler", "~> 2.0"
|
|
36
36
|
|
|
37
37
|
gem.metadata = {
|
|
38
|
-
"source_code_uri"
|
|
39
|
-
"wiki_uri"
|
|
40
|
-
"bug_tracker_uri"
|
|
41
|
-
"changelog_uri"
|
|
38
|
+
"source_code_uri" => "https://github.com/httprb/http",
|
|
39
|
+
"wiki_uri" => "https://github.com/httprb/http/wiki",
|
|
40
|
+
"bug_tracker_uri" => "https://github.com/httprb/http/issues",
|
|
41
|
+
"changelog_uri" => "https://github.com/httprb/http/blob/v#{HTTP::VERSION}/CHANGES.md",
|
|
42
|
+
"rubygems_mfa_required" => "true"
|
|
42
43
|
}
|
|
43
44
|
end
|
data/lib/http/errors.rb
CHANGED
|
@@ -19,6 +19,9 @@ module HTTP
|
|
|
19
19
|
# Generic Timeout error
|
|
20
20
|
class TimeoutError < Error; end
|
|
21
21
|
|
|
22
|
+
# Timeout when first establishing the conncetion
|
|
23
|
+
class ConnectTimeoutError < TimeoutError; end
|
|
24
|
+
|
|
22
25
|
# Header value is of unexpected format (similar to Net::HTTPHeaderSyntaxError)
|
|
23
26
|
class HeaderError < Error; end
|
|
24
27
|
end
|
data/lib/http/headers.rb
CHANGED
data/lib/http/redirector.rb
CHANGED
|
@@ -49,6 +49,8 @@ module HTTP
|
|
|
49
49
|
@request = request
|
|
50
50
|
@response = response
|
|
51
51
|
@visited = []
|
|
52
|
+
collect_cookies_from_request
|
|
53
|
+
collect_cookies_from_response
|
|
52
54
|
|
|
53
55
|
while REDIRECT_CODES.include? @response.status.code
|
|
54
56
|
@visited << "#{@request.verb} #{@request.uri}"
|
|
@@ -59,8 +61,12 @@ module HTTP
|
|
|
59
61
|
@response.flush
|
|
60
62
|
|
|
61
63
|
# XXX(ixti): using `Array#inject` to return `nil` if no Location header.
|
|
62
|
-
@request
|
|
64
|
+
@request = redirect_to(@response.headers.get(Headers::LOCATION).inject(:+))
|
|
65
|
+
unless cookie_jar.empty?
|
|
66
|
+
@request.headers.set(Headers::COOKIE, cookie_jar.cookies.map { |c| "#{c.name}=#{c.value}" }.join("; "))
|
|
67
|
+
end
|
|
63
68
|
@response = yield @request
|
|
69
|
+
collect_cookies_from_response
|
|
64
70
|
end
|
|
65
71
|
|
|
66
72
|
@response
|
|
@@ -68,6 +74,48 @@ module HTTP
|
|
|
68
74
|
|
|
69
75
|
private
|
|
70
76
|
|
|
77
|
+
# All known cookies. On the original request, this is only the original cookies, but after that,
|
|
78
|
+
# Set-Cookie headers can add, set or delete cookies.
|
|
79
|
+
def cookie_jar
|
|
80
|
+
# it seems that @response.cookies instance is reused between responses, so we have to "clone"
|
|
81
|
+
@cookie_jar ||= HTTP::CookieJar.new
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def collect_cookies_from_request
|
|
85
|
+
request_cookie_header = @request.headers["Cookie"]
|
|
86
|
+
cookies =
|
|
87
|
+
if request_cookie_header
|
|
88
|
+
HTTP::Cookie.cookie_value_to_hash(request_cookie_header)
|
|
89
|
+
else
|
|
90
|
+
{}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
cookies.each do |key, value|
|
|
94
|
+
cookie_jar.add(HTTP::Cookie.new(key, value, :path => @request.uri.path, :domain => @request.host))
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
# Carry cookies from one response to the next. Carrying cookies to the next response ends up
|
|
99
|
+
# carrying them to the next request as well.
|
|
100
|
+
#
|
|
101
|
+
# Note that this isn't part of the IETF standard, but all major browsers support setting cookies
|
|
102
|
+
# on redirect: https://blog.dubbelboer.com/2012/11/25/302-cookie.html
|
|
103
|
+
def collect_cookies_from_response
|
|
104
|
+
# Overwrite previous cookies
|
|
105
|
+
@response.cookies.each do |cookie|
|
|
106
|
+
if cookie.value == ""
|
|
107
|
+
cookie_jar.delete(cookie)
|
|
108
|
+
else
|
|
109
|
+
cookie_jar.add(cookie)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# I wish we could just do @response.cookes = cookie_jar
|
|
114
|
+
cookie_jar.each do |cookie|
|
|
115
|
+
@response.cookies.add(cookie)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
71
119
|
# Check if we reached max amount of redirect hops
|
|
72
120
|
# @return [Boolean]
|
|
73
121
|
def too_many_hops?
|
data/lib/http/response/status.rb
CHANGED
|
@@ -69,7 +69,7 @@ module HTTP
|
|
|
69
69
|
# SYMBOL_CODES[:im_a_teapot] # => 418
|
|
70
70
|
#
|
|
71
71
|
# @return [Hash<Symbol => Fixnum>]
|
|
72
|
-
SYMBOL_CODES = SYMBOLS.
|
|
72
|
+
SYMBOL_CODES = SYMBOLS.to_h { |k, v| [v, k] }.freeze
|
|
73
73
|
|
|
74
74
|
# @return [Fixnum] status code
|
|
75
75
|
attr_reader :code
|
data/lib/http/response.rb
CHANGED
|
@@ -53,7 +53,7 @@ module HTTP
|
|
|
53
53
|
@body = opts.fetch(:body)
|
|
54
54
|
else
|
|
55
55
|
connection = opts.fetch(:connection)
|
|
56
|
-
encoding
|
|
56
|
+
encoding = opts[:encoding] || charset || default_encoding
|
|
57
57
|
|
|
58
58
|
@body = Response::Body.new(connection, :encoding => encoding)
|
|
59
59
|
end
|
|
@@ -168,6 +168,12 @@ module HTTP
|
|
|
168
168
|
|
|
169
169
|
private
|
|
170
170
|
|
|
171
|
+
def default_encoding
|
|
172
|
+
return Encoding::UTF_8 if mime_type == "application/json"
|
|
173
|
+
|
|
174
|
+
Encoding::BINARY
|
|
175
|
+
end
|
|
176
|
+
|
|
171
177
|
# Initialize an HTTP::Request from options.
|
|
172
178
|
#
|
|
173
179
|
# @return [HTTP::Request]
|
data/lib/http/timeout/global.rb
CHANGED
|
@@ -21,7 +21,7 @@ module HTTP
|
|
|
21
21
|
|
|
22
22
|
def connect(socket_class, host, port, nodelay = false)
|
|
23
23
|
reset_timer
|
|
24
|
-
::Timeout.timeout(@time_left,
|
|
24
|
+
::Timeout.timeout(@time_left, ConnectTimeoutError) do
|
|
25
25
|
@socket = socket_class.open(host, port)
|
|
26
26
|
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay
|
|
27
27
|
end
|
|
@@ -20,7 +20,7 @@ module HTTP
|
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def connect(socket_class, host, port, nodelay = false)
|
|
23
|
-
::Timeout.timeout(@connect_timeout,
|
|
23
|
+
::Timeout.timeout(@connect_timeout, ConnectTimeoutError) do
|
|
24
24
|
@socket = socket_class.open(host, port)
|
|
25
25
|
@socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) if nodelay
|
|
26
26
|
end
|
data/lib/http/version.rb
CHANGED
|
@@ -389,8 +389,8 @@ RSpec.describe HTTP::Client do
|
|
|
389
389
|
client.use(:test_feature => feature_instance).
|
|
390
390
|
timeout(0.001).
|
|
391
391
|
request(:post, sleep_url)
|
|
392
|
-
end.to raise_error(HTTP::
|
|
393
|
-
expect(feature_instance.captured_error).to be_a(HTTP::
|
|
392
|
+
end.to raise_error(HTTP::ConnectTimeoutError)
|
|
393
|
+
expect(feature_instance.captured_error).to be_a(HTTP::ConnectTimeoutError)
|
|
394
394
|
end
|
|
395
395
|
end
|
|
396
396
|
end
|
|
@@ -11,8 +11,12 @@ RSpec.describe HTTP::Redirector do
|
|
|
11
11
|
)
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def redirect_response(status, location)
|
|
15
|
-
simple_response status, "", "Location" => location
|
|
14
|
+
def redirect_response(status, location, set_cookie = {})
|
|
15
|
+
res = simple_response status, "", "Location" => location
|
|
16
|
+
set_cookie.each do |name, value|
|
|
17
|
+
res.headers.add("Set-Cookie", "#{name}=#{value}; path=/; httponly; secure; SameSite=none; Secure")
|
|
18
|
+
end
|
|
19
|
+
res
|
|
16
20
|
end
|
|
17
21
|
|
|
18
22
|
describe "#strict" do
|
|
@@ -89,6 +93,61 @@ RSpec.describe HTTP::Redirector do
|
|
|
89
93
|
expect(res.to_s).to eq "http://example.com/123"
|
|
90
94
|
end
|
|
91
95
|
|
|
96
|
+
it "returns cookies in response" do
|
|
97
|
+
req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
|
|
98
|
+
hops = [
|
|
99
|
+
redirect_response(301, "http://example.com/1", {"foo" => "42"}),
|
|
100
|
+
redirect_response(301, "http://example.com/2", {"bar" => "53", "deleted" => "foo"}),
|
|
101
|
+
redirect_response(301, "http://example.com/3", {"baz" => "64", "deleted" => ""}),
|
|
102
|
+
redirect_response(301, "http://example.com/4", {"baz" => "65"}),
|
|
103
|
+
simple_response(200, "bar")
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
request_cookies = [
|
|
107
|
+
{"foo" => "42"},
|
|
108
|
+
{"foo" => "42", "bar" => "53", "deleted" => "foo"},
|
|
109
|
+
{"foo" => "42", "bar" => "53", "baz" => "64"},
|
|
110
|
+
{"foo" => "42", "bar" => "53", "baz" => "65"}
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
res = redirector.perform(req, hops.shift) do |request|
|
|
114
|
+
req_cookie = HTTP::Cookie.cookie_value_to_hash(request.headers["Cookie"] || "")
|
|
115
|
+
expect(req_cookie).to eq request_cookies.shift
|
|
116
|
+
hops.shift
|
|
117
|
+
end
|
|
118
|
+
expect(res.to_s).to eq "bar"
|
|
119
|
+
cookies = res.cookies.cookies.to_h { |c| [c.name, c.value] }
|
|
120
|
+
expect(cookies["foo"]).to eq "42"
|
|
121
|
+
expect(cookies["bar"]).to eq "53"
|
|
122
|
+
expect(cookies["baz"]).to eq "65"
|
|
123
|
+
expect(cookies["deleted"]).to eq nil
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "returns original cookies in response" do
|
|
127
|
+
req = HTTP::Request.new :verb => :head, :uri => "http://example.com"
|
|
128
|
+
req.headers.set("Cookie", "foo=42; deleted=baz")
|
|
129
|
+
hops = [
|
|
130
|
+
redirect_response(301, "http://example.com/1", {"bar" => "64", "deleted" => ""}),
|
|
131
|
+
simple_response(200, "bar")
|
|
132
|
+
]
|
|
133
|
+
|
|
134
|
+
request_cookies = [
|
|
135
|
+
{"foo" => "42", "bar" => "64"},
|
|
136
|
+
{"foo" => "42", "bar" => "64"}
|
|
137
|
+
]
|
|
138
|
+
|
|
139
|
+
res = redirector.perform(req, hops.shift) do |request|
|
|
140
|
+
req_cookie = HTTP::Cookie.cookie_value_to_hash(request.headers["Cookie"] || "")
|
|
141
|
+
expect(req_cookie).to eq request_cookies.shift
|
|
142
|
+
hops.shift
|
|
143
|
+
end
|
|
144
|
+
expect(res.to_s).to eq "bar"
|
|
145
|
+
cookies = res.cookies.cookies.to_h { |c| [c.name, c.value] }
|
|
146
|
+
expect(cookies["foo"]).to eq "42"
|
|
147
|
+
expect(cookies["bar"]).to eq "64"
|
|
148
|
+
expect(cookies["deleted"]).to eq nil
|
|
149
|
+
end
|
|
150
|
+
|
|
92
151
|
context "following 300 redirect" do
|
|
93
152
|
context "with strict mode" do
|
|
94
153
|
let(:options) { {:strict => true} }
|
|
@@ -400,7 +459,7 @@ RSpec.describe HTTP::Redirector do
|
|
|
400
459
|
describe "changing verbs during redirects" do
|
|
401
460
|
let(:options) { {:strict => false} }
|
|
402
461
|
let(:post_body) { HTTP::Request::Body.new("i might be way longer in real life") }
|
|
403
|
-
let(:cookie) { "dont
|
|
462
|
+
let(:cookie) { "dont=eat my cookies" }
|
|
404
463
|
|
|
405
464
|
def a_dangerous_request(verb)
|
|
406
465
|
HTTP::Request.new(
|
|
@@ -59,7 +59,7 @@ RSpec.describe HTTP::Response::Body do
|
|
|
59
59
|
let(:chunks) do
|
|
60
60
|
body = Zlib::Deflate.deflate("Hi, HTTP here ☺")
|
|
61
61
|
len = body.length
|
|
62
|
-
[body[0, len / 2], body[(len / 2)
|
|
62
|
+
[body[0, len / 2], body[(len / 2)..]]
|
|
63
63
|
end
|
|
64
64
|
subject(:body) do
|
|
65
65
|
inflater = HTTP::Response::Inflater.new(connection)
|
|
@@ -223,4 +223,40 @@ RSpec.describe HTTP::Response do
|
|
|
223
223
|
end
|
|
224
224
|
end
|
|
225
225
|
end
|
|
226
|
+
|
|
227
|
+
describe "#body" do
|
|
228
|
+
let(:connection) { double(:sequence_id => 0) }
|
|
229
|
+
let(:chunks) { ["Hello, ", "World!"] }
|
|
230
|
+
|
|
231
|
+
subject(:response) do
|
|
232
|
+
HTTP::Response.new(
|
|
233
|
+
:status => 200,
|
|
234
|
+
:version => "1.1",
|
|
235
|
+
:headers => headers,
|
|
236
|
+
:request => request,
|
|
237
|
+
:connection => connection
|
|
238
|
+
)
|
|
239
|
+
end
|
|
240
|
+
|
|
241
|
+
before do
|
|
242
|
+
allow(connection).to receive(:readpartial) { chunks.shift }
|
|
243
|
+
allow(connection).to receive(:body_completed?) { chunks.empty? }
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
context "with no Content-Type" do
|
|
247
|
+
let(:headers) { {} }
|
|
248
|
+
|
|
249
|
+
it "returns a body with default binary encoding" do
|
|
250
|
+
expect(response.body.to_s.encoding).to eq Encoding::BINARY
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
context "with Content-Type: application/json" do
|
|
255
|
+
let(:headers) { {"Content-Type" => "application/json"} }
|
|
256
|
+
|
|
257
|
+
it "returns a body with a default UTF_8 encoding" do
|
|
258
|
+
expect(response.body.to_s.encoding).to eq Encoding::UTF_8
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
end
|
|
226
262
|
end
|
|
@@ -77,7 +77,7 @@ RSpec.shared_context "HTTP handling" do
|
|
|
77
77
|
sleep 1.25
|
|
78
78
|
end
|
|
79
79
|
|
|
80
|
-
expect { response }.to raise_error(HTTP::
|
|
80
|
+
expect { response }.to raise_error(HTTP::ConnectTimeoutError, /execution/)
|
|
81
81
|
end
|
|
82
82
|
|
|
83
83
|
it "errors if reading takes too long" do
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: http
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.0
|
|
4
|
+
version: 5.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tony Arcieri
|
|
@@ -11,7 +11,7 @@ authors:
|
|
|
11
11
|
autorequire:
|
|
12
12
|
bindir: bin
|
|
13
13
|
cert_chain: []
|
|
14
|
-
date:
|
|
14
|
+
date: 2022-06-17 00:00:00.000000000 Z
|
|
15
15
|
dependencies:
|
|
16
16
|
- !ruby/object:Gem::Dependency
|
|
17
17
|
name: addressable
|
|
@@ -106,6 +106,7 @@ files:
|
|
|
106
106
|
- LICENSE.txt
|
|
107
107
|
- README.md
|
|
108
108
|
- Rakefile
|
|
109
|
+
- SECURITY.md
|
|
109
110
|
- http.gemspec
|
|
110
111
|
- lib/http.rb
|
|
111
112
|
- lib/http/chainable.rb
|
|
@@ -191,7 +192,8 @@ metadata:
|
|
|
191
192
|
source_code_uri: https://github.com/httprb/http
|
|
192
193
|
wiki_uri: https://github.com/httprb/http/wiki
|
|
193
194
|
bug_tracker_uri: https://github.com/httprb/http/issues
|
|
194
|
-
changelog_uri: https://github.com/httprb/http/blob/v5.0
|
|
195
|
+
changelog_uri: https://github.com/httprb/http/blob/v5.1.0/CHANGES.md
|
|
196
|
+
rubygems_mfa_required: 'true'
|
|
195
197
|
post_install_message:
|
|
196
198
|
rdoc_options: []
|
|
197
199
|
require_paths:
|
|
@@ -200,14 +202,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
200
202
|
requirements:
|
|
201
203
|
- - ">="
|
|
202
204
|
- !ruby/object:Gem::Version
|
|
203
|
-
version: '2.
|
|
205
|
+
version: '2.6'
|
|
204
206
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
205
207
|
requirements:
|
|
206
208
|
- - ">="
|
|
207
209
|
- !ruby/object:Gem::Version
|
|
208
210
|
version: '0'
|
|
209
211
|
requirements: []
|
|
210
|
-
rubygems_version: 3.
|
|
212
|
+
rubygems_version: 3.1.6
|
|
211
213
|
signing_key:
|
|
212
214
|
specification_version: 4
|
|
213
215
|
summary: HTTP should be easy
|