net-http 0.1.1 → 0.3.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/dependabot.yml +6 -0
- data/.github/workflows/test.yml +3 -5
- data/Gemfile +1 -0
- data/README.md +1 -1
- data/Rakefile +1 -1
- data/lib/net/http/backward.rb +26 -12
- data/lib/net/http/exceptions.rb +27 -26
- data/lib/net/http/generic_request.rb +6 -7
- data/lib/net/http/header.rb +3 -2
- data/lib/net/http/response.rb +176 -1
- data/lib/net/http/responses.rb +228 -223
- data/lib/net/http.rb +96 -39
- data/net-http.gemspec +0 -2
- metadata +4 -18
- data/Gemfile.lock +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 83d503ad3cfa67ad617fbfe5f168b22759f54eba460aceedba49245dd09d36d0
|
4
|
+
data.tar.gz: 57ae006e8c77d3d1bac46a6693e6377ad38e0d690669b9f1a2a447926e2a626b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 131cb53d9b3ae85db640cf78f1a43f660908cfd8f753cd41f5bea7179a92e5efd328e2f91fced1bc4e8cc69152ca9d95bc32544031cc79654c157f4573506a86
|
7
|
+
data.tar.gz: 3753128576e206b26a75f2828b5502cfc341854273f385a0771a988dfa69a6482351767f607d4bee211dbdac94937980b69c10c57e1cf69df41147a31621f2ce
|
data/.github/workflows/test.yml
CHANGED
@@ -7,18 +7,16 @@ jobs:
|
|
7
7
|
name: build (${{ matrix.ruby }} / ${{ matrix.os }})
|
8
8
|
strategy:
|
9
9
|
matrix:
|
10
|
-
ruby: [ 2.7, 2.6, head ]
|
10
|
+
ruby: [ 3.1, '3.0', 2.7, 2.6, head ]
|
11
11
|
os: [ ubuntu-latest, macos-latest ]
|
12
12
|
runs-on: ${{ matrix.os }}
|
13
13
|
steps:
|
14
|
-
- uses: actions/checkout@
|
14
|
+
- uses: actions/checkout@v3
|
15
15
|
- name: Set up Ruby
|
16
16
|
uses: ruby/setup-ruby@v1
|
17
17
|
with:
|
18
18
|
ruby-version: ${{ matrix.ruby }}
|
19
19
|
- name: Install dependencies
|
20
|
-
run:
|
21
|
-
gem install bundler --no-document
|
22
|
-
bundle install
|
20
|
+
run: bundle install
|
23
21
|
- name: Run test
|
24
22
|
run: rake test
|
data/Gemfile
CHANGED
data/README.md
CHANGED
data/Rakefile
CHANGED
@@ -9,7 +9,7 @@ end
|
|
9
9
|
|
10
10
|
task :sync_tool do
|
11
11
|
require 'fileutils'
|
12
|
-
FileUtils.cp "../ruby/tool/lib/
|
12
|
+
FileUtils.cp "../ruby/tool/lib/core_assertions.rb", "./test/lib"
|
13
13
|
FileUtils.cp "../ruby/tool/lib/envutil.rb", "./test/lib"
|
14
14
|
FileUtils.cp "../ruby/tool/lib/find_executable.rb", "./test/lib"
|
15
15
|
end
|
data/lib/net/http/backward.rb
CHANGED
@@ -5,22 +5,36 @@
|
|
5
5
|
|
6
6
|
class Net::HTTP
|
7
7
|
ProxyMod = ProxyDelta
|
8
|
-
|
9
|
-
|
10
|
-
module Net
|
11
|
-
HTTPSession = Net::HTTP
|
8
|
+
deprecate_constant :ProxyMod
|
12
9
|
end
|
13
10
|
|
14
11
|
module Net::NetPrivate
|
15
12
|
HTTPRequest = ::Net::HTTPRequest
|
13
|
+
deprecate_constant :HTTPRequest
|
16
14
|
end
|
17
15
|
|
18
|
-
|
19
|
-
|
20
|
-
Net::HTTPRedirectionCode = Net::HTTPRedirection
|
21
|
-
Net::HTTPRetriableCode = Net::HTTPRedirection
|
22
|
-
Net::HTTPClientErrorCode = Net::HTTPClientError
|
23
|
-
Net::HTTPFatalErrorCode = Net::HTTPClientError
|
24
|
-
Net::HTTPServerErrorCode = Net::HTTPServerError
|
25
|
-
Net::HTTPResponceReceiver = Net::HTTPResponse
|
16
|
+
module Net
|
17
|
+
HTTPSession = HTTP
|
26
18
|
|
19
|
+
HTTPInformationCode = HTTPInformation
|
20
|
+
HTTPSuccessCode = HTTPSuccess
|
21
|
+
HTTPRedirectionCode = HTTPRedirection
|
22
|
+
HTTPRetriableCode = HTTPRedirection
|
23
|
+
HTTPClientErrorCode = HTTPClientError
|
24
|
+
HTTPFatalErrorCode = HTTPClientError
|
25
|
+
HTTPServerErrorCode = HTTPServerError
|
26
|
+
HTTPResponseReceiver = HTTPResponse
|
27
|
+
|
28
|
+
HTTPResponceReceiver = HTTPResponse # Typo since 2001
|
29
|
+
|
30
|
+
deprecate_constant :HTTPSession,
|
31
|
+
:HTTPInformationCode,
|
32
|
+
:HTTPSuccessCode,
|
33
|
+
:HTTPRedirectionCode,
|
34
|
+
:HTTPRetriableCode,
|
35
|
+
:HTTPClientErrorCode,
|
36
|
+
:HTTPFatalErrorCode,
|
37
|
+
:HTTPServerErrorCode,
|
38
|
+
:HTTPResponseReceiver,
|
39
|
+
:HTTPResponceReceiver
|
40
|
+
end
|
data/lib/net/http/exceptions.rb
CHANGED
@@ -1,33 +1,34 @@
|
|
1
1
|
# frozen_string_literal: false
|
2
|
-
|
3
|
-
#
|
4
|
-
#
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
module Net
|
3
|
+
# Net::HTTP exception class.
|
4
|
+
# You cannot use Net::HTTPExceptions directly; instead, you must use
|
5
|
+
# its subclasses.
|
6
|
+
module HTTPExceptions
|
7
|
+
def initialize(msg, res) #:nodoc:
|
8
|
+
super msg
|
9
|
+
@response = res
|
10
|
+
end
|
11
|
+
attr_reader :response
|
12
|
+
alias data response #:nodoc: obsolete
|
9
13
|
end
|
10
|
-
attr_reader :response
|
11
|
-
alias data response #:nodoc: obsolete
|
12
|
-
end
|
13
|
-
class Net::HTTPError < Net::ProtocolError
|
14
|
-
include Net::HTTPExceptions
|
15
|
-
end
|
16
|
-
class Net::HTTPRetriableError < Net::ProtoRetriableError
|
17
|
-
include Net::HTTPExceptions
|
18
|
-
end
|
19
|
-
class Net::HTTPServerException < Net::ProtoServerError
|
20
|
-
# We cannot use the name "HTTPServerError", it is the name of the response.
|
21
|
-
include Net::HTTPExceptions
|
22
|
-
end
|
23
14
|
|
24
|
-
|
25
|
-
|
15
|
+
class HTTPError < ProtocolError
|
16
|
+
include HTTPExceptions
|
17
|
+
end
|
26
18
|
|
27
|
-
class
|
28
|
-
|
29
|
-
end
|
19
|
+
class HTTPRetriableError < ProtoRetriableError
|
20
|
+
include HTTPExceptions
|
21
|
+
end
|
30
22
|
|
31
|
-
|
23
|
+
class HTTPClientException < ProtoServerError
|
24
|
+
include HTTPExceptions
|
25
|
+
end
|
26
|
+
|
27
|
+
class HTTPFatalError < ProtoFatalError
|
28
|
+
include HTTPExceptions
|
29
|
+
end
|
30
|
+
|
31
|
+
# We cannot use the name "HTTPServerError", it is the name of the response.
|
32
|
+
HTTPServerException = HTTPClientException # :nodoc:
|
32
33
|
deprecate_constant(:HTTPServerException)
|
33
34
|
end
|
@@ -15,7 +15,8 @@ class Net::HTTPGenericRequest
|
|
15
15
|
|
16
16
|
if URI === uri_or_path then
|
17
17
|
raise ArgumentError, "not an HTTP URI" unless URI::HTTP === uri_or_path
|
18
|
-
|
18
|
+
hostname = uri_or_path.hostname
|
19
|
+
raise ArgumentError, "no host component for URI" unless (hostname && hostname.length > 0)
|
19
20
|
@uri = uri_or_path.dup
|
20
21
|
host = @uri.hostname.dup
|
21
22
|
host << ":".freeze << @uri.port.to_s if @uri.port != @uri.default_port
|
@@ -31,12 +32,12 @@ class Net::HTTPGenericRequest
|
|
31
32
|
|
32
33
|
@decode_content = false
|
33
34
|
|
34
|
-
if
|
35
|
+
if Net::HTTP::HAVE_ZLIB then
|
35
36
|
if !initheader ||
|
36
37
|
!initheader.keys.any? { |k|
|
37
38
|
%w[accept-encoding range].include? k.downcase
|
38
39
|
} then
|
39
|
-
@decode_content = true
|
40
|
+
@decode_content = true if @response_has_body
|
40
41
|
initheader = initheader ? initheader.dup : {}
|
41
42
|
initheader["accept-encoding"] =
|
42
43
|
"gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
|
@@ -143,7 +144,7 @@ class Net::HTTPGenericRequest
|
|
143
144
|
end
|
144
145
|
|
145
146
|
if host = self['host']
|
146
|
-
host.sub!(/:.*/
|
147
|
+
host.sub!(/:.*/m, ''.freeze)
|
147
148
|
elsif host = @uri.host
|
148
149
|
else
|
149
150
|
host = addr
|
@@ -202,9 +203,7 @@ class Net::HTTPGenericRequest
|
|
202
203
|
IO.copy_stream(f, chunker)
|
203
204
|
chunker.finish
|
204
205
|
else
|
205
|
-
|
206
|
-
# If sock.io is an SSLSocket, copy_stream will hit SSL_write()
|
207
|
-
IO.copy_stream(f, sock.io)
|
206
|
+
IO.copy_stream(f, sock)
|
208
207
|
end
|
209
208
|
end
|
210
209
|
|
data/lib/net/http/header.rb
CHANGED
@@ -338,9 +338,10 @@ module Net::HTTPHeader
|
|
338
338
|
# fits inside the full entity body, as range of byte offsets.
|
339
339
|
def content_range
|
340
340
|
return nil unless @header['content-range']
|
341
|
-
m = %r
|
341
|
+
m = %r<\A\s*(\w+)\s+(\d+)-(\d+)/(\d+|\*)>.match(self['Content-Range']) or
|
342
342
|
raise Net::HTTPHeaderSyntaxError, 'wrong Content-Range format'
|
343
|
-
m[1]
|
343
|
+
return unless m[1] == 'bytes'
|
344
|
+
m[2].to_i .. m[3].to_i
|
344
345
|
end
|
345
346
|
|
346
347
|
# The length of the range represented in Content-Range: header.
|
data/lib/net/http/response.rb
CHANGED
@@ -84,6 +84,8 @@ class Net::HTTPResponse
|
|
84
84
|
@read = false
|
85
85
|
@uri = nil
|
86
86
|
@decode_content = false
|
87
|
+
@body_encoding = false
|
88
|
+
@ignore_eof = true
|
87
89
|
end
|
88
90
|
|
89
91
|
# The HTTP version supported by the server.
|
@@ -106,6 +108,22 @@ class Net::HTTPResponse
|
|
106
108
|
# Accept-Encoding header from the user.
|
107
109
|
attr_accessor :decode_content
|
108
110
|
|
111
|
+
# The encoding to use for the response body. If Encoding, use that encoding.
|
112
|
+
# If other true value, attempt to detect the appropriate encoding, and use
|
113
|
+
# that.
|
114
|
+
attr_reader :body_encoding
|
115
|
+
|
116
|
+
# Set the encoding to use for the response body. If given a String, find
|
117
|
+
# the related Encoding.
|
118
|
+
def body_encoding=(value)
|
119
|
+
value = Encoding.find(value) if value.is_a?(String)
|
120
|
+
@body_encoding = value
|
121
|
+
end
|
122
|
+
|
123
|
+
# Whether to ignore EOF when reading bodies with a specified Content-Length
|
124
|
+
# header.
|
125
|
+
attr_accessor :ignore_eof
|
126
|
+
|
109
127
|
def inspect
|
110
128
|
"#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
|
111
129
|
end
|
@@ -214,6 +232,17 @@ class Net::HTTPResponse
|
|
214
232
|
end
|
215
233
|
@read = true
|
216
234
|
|
235
|
+
case enc = @body_encoding
|
236
|
+
when Encoding, false, nil
|
237
|
+
# Encoding: force given encoding
|
238
|
+
# false/nil: do not force encoding
|
239
|
+
else
|
240
|
+
# other value: detect encoding from body
|
241
|
+
enc = detect_encoding(@body)
|
242
|
+
end
|
243
|
+
|
244
|
+
@body.force_encoding(enc) if enc
|
245
|
+
|
217
246
|
@body
|
218
247
|
end
|
219
248
|
|
@@ -245,6 +274,141 @@ class Net::HTTPResponse
|
|
245
274
|
|
246
275
|
private
|
247
276
|
|
277
|
+
# :nodoc:
|
278
|
+
def detect_encoding(str, encoding=nil)
|
279
|
+
if encoding
|
280
|
+
elsif encoding = type_params['charset']
|
281
|
+
elsif encoding = check_bom(str)
|
282
|
+
else
|
283
|
+
encoding = case content_type&.downcase
|
284
|
+
when %r{text/x(?:ht)?ml|application/(?:[^+]+\+)?xml}
|
285
|
+
/\A<xml[ \t\r\n]+
|
286
|
+
version[ \t\r\n]*=[ \t\r\n]*(?:"[0-9.]+"|'[0-9.]*')[ \t\r\n]+
|
287
|
+
encoding[ \t\r\n]*=[ \t\r\n]*
|
288
|
+
(?:"([A-Za-z][\-A-Za-z0-9._]*)"|'([A-Za-z][\-A-Za-z0-9._]*)')/x =~ str
|
289
|
+
encoding = $1 || $2 || Encoding::UTF_8
|
290
|
+
when %r{text/html.*}
|
291
|
+
sniff_encoding(str)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
return encoding
|
295
|
+
end
|
296
|
+
|
297
|
+
# :nodoc:
|
298
|
+
def sniff_encoding(str, encoding=nil)
|
299
|
+
# the encoding sniffing algorithm
|
300
|
+
# http://www.w3.org/TR/html5/parsing.html#determining-the-character-encoding
|
301
|
+
if enc = scanning_meta(str)
|
302
|
+
enc
|
303
|
+
# 6. last visited page or something
|
304
|
+
# 7. frequency
|
305
|
+
elsif str.ascii_only?
|
306
|
+
Encoding::US_ASCII
|
307
|
+
elsif str.dup.force_encoding(Encoding::UTF_8).valid_encoding?
|
308
|
+
Encoding::UTF_8
|
309
|
+
end
|
310
|
+
# 8. implementation-defined or user-specified
|
311
|
+
end
|
312
|
+
|
313
|
+
# :nodoc:
|
314
|
+
def check_bom(str)
|
315
|
+
case str.byteslice(0, 2)
|
316
|
+
when "\xFE\xFF"
|
317
|
+
return Encoding::UTF_16BE
|
318
|
+
when "\xFF\xFE"
|
319
|
+
return Encoding::UTF_16LE
|
320
|
+
end
|
321
|
+
if "\xEF\xBB\xBF" == str.byteslice(0, 3)
|
322
|
+
return Encoding::UTF_8
|
323
|
+
end
|
324
|
+
nil
|
325
|
+
end
|
326
|
+
|
327
|
+
# :nodoc:
|
328
|
+
def scanning_meta(str)
|
329
|
+
require 'strscan'
|
330
|
+
ss = StringScanner.new(str)
|
331
|
+
if ss.scan_until(/<meta[\t\n\f\r ]*/)
|
332
|
+
attrs = {} # attribute_list
|
333
|
+
got_pragma = false
|
334
|
+
need_pragma = nil
|
335
|
+
charset = nil
|
336
|
+
|
337
|
+
# step: Attributes
|
338
|
+
while attr = get_attribute(ss)
|
339
|
+
name, value = *attr
|
340
|
+
next if attrs[name]
|
341
|
+
attrs[name] = true
|
342
|
+
case name
|
343
|
+
when 'http-equiv'
|
344
|
+
got_pragma = true if value == 'content-type'
|
345
|
+
when 'content'
|
346
|
+
encoding = extracting_encodings_from_meta_elements(value)
|
347
|
+
unless charset
|
348
|
+
charset = encoding
|
349
|
+
end
|
350
|
+
need_pragma = true
|
351
|
+
when 'charset'
|
352
|
+
need_pragma = false
|
353
|
+
charset = value
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
# step: Processing
|
358
|
+
return if need_pragma.nil?
|
359
|
+
return if need_pragma && !got_pragma
|
360
|
+
|
361
|
+
charset = Encoding.find(charset) rescue nil
|
362
|
+
return unless charset
|
363
|
+
charset = Encoding::UTF_8 if charset == Encoding::UTF_16
|
364
|
+
return charset # tentative
|
365
|
+
end
|
366
|
+
nil
|
367
|
+
end
|
368
|
+
|
369
|
+
def get_attribute(ss)
|
370
|
+
ss.scan(/[\t\n\f\r \/]*/)
|
371
|
+
if ss.peek(1) == '>'
|
372
|
+
ss.getch
|
373
|
+
return nil
|
374
|
+
end
|
375
|
+
name = ss.scan(/[^=\t\n\f\r \/>]*/)
|
376
|
+
name.downcase!
|
377
|
+
raise if name.empty?
|
378
|
+
ss.skip(/[\t\n\f\r ]*/)
|
379
|
+
if ss.getch != '='
|
380
|
+
value = ''
|
381
|
+
return [name, value]
|
382
|
+
end
|
383
|
+
ss.skip(/[\t\n\f\r ]*/)
|
384
|
+
case ss.peek(1)
|
385
|
+
when '"'
|
386
|
+
ss.getch
|
387
|
+
value = ss.scan(/[^"]+/)
|
388
|
+
value.downcase!
|
389
|
+
ss.getch
|
390
|
+
when "'"
|
391
|
+
ss.getch
|
392
|
+
value = ss.scan(/[^']+/)
|
393
|
+
value.downcase!
|
394
|
+
ss.getch
|
395
|
+
when '>'
|
396
|
+
value = ''
|
397
|
+
else
|
398
|
+
value = ss.scan(/[^\t\n\f\r >]+/)
|
399
|
+
value.downcase!
|
400
|
+
end
|
401
|
+
[name, value]
|
402
|
+
end
|
403
|
+
|
404
|
+
def extracting_encodings_from_meta_elements(value)
|
405
|
+
# http://dev.w3.org/html5/spec/fetching-resources.html#algorithm-for-extracting-an-encoding-from-a-meta-element
|
406
|
+
if /charset[\t\n\f\r ]*=(?:"([^"]*)"|'([^']*)'|["']|\z|([^\t\n\f\r ;]+))/i =~ value
|
407
|
+
return $1 || $2 || $3
|
408
|
+
end
|
409
|
+
return nil
|
410
|
+
end
|
411
|
+
|
248
412
|
##
|
249
413
|
# Checks for a supported Content-Encoding header and yields an Inflate
|
250
414
|
# wrapper for this response's socket when zlib is present. If the
|
@@ -272,6 +436,9 @@ class Net::HTTPResponse
|
|
272
436
|
ensure
|
273
437
|
begin
|
274
438
|
inflate_body_io.finish
|
439
|
+
if self['content-length']
|
440
|
+
self['content-length'] = inflate_body_io.bytes_inflated.to_s
|
441
|
+
end
|
275
442
|
rescue => err
|
276
443
|
# Ignore #finish's error if there is an exception from yield
|
277
444
|
raise err if success
|
@@ -297,7 +464,7 @@ class Net::HTTPResponse
|
|
297
464
|
|
298
465
|
clen = content_length()
|
299
466
|
if clen
|
300
|
-
@socket.read clen, dest,
|
467
|
+
@socket.read clen, dest, @ignore_eof
|
301
468
|
return
|
302
469
|
end
|
303
470
|
clen = range_length()
|
@@ -373,6 +540,14 @@ class Net::HTTPResponse
|
|
373
540
|
@inflate.finish
|
374
541
|
end
|
375
542
|
|
543
|
+
##
|
544
|
+
# The number of bytes inflated, used to update the Content-Length of
|
545
|
+
# the response.
|
546
|
+
|
547
|
+
def bytes_inflated
|
548
|
+
@inflate.total_out
|
549
|
+
end
|
550
|
+
|
376
551
|
##
|
377
552
|
# Returns a Net::ReadAdapter that inflates each read chunk into +dest+.
|
378
553
|
#
|