http 5.3.1 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +241 -41
  3. data/LICENSE.txt +1 -1
  4. data/README.md +110 -13
  5. data/UPGRADING.md +491 -0
  6. data/http.gemspec +32 -29
  7. data/lib/http/base64.rb +11 -1
  8. data/lib/http/chainable/helpers.rb +62 -0
  9. data/lib/http/chainable/verbs.rb +136 -0
  10. data/lib/http/chainable.rb +232 -136
  11. data/lib/http/client.rb +158 -127
  12. data/lib/http/connection/internals.rb +141 -0
  13. data/lib/http/connection.rb +126 -97
  14. data/lib/http/content_type.rb +61 -6
  15. data/lib/http/errors.rb +25 -1
  16. data/lib/http/feature.rb +65 -5
  17. data/lib/http/features/auto_deflate.rb +124 -17
  18. data/lib/http/features/auto_inflate.rb +38 -15
  19. data/lib/http/features/caching/entry.rb +178 -0
  20. data/lib/http/features/caching/in_memory_store.rb +63 -0
  21. data/lib/http/features/caching.rb +216 -0
  22. data/lib/http/features/digest_auth.rb +234 -0
  23. data/lib/http/features/instrumentation.rb +97 -17
  24. data/lib/http/features/logging.rb +183 -5
  25. data/lib/http/features/normalize_uri.rb +17 -0
  26. data/lib/http/features/raise_error.rb +18 -3
  27. data/lib/http/form_data/composite_io.rb +106 -0
  28. data/lib/http/form_data/file.rb +95 -0
  29. data/lib/http/form_data/multipart/param.rb +62 -0
  30. data/lib/http/form_data/multipart.rb +106 -0
  31. data/lib/http/form_data/part.rb +52 -0
  32. data/lib/http/form_data/readable.rb +58 -0
  33. data/lib/http/form_data/urlencoded.rb +175 -0
  34. data/lib/http/form_data/version.rb +8 -0
  35. data/lib/http/form_data.rb +102 -0
  36. data/lib/http/headers/known.rb +3 -0
  37. data/lib/http/headers/normalizer.rb +17 -36
  38. data/lib/http/headers.rb +172 -65
  39. data/lib/http/mime_type/adapter.rb +24 -9
  40. data/lib/http/mime_type/json.rb +19 -4
  41. data/lib/http/mime_type.rb +21 -3
  42. data/lib/http/options/definitions.rb +189 -0
  43. data/lib/http/options.rb +172 -125
  44. data/lib/http/redirector.rb +80 -75
  45. data/lib/http/request/body.rb +87 -6
  46. data/lib/http/request/builder.rb +184 -0
  47. data/lib/http/request/proxy.rb +83 -0
  48. data/lib/http/request/writer.rb +76 -16
  49. data/lib/http/request.rb +214 -98
  50. data/lib/http/response/body.rb +103 -18
  51. data/lib/http/response/inflater.rb +35 -7
  52. data/lib/http/response/parser.rb +98 -4
  53. data/lib/http/response/status/reasons.rb +2 -4
  54. data/lib/http/response/status.rb +141 -31
  55. data/lib/http/response.rb +219 -61
  56. data/lib/http/retriable/delay_calculator.rb +38 -11
  57. data/lib/http/retriable/errors.rb +21 -0
  58. data/lib/http/retriable/performer.rb +82 -38
  59. data/lib/http/session.rb +280 -0
  60. data/lib/http/timeout/global.rb +147 -34
  61. data/lib/http/timeout/null.rb +155 -9
  62. data/lib/http/timeout/per_operation.rb +139 -18
  63. data/lib/http/uri/normalizer.rb +82 -0
  64. data/lib/http/uri/parsing.rb +182 -0
  65. data/lib/http/uri.rb +289 -124
  66. data/lib/http/version.rb +2 -1
  67. data/lib/http.rb +11 -2
  68. data/sig/deps.rbs +122 -0
  69. data/sig/http.rbs +1619 -0
  70. data/test/http/base64_test.rb +28 -0
  71. data/test/http/client_test.rb +739 -0
  72. data/test/http/connection_test.rb +1533 -0
  73. data/test/http/content_type_test.rb +190 -0
  74. data/test/http/errors_test.rb +28 -0
  75. data/test/http/feature_test.rb +49 -0
  76. data/test/http/features/auto_deflate_test.rb +317 -0
  77. data/test/http/features/auto_inflate_test.rb +213 -0
  78. data/test/http/features/caching_test.rb +942 -0
  79. data/test/http/features/digest_auth_test.rb +996 -0
  80. data/test/http/features/instrumentation_test.rb +246 -0
  81. data/test/http/features/logging_test.rb +654 -0
  82. data/test/http/features/normalize_uri_test.rb +41 -0
  83. data/test/http/features/raise_error_test.rb +77 -0
  84. data/test/http/form_data/composite_io_test.rb +215 -0
  85. data/test/http/form_data/file_test.rb +255 -0
  86. data/test/http/form_data/fixtures/the-http-gem.info +1 -0
  87. data/test/http/form_data/multipart_test.rb +303 -0
  88. data/test/http/form_data/part_test.rb +90 -0
  89. data/test/http/form_data/urlencoded_test.rb +164 -0
  90. data/test/http/form_data_test.rb +232 -0
  91. data/test/http/headers/normalizer_test.rb +93 -0
  92. data/test/http/headers_test.rb +888 -0
  93. data/test/http/mime_type/json_test.rb +39 -0
  94. data/test/http/mime_type_test.rb +150 -0
  95. data/test/http/options/base_uri_test.rb +148 -0
  96. data/test/http/options/body_test.rb +21 -0
  97. data/test/http/options/features_test.rb +38 -0
  98. data/test/http/options/form_test.rb +21 -0
  99. data/test/http/options/headers_test.rb +32 -0
  100. data/test/http/options/json_test.rb +21 -0
  101. data/test/http/options/merge_test.rb +78 -0
  102. data/test/http/options/new_test.rb +37 -0
  103. data/test/http/options/proxy_test.rb +32 -0
  104. data/test/http/options_test.rb +575 -0
  105. data/test/http/redirector_test.rb +639 -0
  106. data/test/http/request/body_test.rb +318 -0
  107. data/test/http/request/builder_test.rb +623 -0
  108. data/test/http/request/writer_test.rb +391 -0
  109. data/test/http/request_test.rb +1733 -0
  110. data/test/http/response/body_test.rb +292 -0
  111. data/test/http/response/parser_test.rb +105 -0
  112. data/test/http/response/status_test.rb +322 -0
  113. data/test/http/response_test.rb +502 -0
  114. data/test/http/retriable/delay_calculator_test.rb +194 -0
  115. data/test/http/retriable/errors_test.rb +71 -0
  116. data/test/http/retriable/performer_test.rb +551 -0
  117. data/test/http/session_test.rb +424 -0
  118. data/test/http/timeout/global_test.rb +239 -0
  119. data/test/http/timeout/null_test.rb +218 -0
  120. data/test/http/timeout/per_operation_test.rb +220 -0
  121. data/test/http/uri/normalizer_test.rb +89 -0
  122. data/test/http/uri_test.rb +1140 -0
  123. data/test/http/version_test.rb +15 -0
  124. data/test/http_test.rb +818 -0
  125. data/test/regression_tests.rb +27 -0
  126. data/test/support/dummy_server/encoding_routes.rb +47 -0
  127. data/test/support/dummy_server/routes.rb +201 -0
  128. data/test/support/dummy_server/servlet.rb +81 -0
  129. data/test/support/dummy_server.rb +200 -0
  130. data/{spec → test}/support/fakeio.rb +2 -2
  131. data/test/support/http_handling_shared/connection_reuse_tests.rb +97 -0
  132. data/test/support/http_handling_shared/timeout_tests.rb +134 -0
  133. data/test/support/http_handling_shared.rb +11 -0
  134. data/test/support/proxy_server.rb +207 -0
  135. data/test/support/servers/runner.rb +67 -0
  136. data/{spec → test}/support/simplecov.rb +11 -2
  137. data/test/support/ssl_helper.rb +108 -0
  138. data/test/test_helper.rb +38 -0
  139. metadata +108 -168
  140. data/.github/workflows/ci.yml +0 -67
  141. data/.gitignore +0 -15
  142. data/.rspec +0 -1
  143. data/.rubocop/layout.yml +0 -8
  144. data/.rubocop/metrics.yml +0 -4
  145. data/.rubocop/rspec.yml +0 -9
  146. data/.rubocop/style.yml +0 -32
  147. data/.rubocop.yml +0 -11
  148. data/.rubocop_todo.yml +0 -219
  149. data/.yardopts +0 -2
  150. data/CHANGES_OLD.md +0 -1002
  151. data/Gemfile +0 -51
  152. data/Guardfile +0 -18
  153. data/Rakefile +0 -64
  154. data/lib/http/headers/mixin.rb +0 -34
  155. data/lib/http/retriable/client.rb +0 -37
  156. data/logo.png +0 -0
  157. data/spec/lib/http/client_spec.rb +0 -556
  158. data/spec/lib/http/connection_spec.rb +0 -88
  159. data/spec/lib/http/content_type_spec.rb +0 -47
  160. data/spec/lib/http/features/auto_deflate_spec.rb +0 -77
  161. data/spec/lib/http/features/auto_inflate_spec.rb +0 -86
  162. data/spec/lib/http/features/instrumentation_spec.rb +0 -81
  163. data/spec/lib/http/features/logging_spec.rb +0 -65
  164. data/spec/lib/http/features/raise_error_spec.rb +0 -62
  165. data/spec/lib/http/headers/mixin_spec.rb +0 -36
  166. data/spec/lib/http/headers/normalizer_spec.rb +0 -52
  167. data/spec/lib/http/headers_spec.rb +0 -527
  168. data/spec/lib/http/options/body_spec.rb +0 -15
  169. data/spec/lib/http/options/features_spec.rb +0 -33
  170. data/spec/lib/http/options/form_spec.rb +0 -15
  171. data/spec/lib/http/options/headers_spec.rb +0 -24
  172. data/spec/lib/http/options/json_spec.rb +0 -15
  173. data/spec/lib/http/options/merge_spec.rb +0 -68
  174. data/spec/lib/http/options/new_spec.rb +0 -30
  175. data/spec/lib/http/options/proxy_spec.rb +0 -20
  176. data/spec/lib/http/options_spec.rb +0 -13
  177. data/spec/lib/http/redirector_spec.rb +0 -530
  178. data/spec/lib/http/request/body_spec.rb +0 -211
  179. data/spec/lib/http/request/writer_spec.rb +0 -121
  180. data/spec/lib/http/request_spec.rb +0 -234
  181. data/spec/lib/http/response/body_spec.rb +0 -85
  182. data/spec/lib/http/response/parser_spec.rb +0 -74
  183. data/spec/lib/http/response/status_spec.rb +0 -253
  184. data/spec/lib/http/response_spec.rb +0 -262
  185. data/spec/lib/http/retriable/delay_calculator_spec.rb +0 -69
  186. data/spec/lib/http/retriable/performer_spec.rb +0 -302
  187. data/spec/lib/http/uri/normalizer_spec.rb +0 -95
  188. data/spec/lib/http/uri_spec.rb +0 -71
  189. data/spec/lib/http_spec.rb +0 -535
  190. data/spec/regression_specs.rb +0 -24
  191. data/spec/spec_helper.rb +0 -89
  192. data/spec/support/black_hole.rb +0 -13
  193. data/spec/support/dummy_server/servlet.rb +0 -203
  194. data/spec/support/dummy_server.rb +0 -44
  195. data/spec/support/fuubar.rb +0 -21
  196. data/spec/support/http_handling_shared.rb +0 -190
  197. data/spec/support/proxy_server.rb +0 -39
  198. data/spec/support/servers/config.rb +0 -11
  199. data/spec/support/servers/runner.rb +0 -19
  200. data/spec/support/ssl_helper.rb +0 -104
  201. /data/{spec → test}/support/capture_warning.rb +0 -0
