net-http 0.9.0 → 0.10.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/README.md +2 -0
- data/lib/net/http/generic_request.rb +10 -1
- data/lib/net/http/header.rb +56 -15
- data/lib/net/http/request.rb +1 -0
- data/lib/net/http/requests.rb +59 -24
- data/lib/net/http/response.rb +40 -15
- data/lib/net/http.rb +77 -16
- data/sig/manifest.yaml +3 -0
- data/sig/net-http.rbs +5635 -0
- metadata +70 -48
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7ef5db5bbe7d235bad14b04a257948207798e176d4f1d03029801615aa26823c
|
|
4
|
+
data.tar.gz: 1677b07e53a693f5d784a39e4d76a447868b5d435f3269561ccc772dd0345d10
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fd9e8e4ec27ff431f0a36acde5d6caecdebf34c5a625a6023b02bade546e7133bb6b12b3a0594d6cb3c5824577e093ef8677a209b9b35a2ee727b5b1906bf77e
|
|
7
|
+
data.tar.gz: b04a6747ae31dedd05716b221f9c9a6e668587cd025094f91f4b7c487feb85d769d4b8ff0d22ee55a79b96755324e447094579bf2306fc3acb363bb547e38b3d
|
data/README.md
CHANGED
|
@@ -81,6 +81,8 @@ res = Net::HTTP.post_form(uri, 'q' => ['ruby', 'perl'], 'max' => '50')
|
|
|
81
81
|
puts res.body
|
|
82
82
|
```
|
|
83
83
|
|
|
84
|
+
See the [documentation](https://docs.ruby-lang.org/en/master/Net/HTTP.html) for more details.
|
|
85
|
+
|
|
84
86
|
## Development
|
|
85
87
|
|
|
86
88
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
|
@@ -336,6 +336,9 @@ class Net::HTTPGenericRequest
|
|
|
336
336
|
boundary = opt[:boundary]
|
|
337
337
|
require 'securerandom' unless defined?(SecureRandom)
|
|
338
338
|
boundary ||= SecureRandom.urlsafe_base64(40)
|
|
339
|
+
if /[\r\n]/.match?(boundary.to_s)
|
|
340
|
+
raise ArgumentError, "multipart boundary cannot include CR/LF"
|
|
341
|
+
end
|
|
339
342
|
chunked_p = chunked?
|
|
340
343
|
|
|
341
344
|
buf = +''
|
|
@@ -349,7 +352,10 @@ class Net::HTTPGenericRequest
|
|
|
349
352
|
buf << "--#{boundary}\r\n"
|
|
350
353
|
if filename
|
|
351
354
|
filename = quote_string(filename, charset)
|
|
352
|
-
type = h[:content_type] || 'application/octet-stream'
|
|
355
|
+
type = (h[:content_type] || 'application/octet-stream').to_s
|
|
356
|
+
if /[\r\n]/.match?(type)
|
|
357
|
+
raise ArgumentError, "field content type cannot include CR/LF"
|
|
358
|
+
end
|
|
353
359
|
buf << "Content-Disposition: form-data; " \
|
|
354
360
|
"name=\"#{key}\"; filename=\"#{filename}\"\r\n" \
|
|
355
361
|
"Content-Type: #{type}\r\n\r\n"
|
|
@@ -384,6 +390,9 @@ class Net::HTTPGenericRequest
|
|
|
384
390
|
|
|
385
391
|
def quote_string(str, charset)
|
|
386
392
|
str = str.encode(charset, fallback:->(c){'&#%d;'%c.encode("UTF-8").ord}) if charset
|
|
393
|
+
if /[\r\n]/.match?(str)
|
|
394
|
+
raise ArgumentError, "multipart field name or filename cannot include CR/LF"
|
|
395
|
+
end
|
|
387
396
|
str.gsub(/[\\"]/, '\\\\\&')
|
|
388
397
|
end
|
|
389
398
|
|
data/lib/net/http/header.rb
CHANGED
|
@@ -193,11 +193,9 @@ module Net::HTTPHeader
|
|
|
193
193
|
warn "net/http: nil HTTP header: #{key}", uplevel: 3 if $VERBOSE
|
|
194
194
|
else
|
|
195
195
|
value = value.strip # raise error for invalid byte sequences
|
|
196
|
-
|
|
197
|
-
raise ArgumentError, "too long (#{key.bytesize} bytes) header: #{key[0, 30].inspect}..."
|
|
198
|
-
end
|
|
196
|
+
validate_field_name(key)
|
|
199
197
|
if value.to_s.bytesize > MAX_FIELD_LENGTH
|
|
200
|
-
raise ArgumentError, "header #{key} has too long field value: #{value.bytesize}"
|
|
198
|
+
raise ArgumentError, "header #{key} has too long field value: #{value.bytesize} bytes (limit #{MAX_FIELD_LENGTH})"
|
|
201
199
|
end
|
|
202
200
|
if value.count("\r\n") > 0
|
|
203
201
|
raise ArgumentError, "header #{key} has field value #{value.inspect}, this cannot include CR/LF"
|
|
@@ -263,21 +261,34 @@ module Net::HTTPHeader
|
|
|
263
261
|
def add_field(key, val)
|
|
264
262
|
stringified_downcased_key = key.downcase.to_s
|
|
265
263
|
if @header.key?(stringified_downcased_key)
|
|
266
|
-
append_field_value(@header[stringified_downcased_key], val)
|
|
264
|
+
append_field_value(@header[stringified_downcased_key], val, key)
|
|
267
265
|
else
|
|
268
266
|
set_field(key, val)
|
|
269
267
|
end
|
|
270
268
|
end
|
|
271
269
|
|
|
272
270
|
# :stopdoc:
|
|
271
|
+
private def validate_field_name(key)
|
|
272
|
+
if key.to_s.bytesize > MAX_KEY_LENGTH
|
|
273
|
+
raise ArgumentError, "too long (#{key.to_s.bytesize} bytes) header: #{key.to_s[0, 30].inspect}..."
|
|
274
|
+
end
|
|
275
|
+
if /[\x00-\x1f\x7f:]/n.match?(key.to_s.b)
|
|
276
|
+
raise ArgumentError, "header field name cannot include control characters or colon: #{key.to_s[0, 30].inspect}"
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
273
280
|
private def set_field(key, val)
|
|
281
|
+
validate_field_name(key)
|
|
274
282
|
case val
|
|
275
283
|
when Enumerable
|
|
276
284
|
ary = []
|
|
277
|
-
append_field_value(ary, val)
|
|
285
|
+
append_field_value(ary, val, key)
|
|
278
286
|
@header[key.downcase.to_s] = ary
|
|
279
287
|
else
|
|
280
288
|
val = val.to_s # for compatibility use to_s instead of to_str
|
|
289
|
+
if val.bytesize > MAX_FIELD_LENGTH
|
|
290
|
+
raise ArgumentError, "header #{key} has too long field value: #{val.bytesize} bytes (limit #{MAX_FIELD_LENGTH})"
|
|
291
|
+
end
|
|
281
292
|
if val.b.count("\r\n") > 0
|
|
282
293
|
raise ArgumentError, 'header field value cannot include CR/LF'
|
|
283
294
|
end
|
|
@@ -285,12 +296,15 @@ module Net::HTTPHeader
|
|
|
285
296
|
end
|
|
286
297
|
end
|
|
287
298
|
|
|
288
|
-
private def append_field_value(ary, val)
|
|
299
|
+
private def append_field_value(ary, val, key)
|
|
289
300
|
case val
|
|
290
301
|
when Enumerable
|
|
291
|
-
val.each{|x| append_field_value(ary, x)}
|
|
302
|
+
val.each{|x| append_field_value(ary, x, key)}
|
|
292
303
|
else
|
|
293
304
|
val = val.to_s
|
|
305
|
+
if val.bytesize > MAX_FIELD_LENGTH
|
|
306
|
+
raise ArgumentError, "header #{key} has too long field value: #{val.bytesize} bytes (limit #{MAX_FIELD_LENGTH})"
|
|
307
|
+
end
|
|
294
308
|
if /[\r\n]/n.match?(val.b)
|
|
295
309
|
raise ArgumentError, 'header field value cannot include CR/LF'
|
|
296
310
|
end
|
|
@@ -617,11 +631,35 @@ module Net::HTTPHeader
|
|
|
617
631
|
# res = Net::HTTP.get_response(hostname, '/todos/1')
|
|
618
632
|
# res.content_length # => nil
|
|
619
633
|
#
|
|
634
|
+
# The value must consist of digits only.
|
|
635
|
+
# Multiple <tt>'Content-Length'</tt> values are accepted
|
|
636
|
+
# only when they are all identical;
|
|
637
|
+
# otherwise Net::HTTPHeaderSyntaxError is raised.
|
|
638
|
+
# See {RFC 9110 Section 8.6}[https://www.rfc-editor.org/rfc/rfc9110.html#section-8.6].
|
|
620
639
|
def content_length
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
640
|
+
values = @header['content-length']
|
|
641
|
+
return nil if values.nil?
|
|
642
|
+
|
|
643
|
+
lengths = []
|
|
644
|
+
values.each do |value|
|
|
645
|
+
value = value.strip
|
|
646
|
+
if value.empty?
|
|
647
|
+
raise Net::HTTPHeaderSyntaxError,
|
|
648
|
+
"empty Content-Length value"
|
|
649
|
+
end
|
|
650
|
+
lengths.concat(value.split(/\s*,\s*/, -1))
|
|
651
|
+
end
|
|
652
|
+
if lengths.uniq.size != 1
|
|
653
|
+
raise Net::HTTPHeaderSyntaxError,
|
|
654
|
+
"Content-Length has multiple different values: " +
|
|
655
|
+
values.join(", ")
|
|
656
|
+
end
|
|
657
|
+
length = lengths.first
|
|
658
|
+
unless /\A\d+\z/.match?(length)
|
|
659
|
+
raise Net::HTTPHeaderSyntaxError,
|
|
660
|
+
"wrong Content-Length format: #{length}"
|
|
661
|
+
end
|
|
662
|
+
length.to_i
|
|
625
663
|
end
|
|
626
664
|
|
|
627
665
|
# Sets the value of field <tt>'Content-Length'</tt> to the given numeric;
|
|
@@ -647,7 +685,7 @@ module Net::HTTPHeader
|
|
|
647
685
|
end
|
|
648
686
|
|
|
649
687
|
# Returns +true+ if field <tt>'Transfer-Encoding'</tt>
|
|
650
|
-
# exists and has
|
|
688
|
+
# exists and has <tt>'chunked'</tt> as its final transfer coding,
|
|
651
689
|
# +false+ otherwise;
|
|
652
690
|
# see {Transfer-Encoding response header}[https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#transfer-encoding-response-header]:
|
|
653
691
|
#
|
|
@@ -655,10 +693,13 @@ module Net::HTTPHeader
|
|
|
655
693
|
# res['Transfer-Encoding'] # => "chunked"
|
|
656
694
|
# res.chunked? # => true
|
|
657
695
|
#
|
|
696
|
+
# <tt>'gzip, chunked'</tt> is chunked but <tt>'chunked, gzip'</tt> is not,
|
|
697
|
+
# because only the final transfer coding frames the message.
|
|
698
|
+
# See {RFC 9112 Section 6.3}[https://www.rfc-editor.org/rfc/rfc9112.html#section-6.3].
|
|
658
699
|
def chunked?
|
|
659
700
|
return false unless @header['transfer-encoding']
|
|
660
701
|
field = self['Transfer-Encoding']
|
|
661
|
-
(/(?:\A|[^\-\w])chunked(?![\-\w])/i =~ field) ? true : false
|
|
702
|
+
(/(?:\A|[^\-\w])chunked(?![\-\w])\s*(?:,\s*)*\z/i =~ field) ? true : false
|
|
662
703
|
end
|
|
663
704
|
|
|
664
705
|
# Returns a Range object representing the value of field
|
|
@@ -774,7 +815,7 @@ module Net::HTTPHeader
|
|
|
774
815
|
#
|
|
775
816
|
# Net::HTTPHeader#content_type= is an alias for Net::HTTPHeader#set_content_type.
|
|
776
817
|
def set_content_type(type, params = {})
|
|
777
|
-
|
|
818
|
+
set_field('Content-Type', type + params.map{|k,v|"; #{k}=#{v}"}.join(''))
|
|
778
819
|
end
|
|
779
820
|
|
|
780
821
|
alias content_type= set_content_type
|
data/lib/net/http/request.rb
CHANGED
data/lib/net/http/requests.rb
CHANGED
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
#
|
|
20
20
|
# - Request body: optional.
|
|
21
21
|
# - Response body: yes.
|
|
22
|
-
# - {Safe}[https://en.wikipedia.org/wiki/
|
|
23
|
-
# - {Idempotent}[https://en.wikipedia.org/wiki/
|
|
24
|
-
# - {Cacheable}[https://en.wikipedia.org/wiki/
|
|
22
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
|
|
23
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
|
|
24
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
|
|
25
25
|
#
|
|
26
26
|
# Related:
|
|
27
27
|
#
|
|
@@ -52,9 +52,9 @@ end
|
|
|
52
52
|
#
|
|
53
53
|
# - Request body: optional.
|
|
54
54
|
# - Response body: no.
|
|
55
|
-
# - {Safe}[https://en.wikipedia.org/wiki/
|
|
56
|
-
# - {Idempotent}[https://en.wikipedia.org/wiki/
|
|
57
|
-
# - {Cacheable}[https://en.wikipedia.org/wiki/
|
|
55
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
|
|
56
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
|
|
57
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
|
|
58
58
|
#
|
|
59
59
|
# Related:
|
|
60
60
|
#
|
|
@@ -87,9 +87,9 @@ end
|
|
|
87
87
|
#
|
|
88
88
|
# - Request body: yes.
|
|
89
89
|
# - Response body: yes.
|
|
90
|
-
# - {Safe}[https://en.wikipedia.org/wiki/
|
|
91
|
-
# - {Idempotent}[https://en.wikipedia.org/wiki/
|
|
92
|
-
# - {Cacheable}[https://en.wikipedia.org/wiki/
|
|
90
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
|
|
91
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
|
|
92
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
|
|
93
93
|
#
|
|
94
94
|
# Related:
|
|
95
95
|
#
|
|
@@ -123,9 +123,9 @@ end
|
|
|
123
123
|
#
|
|
124
124
|
# - Request body: yes.
|
|
125
125
|
# - Response body: yes.
|
|
126
|
-
# - {Safe}[https://en.wikipedia.org/wiki/
|
|
127
|
-
# - {Idempotent}[https://en.wikipedia.org/wiki/
|
|
128
|
-
# - {Cacheable}[https://en.wikipedia.org/wiki/
|
|
126
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
|
|
127
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
|
|
128
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
|
|
129
129
|
#
|
|
130
130
|
# Related:
|
|
131
131
|
#
|
|
@@ -157,9 +157,9 @@ end
|
|
|
157
157
|
#
|
|
158
158
|
# - Request body: optional.
|
|
159
159
|
# - Response body: yes.
|
|
160
|
-
# - {Safe}[https://en.wikipedia.org/wiki/
|
|
161
|
-
# - {Idempotent}[https://en.wikipedia.org/wiki/
|
|
162
|
-
# - {Cacheable}[https://en.wikipedia.org/wiki/
|
|
160
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
|
|
161
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
|
|
162
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
|
|
163
163
|
#
|
|
164
164
|
# Related:
|
|
165
165
|
#
|
|
@@ -189,9 +189,9 @@ end
|
|
|
189
189
|
#
|
|
190
190
|
# - Request body: optional.
|
|
191
191
|
# - Response body: yes.
|
|
192
|
-
# - {Safe}[https://en.wikipedia.org/wiki/
|
|
193
|
-
# - {Idempotent}[https://en.wikipedia.org/wiki/
|
|
194
|
-
# - {Cacheable}[https://en.wikipedia.org/wiki/
|
|
192
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
|
|
193
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
|
|
194
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
|
|
195
195
|
#
|
|
196
196
|
# Related:
|
|
197
197
|
#
|
|
@@ -221,9 +221,9 @@ end
|
|
|
221
221
|
#
|
|
222
222
|
# - Request body: no.
|
|
223
223
|
# - Response body: yes.
|
|
224
|
-
# - {Safe}[https://en.wikipedia.org/wiki/
|
|
225
|
-
# - {Idempotent}[https://en.wikipedia.org/wiki/
|
|
226
|
-
# - {Cacheable}[https://en.wikipedia.org/wiki/
|
|
224
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
|
|
225
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
|
|
226
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
|
|
227
227
|
#
|
|
228
228
|
# Related:
|
|
229
229
|
#
|
|
@@ -256,9 +256,9 @@ end
|
|
|
256
256
|
#
|
|
257
257
|
# - Request body: yes.
|
|
258
258
|
# - Response body: yes.
|
|
259
|
-
# - {Safe}[https://en.wikipedia.org/wiki/
|
|
260
|
-
# - {Idempotent}[https://en.wikipedia.org/wiki/
|
|
261
|
-
# - {Cacheable}[https://en.wikipedia.org/wiki/
|
|
259
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
|
|
260
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
|
|
261
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
|
|
262
262
|
#
|
|
263
263
|
# Related:
|
|
264
264
|
#
|
|
@@ -271,6 +271,41 @@ class Net::HTTP::Patch < Net::HTTPRequest
|
|
|
271
271
|
RESPONSE_HAS_BODY = true
|
|
272
272
|
end
|
|
273
273
|
|
|
274
|
+
# \Class for representing
|
|
275
|
+
# {HTTP method QUERY}[https://www.rfc-editor.org/rfc/rfc10008.html]:
|
|
276
|
+
#
|
|
277
|
+
# require 'net/http'
|
|
278
|
+
# uri = URI('http://example.com')
|
|
279
|
+
# hostname = uri.hostname # => "example.com"
|
|
280
|
+
# uri.path = '/posts'
|
|
281
|
+
# req = Net::HTTP::Query.new(uri) # => #<Net::HTTP::Query QUERY>
|
|
282
|
+
# req.body = '{"title": "foo","body": "bar","userId": 1}'
|
|
283
|
+
# req.content_type = 'application/json'
|
|
284
|
+
# res = Net::HTTP.start(hostname) do |http|
|
|
285
|
+
# http.request(req)
|
|
286
|
+
# end
|
|
287
|
+
#
|
|
288
|
+
# See {Request Headers}[rdoc-ref:Net::HTTPRequest@Request+Headers].
|
|
289
|
+
#
|
|
290
|
+
# Properties:
|
|
291
|
+
#
|
|
292
|
+
# - Request body: yes.
|
|
293
|
+
# - Response body: yes.
|
|
294
|
+
# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
|
|
295
|
+
# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
|
|
296
|
+
# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
|
|
297
|
+
#
|
|
298
|
+
# Related:
|
|
299
|
+
#
|
|
300
|
+
# - Net::HTTP#query: sends +QUERY+ request, returns response object.
|
|
301
|
+
#
|
|
302
|
+
class Net::HTTP::Query < Net::HTTPRequest
|
|
303
|
+
# :stopdoc:
|
|
304
|
+
METHOD = 'QUERY'
|
|
305
|
+
REQUEST_HAS_BODY = true
|
|
306
|
+
RESPONSE_HAS_BODY = true
|
|
307
|
+
end
|
|
308
|
+
|
|
274
309
|
#
|
|
275
310
|
# WebDAV methods --- RFC2518
|
|
276
311
|
#
|
data/lib/net/http/response.rb
CHANGED
|
@@ -133,6 +133,13 @@
|
|
|
133
133
|
# there is a protocol error.
|
|
134
134
|
#
|
|
135
135
|
class Net::HTTPResponse
|
|
136
|
+
# The maximum total size in bytes of the response header.
|
|
137
|
+
MAX_RESPONSE_HEADER_LENGTH = 1024 * 1024 # 1 MiB
|
|
138
|
+
|
|
139
|
+
# The maximum number of informational (1xx) responses accepted before the
|
|
140
|
+
# final response.
|
|
141
|
+
MAX_INFORMATIONAL_RESPONSES = 100
|
|
142
|
+
|
|
136
143
|
class << self
|
|
137
144
|
# true if the response has a body.
|
|
138
145
|
def body_permitted?
|
|
@@ -152,11 +159,17 @@ class Net::HTTPResponse
|
|
|
152
159
|
res
|
|
153
160
|
end
|
|
154
161
|
|
|
162
|
+
def read_line(sock, limit, ignore_eof = false) #:nodoc: internal use only
|
|
163
|
+
sock.readuntil("\n", ignore_eof, limit: limit)
|
|
164
|
+
rescue Net::ReadLimitExceeded
|
|
165
|
+
raise Net::HTTPBadResponse, 'response line too long'
|
|
166
|
+
end
|
|
167
|
+
|
|
155
168
|
private
|
|
156
169
|
# :stopdoc:
|
|
157
170
|
|
|
158
171
|
def read_status_line(sock)
|
|
159
|
-
str = sock.
|
|
172
|
+
str = read_line(sock, MAX_RESPONSE_HEADER_LENGTH).chop
|
|
160
173
|
m = /\AHTTP(?:\/(\d+\.\d+))?\s+(\d\d\d)(?:\s+(.*))?\z/in.match(str) or
|
|
161
174
|
raise Net::HTTPBadResponse, "wrong status line: #{str.dump}"
|
|
162
175
|
m.captures
|
|
@@ -170,12 +183,19 @@ class Net::HTTPResponse
|
|
|
170
183
|
|
|
171
184
|
def each_response_header(sock)
|
|
172
185
|
key = value = nil
|
|
186
|
+
remaining = MAX_RESPONSE_HEADER_LENGTH
|
|
173
187
|
while true
|
|
174
|
-
line = sock
|
|
188
|
+
line = read_line(sock, MAX_RESPONSE_HEADER_LENGTH, true)
|
|
189
|
+
remaining -= line.bytesize
|
|
190
|
+
raise Net::HTTPBadResponse, 'response header too large' if remaining < 0
|
|
191
|
+
line = line.chomp
|
|
175
192
|
break if line.empty?
|
|
176
193
|
if line[0] == ?\s or line[0] == ?\t and value
|
|
177
|
-
|
|
178
|
-
|
|
194
|
+
folded = line.strip
|
|
195
|
+
unless folded.empty?
|
|
196
|
+
value << ' ' unless value.empty?
|
|
197
|
+
value << folded
|
|
198
|
+
end
|
|
179
199
|
else
|
|
180
200
|
yield key, value if key
|
|
181
201
|
key, value = line.strip.split(/\s*:\s*/, 2)
|
|
@@ -599,15 +619,20 @@ class Net::HTTPResponse
|
|
|
599
619
|
|
|
600
620
|
@socket = inflate_body_io
|
|
601
621
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
622
|
+
# Transfer-Encoding overrides Content-Length, so a body that is not
|
|
623
|
+
# chunk-framed runs until the server closes the connection.
|
|
624
|
+
# See RFC 9112 Section 6.3.
|
|
625
|
+
unless @header['transfer-encoding']
|
|
626
|
+
clen = content_length()
|
|
627
|
+
if clen
|
|
628
|
+
@socket.read clen, dest, @ignore_eof
|
|
629
|
+
return
|
|
630
|
+
end
|
|
631
|
+
clen = range_length()
|
|
632
|
+
if clen
|
|
633
|
+
@socket.read clen, dest
|
|
634
|
+
return
|
|
635
|
+
end
|
|
611
636
|
end
|
|
612
637
|
@socket.read_all dest
|
|
613
638
|
end
|
|
@@ -623,7 +648,7 @@ class Net::HTTPResponse
|
|
|
623
648
|
def read_chunked(dest, chunk_data_io) # :nodoc:
|
|
624
649
|
total = 0
|
|
625
650
|
while true
|
|
626
|
-
line = @socket.
|
|
651
|
+
line = self.class.read_line(@socket, MAX_RESPONSE_HEADER_LENGTH).chop
|
|
627
652
|
hexlen = line.slice(/[0-9a-fA-F]+/) or
|
|
628
653
|
raise Net::HTTPBadResponse, "wrong chunk size line: #{line}"
|
|
629
654
|
len = hexlen.hex
|
|
@@ -635,7 +660,7 @@ class Net::HTTPResponse
|
|
|
635
660
|
@socket.read 2 # \r\n
|
|
636
661
|
end
|
|
637
662
|
end
|
|
638
|
-
until @socket.
|
|
663
|
+
until self.class.read_line(@socket, MAX_RESPONSE_HEADER_LENGTH).chop.empty?
|
|
639
664
|
# none
|
|
640
665
|
end
|
|
641
666
|
end
|