@@ -1,211 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe HTTP::Request::Body do
4
- let(:body) { "" }
5
- subject { HTTP::Request::Body.new(body) }
6
-
7
- describe "#initialize" do
8
- context "when body is nil" do
9
- let(:body) { nil }
10
-
11
- it "does not raise an error" do
12
- expect { subject }.not_to raise_error
13
- end
14
- end
15
-
16
- context "when body is a string" do
17
- let(:body) { "string body" }
18
-
19
- it "does not raise an error" do
20
- expect { subject }.not_to raise_error
21
- end
22
- end
23
-
24
- context "when body is an IO" do
25
- let(:body) { FakeIO.new("IO body") }
26
-
27
- it "does not raise an error" do
28
- expect { subject }.not_to raise_error
29
- end
30
- end
31
-
32
- context "when body is an Enumerable" do
33
- let(:body) { %w[bees cows] }
34
-
35
- it "does not raise an error" do
36
- expect { subject }.not_to raise_error
37
- end
38
- end
39
-
40
- context "when body is of unrecognized type" do
41
- let(:body) { 123 }
42
-
43
- it "raises an error" do
44
- expect { subject }.to raise_error(HTTP::RequestError)
45
- end
46
- end
47
- end
48
-
49
- describe "#source" do
50
- it "returns the original object" do
51
- expect(subject.source).to eq ""
52
- end
53
- end
54
-
55
- describe "#size" do
56
- context "when body is nil" do
57
- let(:body) { nil }
58
-
59
- it "returns zero" do
60
- expect(subject.size).to eq 0
61
- end
62
- end
63
-
64
- context "when body is a string" do
65
- let(:body) { "Привет, мир!" }
66
-
67
- it "returns string bytesize" do
68
- expect(subject.size).to eq 21
69
- end
70
- end
71
-
72
- context "when body is an IO with size" do
73
- let(:body) { FakeIO.new("content") }
74
-
75
- it "returns IO size" do
76
- expect(subject.size).to eq 7
77
- end
78
- end
79
-
80
- context "when body is an IO without size" do
81
- let(:body) { IO.pipe[0] }
82
-
83
- it "raises a RequestError" do
84
- expect { subject.size }.to raise_error(HTTP::RequestError)
85
- end
86
- end
87
-
88
- context "when body is an Enumerable" do
89
- let(:body) { %w[bees cows] }
90
-
91
- it "raises a RequestError" do
92
- expect { subject.size }.to raise_error(HTTP::RequestError)
93
- end
94
- end
95
- end
96
-
97
- describe "#each" do
98
- let(:chunks) do
99
- chunks = []
100
- subject.each { |chunk| chunks << chunk.dup }
101
- chunks
102
- end
103
-
104
- context "when body is nil" do
105
- let(:body) { nil }
106
-
107
- it "yields nothing" do
108
- expect(chunks).to eq []
109
- end
110
- end
111
-
112
- context "when body is a string" do
113
- let(:body) { "content" }
114
-
115
- it "yields the string" do
116
- expect(chunks).to eq %w[content]
117
- end
118
- end
119
-
120
- context "when body is a non-Enumerable IO" do
121
- let(:body) { FakeIO.new(("a" * 16 * 1024) + ("b" * 10 * 1024)) }
122
-
123
- it "yields chunks of content" do
124
- expect(chunks.inject("", :+)).to eq ("a" * 16 * 1024) + ("b" * 10 * 1024)
125
- end
126
- end
127
-
128
- context "when body is a pipe" do
129
- let(:ios) { IO.pipe }
130
- let(:body) { ios[0] }
131
-
132
- around do |example|
133
- writer = Thread.new(ios[1]) do |io|
134
- io << "abcdef"
135
- io.close
136
- end
137
-
138
- begin
139
- example.run
140
- ensure
141
- writer.join
142
- end
143
- end
144
-
145
- it "yields chunks of content" do
146
- expect(chunks.inject("", :+)).to eq("abcdef")
147
- end
148
- end
149
-
150
- context "when body is an Enumerable IO" do
151
- let(:data) { ("a" * 16 * 1024) + ("b" * 10 * 1024) }
152
- let(:body) { StringIO.new data }
153
-
154
- it "yields chunks of content" do
155
- expect(chunks.inject("", :+)).to eq data
156
- end
157
-
158
- it "allows to enumerate multiple times" do
159
- results = []
160
-
161
- 2.times do
162
- result = ""
163
- subject.each { |chunk| result += chunk }
164
- results << result
165
- end
166
-
167
- aggregate_failures do
168
- expect(results.count).to eq 2
169
- expect(results).to all eq data
170
- end
171
- end
172
- end
173
-
174
- context "when body is an Enumerable" do
175
- let(:body) { %w[bees cows] }
176
-
177
- it "yields elements" do
178
- expect(chunks).to eq %w[bees cows]
179
- end
180
- end
181
- end
182
-
183
- describe "#==" do
184
- context "when sources are equivalent" do
185
- let(:body1) { HTTP::Request::Body.new("content") }
186
- let(:body2) { HTTP::Request::Body.new("content") }
187
-
188
- it "returns true" do
189
- expect(body1).to eq body2
190
- end
191
- end
192
-
193
- context "when sources are not equivalent" do
194
- let(:body1) { HTTP::Request::Body.new("content") }
195
- let(:body2) { HTTP::Request::Body.new(nil) }
196
-
197
- it "returns false" do
198
- expect(body1).not_to eq body2
199
- end
200
- end
201
-
202
- context "when objects are not of the same class" do
203
- let(:body1) { HTTP::Request::Body.new("content") }
204
- let(:body2) { "content" }
205
-
206
- it "returns false" do
207
- expect(body1).not_to eq body2
208
- end
209
- end
210
- end
211
- end
@@ -1,121 +0,0 @@
1
- # coding: utf-8
2
- # frozen_string_literal: true
3
-
4
- RSpec.describe HTTP::Request::Writer do
5
- let(:io) { StringIO.new }
6
- let(:body) { HTTP::Request::Body.new("") }
7
- let(:headers) { HTTP::Headers.new }
8
- let(:headerstart) { "GET /test HTTP/1.1" }
9
-
10
- subject(:writer) { described_class.new(io, body, headers, headerstart) }
11
-
12
- describe "#stream" do
13
- context "when multiple headers are set" do
14
- let(:headers) { HTTP::Headers.coerce "Host" => "example.org" }
15
-
16
- it "separates headers with carriage return and line feed" do
17
- writer.stream
18
- expect(io.string).to eq [
19
- "#{headerstart}\r\n",
20
- "Host: example.org\r\nContent-Length: 0\r\n\r\n"
21
- ].join
22
- end
23
- end
24
-
25
- context "when headers are specified as strings with mixed case" do
26
- let(:headers) { HTTP::Headers.coerce "content-Type" => "text", "X_MAX" => "200" }
27
-
28
- it "writes the headers with the same casing" do
29
- writer.stream
30
- expect(io.string).to eq [
31
- "#{headerstart}\r\n",
32
- "content-Type: text\r\nX_MAX: 200\r\nContent-Length: 0\r\n\r\n"
33
- ].join
34
- end
35
- end
36
-
37
- context "when body is nonempty" do
38
- let(:body) { HTTP::Request::Body.new("content") }
39
-
40
- it "writes it to the socket and sets Content-Length" do
41
- writer.stream
42
- expect(io.string).to eq [
43
- "#{headerstart}\r\n",
44
- "Content-Length: 7\r\n\r\n",
45
- "content"
46
- ].join
47
- end
48
- end
49
-
50
- context "when body is not set" do
51
- let(:body) { HTTP::Request::Body.new(nil) }
52
-
53
- it "doesn't write anything to the socket and doesn't set Content-Length" do
54
- writer.stream
55
- expect(io.string).to eq [
56
- "#{headerstart}\r\n\r\n"
57
- ].join
58
- end
59
- end
60
-
61
- context "when body is empty" do
62
- let(:body) { HTTP::Request::Body.new("") }
63
-
64
- it "doesn't write anything to the socket and sets Content-Length" do
65
- writer.stream
66
- expect(io.string).to eq [
67
- "#{headerstart}\r\n",
68
- "Content-Length: 0\r\n\r\n"
69
- ].join
70
- end
71
- end
72
-
73
- context "when Content-Length header is set" do
74
- let(:headers) { HTTP::Headers.coerce "Content-Length" => "12" }
75
- let(:body) { HTTP::Request::Body.new("content") }
76
-
77
- it "keeps the given value" do
78
- writer.stream
79
- expect(io.string).to eq [
80
- "#{headerstart}\r\n",
81
- "Content-Length: 12\r\n\r\n",
82
- "content"
83
- ].join
84
- end
85
- end
86
-
87
- context "when Transfer-Encoding is chunked" do
88
- let(:headers) { HTTP::Headers.coerce "Transfer-Encoding" => "chunked" }
89
- let(:body) { HTTP::Request::Body.new(%w[request body]) }
90
-
91
- it "writes encoded content and omits Content-Length" do
92
- writer.stream
93
- expect(io.string).to eq [
94
- "#{headerstart}\r\n",
95
- "Transfer-Encoding: chunked\r\n\r\n",
96
- "7\r\nrequest\r\n4\r\nbody\r\n0\r\n\r\n"
97
- ].join
98
- end
99
- end
100
-
101
- context "when server won't accept any more data" do
102
- before do
103
- expect(io).to receive(:write).and_raise(Errno::EPIPE)
104
- end
105
-
106
- it "aborts silently" do
107
- writer.stream
108
- end
109
- end
110
-
111
- context "when writing to socket raises an exception" do
112
- before do
113
- expect(io).to receive(:write).and_raise(Errno::ECONNRESET)
114
- end
115
-
116
- it "raises a ConnectionError" do
117
- expect { writer.stream }.to raise_error(HTTP::ConnectionError)
118
- end
119
- end
120
- end
121
- end
@@ -1,234 +0,0 @@
1
- # coding: utf-8
2
- # frozen_string_literal: true
3
-
4
- RSpec.describe HTTP::Request do
5
- let(:proxy) { {} }
6
- let(:headers) { {:accept => "text/html"} }
7
- let(:request_uri) { "http://example.com/foo?bar=baz" }
8
-
9
- subject :request do
10
- HTTP::Request.new(
11
- :verb => :get,
12
- :uri => request_uri,
13
- :headers => headers,
14
- :proxy => proxy
15
- )
16
- end
17
-
18
- it "includes HTTP::Headers::Mixin" do
19
- expect(described_class).to include HTTP::Headers::Mixin
20
- end
21
-
22
- it "requires URI to have scheme part" do
23
- expect { HTTP::Request.new(:verb => :get, :uri => "example.com/") }.to \
24
- raise_error(HTTP::Request::UnsupportedSchemeError)
25
- end
26
-
27
- it "provides a #scheme accessor" do
28
- expect(request.scheme).to eq(:http)
29
- end
30
-
31
- it "provides a #verb accessor" do
32
- expect(subject.verb).to eq(:get)
33
- end
34
-
35
- it "sets given headers" do
36
- expect(subject["Accept"]).to eq("text/html")
37
- end
38
-
39
- describe "Host header" do
40
- subject { request["Host"] }
41
-
42
- context "was not given" do
43
- it { is_expected.to eq "example.com" }
44
-
45
- context "and request URI has non-standard port" do
46
- let(:request_uri) { "http://example.com:3000/" }
47
- it { is_expected.to eq "example.com:3000" }
48
- end
49
- end
50
-
51
- context "was explicitly given" do
52
- before { headers[:host] = "github.com" }
53
- it { is_expected.to eq "github.com" }
54
- end
55
- end
56
-
57
- describe "User-Agent header" do
58
- subject { request["User-Agent"] }
59
-
60
- context "was not given" do
61
- it { is_expected.to eq HTTP::Request::USER_AGENT }
62
- end
63
-
64
- context "was explicitly given" do
65
- before { headers[:user_agent] = "MrCrawly/123" }
66
- it { is_expected.to eq "MrCrawly/123" }
67
- end
68
- end
69
-
70
- describe "#redirect" do
71
- let(:headers) { {:accept => "text/html"} }
72
- let(:proxy) { {:proxy_username => "douglas", :proxy_password => "adams"} }
73
- let(:body) { "The Ultimate Question" }
74
-
75
- let :request do
76
- HTTP::Request.new(
77
- :verb => :post,
78
- :uri => "http://example.com/",
79
- :headers => headers,
80
- :proxy => proxy,
81
- :body => body
82
- )
83
- end
84
-
85
- subject(:redirected) { request.redirect "http://blog.example.com/" }
86
-
87
- its(:uri) { is_expected.to eq HTTP::URI.parse "http://blog.example.com/" }
88
-
89
- its(:verb) { is_expected.to eq request.verb }
90
- its(:body) { is_expected.to eq request.body }
91
- its(:proxy) { is_expected.to eq request.proxy }
92
-
93
- it "presets new Host header" do
94
- expect(redirected["Host"]).to eq "blog.example.com"
95
- end
96
-
97
- context "with URL with non-standard port given" do
98
- subject(:redirected) { request.redirect "http://example.com:8080" }
99
-
100
- its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com:8080" }
101
-
102
- its(:verb) { is_expected.to eq request.verb }
103
- its(:body) { is_expected.to eq request.body }
104
- its(:proxy) { is_expected.to eq request.proxy }
105
-
106
- it "presets new Host header" do
107
- expect(redirected["Host"]).to eq "example.com:8080"
108
- end
109
- end
110
-
111
- context "with schema-less absolute URL given" do
112
- subject(:redirected) { request.redirect "//another.example.com/blog" }
113
-
114
- its(:uri) { is_expected.to eq HTTP::URI.parse "http://another.example.com/blog" }
115
-
116
- its(:verb) { is_expected.to eq request.verb }
117
- its(:body) { is_expected.to eq request.body }
118
- its(:proxy) { is_expected.to eq request.proxy }
119
-
120
- it "presets new Host header" do
121
- expect(redirected["Host"]).to eq "another.example.com"
122
- end
123
- end
124
-
125
- context "with relative URL given" do
126
- subject(:redirected) { request.redirect "/blog" }
127
-
128
- its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com/blog" }
129
-
130
- its(:verb) { is_expected.to eq request.verb }
131
- its(:body) { is_expected.to eq request.body }
132
- its(:proxy) { is_expected.to eq request.proxy }
133
-
134
- it "keeps Host header" do
135
- expect(redirected["Host"]).to eq "example.com"
136
- end
137
-
138
- context "with original URI having non-standard port" do
139
- let :request do
140
- HTTP::Request.new(
141
- :verb => :post,
142
- :uri => "http://example.com:8080/",
143
- :headers => headers,
144
- :proxy => proxy,
145
- :body => body
146
- )
147
- end
148
-
149
- its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com:8080/blog" }
150
- end
151
- end
152
-
153
- context "with relative URL that misses leading slash given" do
154
- subject(:redirected) { request.redirect "blog" }
155
-
156
- its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com/blog" }
157
-
158
- its(:verb) { is_expected.to eq request.verb }
159
- its(:body) { is_expected.to eq request.body }
160
- its(:proxy) { is_expected.to eq request.proxy }
161
-
162
- it "keeps Host header" do
163
- expect(redirected["Host"]).to eq "example.com"
164
- end
165
-
166
- context "with original URI having non-standard port" do
167
- let :request do
168
- HTTP::Request.new(
169
- :verb => :post,
170
- :uri => "http://example.com:8080/",
171
- :headers => headers,
172
- :proxy => proxy,
173
- :body => body
174
- )
175
- end
176
-
177
- its(:uri) { is_expected.to eq HTTP::URI.parse "http://example.com:8080/blog" }
178
- end
179
- end
180
-
181
- context "with new verb given" do
182
- subject { request.redirect "http://blog.example.com/", :get }
183
- its(:verb) { is_expected.to be :get }
184
- end
185
- end
186
-
187
- describe "#headline" do
188
- subject(:headline) { request.headline }
189
-
190
- it { is_expected.to eq "GET /foo?bar=baz HTTP/1.1" }
191
-
192
- context "when URI contains encoded query" do
193
- let(:encoded_query) { "t=1970-01-01T01%3A00%3A00%2B01%3A00" }
194
- let(:request_uri) { "http://example.com/foo/?#{encoded_query}" }
195
-
196
- it "does not unencodes query part" do
197
- expect(headline).to eq "GET /foo/?#{encoded_query} HTTP/1.1"
198
- end
199
- end
200
-
201
- context "when URI contains non-ASCII path" do
202
- let(:request_uri) { "http://example.com/キョ" }
203
-
204
- it "encodes non-ASCII path part" do
205
- expect(headline).to eq "GET /%E3%82%AD%E3%83%A7 HTTP/1.1"
206
- end
207
- end
208
-
209
- context "when URI contains fragment" do
210
- let(:request_uri) { "http://example.com/foo#bar" }
211
-
212
- it "omits fragment part" do
213
- expect(headline).to eq "GET /foo HTTP/1.1"
214
- end
215
- end
216
-
217
- context "with proxy" do
218
- let(:proxy) { {:user => "user", :pass => "pass"} }
219
- it { is_expected.to eq "GET http://example.com/foo?bar=baz HTTP/1.1" }
220
-
221
- context "and HTTPS uri" do
222
- let(:request_uri) { "https://example.com/foo?bar=baz" }
223
-
224
- it { is_expected.to eq "GET /foo?bar=baz HTTP/1.1" }
225
- end
226
- end
227
- end
228
-
229
- describe "#inspect" do
230
- subject { request.inspect }
231
-
232
- it { is_expected.to eq "#<HTTP::Request/1.1 GET #{request_uri}>" }
233
- end
234
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- RSpec.describe HTTP::Response::Body do
4
- let(:connection) { double(:sequence_id => 0) }
5
- let(:chunks) { ["Hello, ", "World!"] }
6
-
7
- before do
8
- allow(connection).to receive(:readpartial) { chunks.shift }
9
- allow(connection).to receive(:body_completed?) { chunks.empty? }
10
- end
11
-
12
- subject(:body) { described_class.new(connection, :encoding => Encoding::UTF_8) }
13
-
14
- it "streams bodies from responses" do
15
- expect(subject.to_s).to eq("Hello, World!")
16
- end
17
-
18
- context "when body empty" do
19
- let(:chunks) { [""] }
20
-
21
- it "returns responds to empty? with true" do
22
- expect(subject).to be_empty
23
- end
24
- end
25
-
26
- describe "#readpartial" do
27
- context "with size given" do
28
- it "passes value to underlying connection" do
29
- expect(connection).to receive(:readpartial).with(42)
30
- body.readpartial 42
31
- end
32
- end
33
-
34
- context "without size given" do
35
- it "does not blows up" do
36
- expect { body.readpartial }.to_not raise_error
37
- end
38
-
39
- it "calls underlying connection readpartial without specific size" do
40
- expect(connection).to receive(:readpartial).with no_args
41
- body.readpartial
42
- end
43
- end
44
-
45
- it "returns content in specified encoding" do
46
- body = described_class.new(connection)
47
- expect(connection).to receive(:readpartial).
48
- and_return(String.new("content", :encoding => Encoding::UTF_8))
49
- expect(body.readpartial.encoding).to eq Encoding::BINARY
50
-
51
- body = described_class.new(connection, :encoding => Encoding::UTF_8)
52
- expect(connection).to receive(:readpartial).
53
- and_return(String.new("content", :encoding => Encoding::BINARY))
54
- expect(body.readpartial.encoding).to eq Encoding::UTF_8
55
- end
56
- end
57
-
58
- context "when body is gzipped" do
59
- let(:chunks) do
60
- body = Zlib::Deflate.deflate("Hi, HTTP here ☺")
61
- len = body.length
62
- [body[0, len / 2], body[(len / 2)..]]
63
- end
64
- subject(:body) do
65
- inflater = HTTP::Response::Inflater.new(connection)
66
- described_class.new(inflater, :encoding => Encoding::UTF_8)
67
- end
68
-
69
- it "decodes body" do
70
- expect(subject.to_s).to eq("Hi, HTTP here ☺")
71
- end
72
-
73
- describe "#readpartial" do
74
- it "streams decoded body" do
75
- [
76
- "Hi, HTTP ",
77
- "here ☺",
78
- nil
79
- ].each do |part|
80
- expect(subject.readpartial).to eq(part)
81
- end
82
- end
83
- end
84
- end
85
- end