net-http 0.1.1 → 0.2.2
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/generic_request.rb +4 -6
- data/lib/net/http/response.rb +176 -1
- data/lib/net/http.rb +100 -37
- 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: ee3df6b6afad0f163708cc0fc0f0a16f4a3b394b56c3c389c55a55274f38c3e7
|
4
|
+
data.tar.gz: 17a0329a4c031e923cd597af5abcd31d08a853ffbb9d9a58308f6bb44b02b88d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 27b412cb8ea24d0a24bc5f3a835cef426481ca6f921323629b0bbabf0b9752373c5f6904179984068fd8a1e7c666f29c989636baa43989a835259252a0278eef
|
7
|
+
data.tar.gz: 52772055904e6f294fb72a13d270b269b37dc3b588c91afe517e3ea74fb639aac6b6586092cb1fa1de65eb9c518290e79ddde3b6804e65b5b532233d295e0d38
|
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
|
@@ -31,12 +31,12 @@ class Net::HTTPGenericRequest
|
|
31
31
|
|
32
32
|
@decode_content = false
|
33
33
|
|
34
|
-
if
|
34
|
+
if Net::HTTP::HAVE_ZLIB then
|
35
35
|
if !initheader ||
|
36
36
|
!initheader.keys.any? { |k|
|
37
37
|
%w[accept-encoding range].include? k.downcase
|
38
38
|
} then
|
39
|
-
@decode_content = true
|
39
|
+
@decode_content = true if @response_has_body
|
40
40
|
initheader = initheader ? initheader.dup : {}
|
41
41
|
initheader["accept-encoding"] =
|
42
42
|
"gzip;q=1.0,deflate;q=0.6,identity;q=0.3"
|
@@ -143,7 +143,7 @@ class Net::HTTPGenericRequest
|
|
143
143
|
end
|
144
144
|
|
145
145
|
if host = self['host']
|
146
|
-
host.sub!(/:.*/
|
146
|
+
host.sub!(/:.*/m, ''.freeze)
|
147
147
|
elsif host = @uri.host
|
148
148
|
else
|
149
149
|
host = addr
|
@@ -202,9 +202,7 @@ class Net::HTTPGenericRequest
|
|
202
202
|
IO.copy_stream(f, chunker)
|
203
203
|
chunker.finish
|
204
204
|
else
|
205
|
-
|
206
|
-
# If sock.io is an SSLSocket, copy_stream will hit SSL_write()
|
207
|
-
IO.copy_stream(f, sock.io)
|
205
|
+
IO.copy_stream(f, sock)
|
208
206
|
end
|
209
207
|
end
|
210
208
|
|
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
|
#
|
data/lib/net/http.rb
CHANGED
@@ -22,6 +22,7 @@
|
|
22
22
|
|
23
23
|
require 'net/protocol'
|
24
24
|
require 'uri'
|
25
|
+
require 'resolv'
|
25
26
|
autoload :OpenSSL, 'openssl'
|
26
27
|
|
27
28
|
module Net #:nodoc:
|
@@ -327,6 +328,8 @@ module Net #:nodoc:
|
|
327
328
|
# HTTPInformation:: 1xx
|
328
329
|
# HTTPContinue:: 100
|
329
330
|
# HTTPSwitchProtocol:: 101
|
331
|
+
# HTTPProcessing:: 102
|
332
|
+
# HTTPEarlyHints:: 103
|
330
333
|
# HTTPSuccess:: 2xx
|
331
334
|
# HTTPOK:: 200
|
332
335
|
# HTTPCreated:: 201
|
@@ -336,6 +339,7 @@ module Net #:nodoc:
|
|
336
339
|
# HTTPResetContent:: 205
|
337
340
|
# HTTPPartialContent:: 206
|
338
341
|
# HTTPMultiStatus:: 207
|
342
|
+
# HTTPAlreadyReported:: 208
|
339
343
|
# HTTPIMUsed:: 226
|
340
344
|
# HTTPRedirection:: 3xx
|
341
345
|
# HTTPMultipleChoices:: 300
|
@@ -345,6 +349,7 @@ module Net #:nodoc:
|
|
345
349
|
# HTTPNotModified:: 304
|
346
350
|
# HTTPUseProxy:: 305
|
347
351
|
# HTTPTemporaryRedirect:: 307
|
352
|
+
# HTTPPermanentRedirect:: 308
|
348
353
|
# HTTPClientError:: 4xx
|
349
354
|
# HTTPBadRequest:: 400
|
350
355
|
# HTTPUnauthorized:: 401
|
@@ -364,6 +369,7 @@ module Net #:nodoc:
|
|
364
369
|
# HTTPUnsupportedMediaType:: 415
|
365
370
|
# HTTPRequestedRangeNotSatisfiable:: 416
|
366
371
|
# HTTPExpectationFailed:: 417
|
372
|
+
# HTTPMisdirectedRequest:: 421
|
367
373
|
# HTTPUnprocessableEntity:: 422
|
368
374
|
# HTTPLocked:: 423
|
369
375
|
# HTTPFailedDependency:: 424
|
@@ -379,7 +385,10 @@ module Net #:nodoc:
|
|
379
385
|
# HTTPServiceUnavailable:: 503
|
380
386
|
# HTTPGatewayTimeOut:: 504
|
381
387
|
# HTTPVersionNotSupported:: 505
|
388
|
+
# HTTPVariantAlsoNegotiates:: 506
|
382
389
|
# HTTPInsufficientStorage:: 507
|
390
|
+
# HTTPLoopDetected:: 508
|
391
|
+
# HTTPNotExtended:: 510
|
383
392
|
# HTTPNetworkAuthenticationRequired:: 511
|
384
393
|
#
|
385
394
|
# There is also the Net::HTTPBadResponse exception which is raised when
|
@@ -388,12 +397,11 @@ module Net #:nodoc:
|
|
388
397
|
class HTTP < Protocol
|
389
398
|
|
390
399
|
# :stopdoc:
|
391
|
-
VERSION = "0.
|
400
|
+
VERSION = "0.2.2"
|
392
401
|
Revision = %q$Revision$.split[1]
|
393
402
|
HTTPVersion = '1.1'
|
394
403
|
begin
|
395
404
|
require 'zlib'
|
396
|
-
require 'stringio' #for our purposes (unpacking gzip) lump these together
|
397
405
|
HAVE_ZLIB=true
|
398
406
|
rescue LoadError
|
399
407
|
HAVE_ZLIB=false
|
@@ -524,14 +532,13 @@ module Net #:nodoc:
|
|
524
532
|
#
|
525
533
|
# { "cmd" => "search", "q" => "ruby", "max" => "50" }
|
526
534
|
#
|
527
|
-
# This method also does Basic Authentication
|
535
|
+
# This method also does Basic Authentication if and only if +url+.user exists.
|
528
536
|
# But userinfo for authentication is deprecated (RFC3986).
|
529
537
|
# So this feature will be removed.
|
530
538
|
#
|
531
539
|
# Example:
|
532
540
|
#
|
533
541
|
# require 'net/http'
|
534
|
-
# require 'uri'
|
535
542
|
#
|
536
543
|
# Net::HTTP.post_form URI('http://www.example.com/search.cgi'),
|
537
544
|
# { "q" => "ruby", "max" => "50" }
|
@@ -691,6 +698,8 @@ module Net #:nodoc:
|
|
691
698
|
@continue_timeout = nil
|
692
699
|
@max_retries = 1
|
693
700
|
@debug_output = nil
|
701
|
+
@response_body_encoding = false
|
702
|
+
@ignore_eof = true
|
694
703
|
|
695
704
|
@proxy_from_env = false
|
696
705
|
@proxy_uri = nil
|
@@ -738,6 +747,18 @@ module Net #:nodoc:
|
|
738
747
|
# The local port used to establish the connection.
|
739
748
|
attr_accessor :local_port
|
740
749
|
|
750
|
+
# The encoding to use for the response body. If Encoding, uses the
|
751
|
+
# specified encoding. If other true value, tries to detect the response
|
752
|
+
# body encoding.
|
753
|
+
attr_reader :response_body_encoding
|
754
|
+
|
755
|
+
# Set the encoding to use for the response body. If given a String, find
|
756
|
+
# the related Encoding.
|
757
|
+
def response_body_encoding=(value)
|
758
|
+
value = Encoding.find(value) if value.is_a?(String)
|
759
|
+
@response_body_encoding = value
|
760
|
+
end
|
761
|
+
|
741
762
|
attr_writer :proxy_from_env
|
742
763
|
attr_writer :proxy_address
|
743
764
|
attr_writer :proxy_port
|
@@ -819,6 +840,10 @@ module Net #:nodoc:
|
|
819
840
|
# The default value is 2 seconds.
|
820
841
|
attr_accessor :keep_alive_timeout
|
821
842
|
|
843
|
+
# Whether to ignore EOF when reading response bodies with defined
|
844
|
+
# Content-Length headers. For backwards compatibility, the default is true.
|
845
|
+
attr_accessor :ignore_eof
|
846
|
+
|
822
847
|
# Returns true if the HTTP session has been started.
|
823
848
|
def started?
|
824
849
|
@started
|
@@ -973,6 +998,12 @@ module Net #:nodoc:
|
|
973
998
|
private :do_start
|
974
999
|
|
975
1000
|
def connect
|
1001
|
+
if use_ssl?
|
1002
|
+
# reference early to load OpenSSL before connecting,
|
1003
|
+
# as OpenSSL may take time to load.
|
1004
|
+
@ssl_context = OpenSSL::SSL::SSLContext.new
|
1005
|
+
end
|
1006
|
+
|
976
1007
|
if proxy? then
|
977
1008
|
conn_addr = proxy_address
|
978
1009
|
conn_port = proxy_port
|
@@ -981,17 +1012,16 @@ module Net #:nodoc:
|
|
981
1012
|
conn_port = port
|
982
1013
|
end
|
983
1014
|
|
984
|
-
|
985
|
-
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
}
|
1015
|
+
debug "opening connection to #{conn_addr}:#{conn_port}..."
|
1016
|
+
begin
|
1017
|
+
s = Socket.tcp conn_addr, conn_port, @local_host, @local_port, connect_timeout: @open_timeout
|
1018
|
+
rescue => e
|
1019
|
+
e = Net::OpenTimeout.new(e) if e.is_a?(Errno::ETIMEDOUT) #for compatibility with previous versions
|
1020
|
+
raise e, "Failed to open TCP connection to " +
|
1021
|
+
"#{conn_addr}:#{conn_port} (#{e.message})"
|
1022
|
+
end
|
993
1023
|
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
994
|
-
|
1024
|
+
debug "opened"
|
995
1025
|
if use_ssl?
|
996
1026
|
if proxy?
|
997
1027
|
plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
|
@@ -1020,35 +1050,56 @@ module Net #:nodoc:
|
|
1020
1050
|
end
|
1021
1051
|
end
|
1022
1052
|
end
|
1023
|
-
@ssl_context = OpenSSL::SSL::SSLContext.new
|
1024
1053
|
@ssl_context.set_params(ssl_parameters)
|
1025
|
-
@ssl_context.session_cache_mode
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1054
|
+
unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
|
1055
|
+
@ssl_context.session_cache_mode =
|
1056
|
+
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
|
1057
|
+
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
|
1058
|
+
end
|
1059
|
+
if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
|
1060
|
+
@ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
|
1061
|
+
end
|
1062
|
+
|
1063
|
+
# Still do the post_connection_check below even if connecting
|
1064
|
+
# to IP address
|
1065
|
+
verify_hostname = @ssl_context.verify_hostname
|
1066
|
+
|
1067
|
+
# Server Name Indication (SNI) RFC 3546/6066
|
1068
|
+
case @address
|
1069
|
+
when Resolv::IPv4::Regex, Resolv::IPv6::Regex
|
1070
|
+
# don't set SNI, as IP addresses in SNI is not valid
|
1071
|
+
# per RFC 6066, section 3.
|
1072
|
+
|
1073
|
+
# Avoid openssl warning
|
1074
|
+
@ssl_context.verify_hostname = false
|
1075
|
+
else
|
1076
|
+
ssl_host_address = @address
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
debug "starting SSL for #{conn_addr}:#{conn_port}..."
|
1030
1080
|
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
|
1031
1081
|
s.sync_close = true
|
1032
|
-
|
1033
|
-
|
1082
|
+
s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
|
1083
|
+
|
1034
1084
|
if @ssl_session and
|
1035
1085
|
Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
|
1036
1086
|
s.session = @ssl_session
|
1037
1087
|
end
|
1038
1088
|
ssl_socket_connect(s, @open_timeout)
|
1039
|
-
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) &&
|
1089
|
+
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
|
1040
1090
|
s.post_connection_check(@address)
|
1041
1091
|
end
|
1042
|
-
|
1092
|
+
debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
|
1043
1093
|
end
|
1044
1094
|
@socket = BufferedIO.new(s, read_timeout: @read_timeout,
|
1045
1095
|
write_timeout: @write_timeout,
|
1046
1096
|
continue_timeout: @continue_timeout,
|
1047
1097
|
debug_output: @debug_output)
|
1098
|
+
@last_communicated = nil
|
1048
1099
|
on_connect
|
1049
1100
|
rescue => exception
|
1050
1101
|
if s
|
1051
|
-
|
1102
|
+
debug "Conn close because of connect error #{exception}"
|
1052
1103
|
s.close
|
1053
1104
|
end
|
1054
1105
|
raise
|
@@ -1180,7 +1231,8 @@ module Net #:nodoc:
|
|
1180
1231
|
# The username of the proxy server, if one is configured.
|
1181
1232
|
def proxy_user
|
1182
1233
|
if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env
|
1183
|
-
proxy_uri&.user
|
1234
|
+
user = proxy_uri&.user
|
1235
|
+
unescape(user) if user
|
1184
1236
|
else
|
1185
1237
|
@proxy_user
|
1186
1238
|
end
|
@@ -1189,7 +1241,8 @@ module Net #:nodoc:
|
|
1189
1241
|
# The password of the proxy server, if one is configured.
|
1190
1242
|
def proxy_pass
|
1191
1243
|
if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env
|
1192
|
-
proxy_uri&.password
|
1244
|
+
pass = proxy_uri&.password
|
1245
|
+
unescape(pass) if pass
|
1193
1246
|
else
|
1194
1247
|
@proxy_pass
|
1195
1248
|
end
|
@@ -1200,6 +1253,11 @@ module Net #:nodoc:
|
|
1200
1253
|
|
1201
1254
|
private
|
1202
1255
|
|
1256
|
+
def unescape(value)
|
1257
|
+
require 'cgi/util'
|
1258
|
+
CGI.unescape(value)
|
1259
|
+
end
|
1260
|
+
|
1203
1261
|
# without proxy, obsolete
|
1204
1262
|
|
1205
1263
|
def conn_address # :nodoc:
|
@@ -1556,6 +1614,8 @@ module Net #:nodoc:
|
|
1556
1614
|
begin
|
1557
1615
|
res = HTTPResponse.read_new(@socket)
|
1558
1616
|
res.decode_content = req.decode_content
|
1617
|
+
res.body_encoding = @response_body_encoding
|
1618
|
+
res.ignore_eof = @ignore_eof
|
1559
1619
|
end while res.kind_of?(HTTPInformation)
|
1560
1620
|
|
1561
1621
|
res.uri = req.uri
|
@@ -1575,10 +1635,10 @@ module Net #:nodoc:
|
|
1575
1635
|
if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
|
1576
1636
|
count += 1
|
1577
1637
|
@socket.close if @socket
|
1578
|
-
|
1638
|
+
debug "Conn close because of error #{exception}, and retry"
|
1579
1639
|
retry
|
1580
1640
|
end
|
1581
|
-
|
1641
|
+
debug "Conn close because of error #{exception}"
|
1582
1642
|
@socket.close if @socket
|
1583
1643
|
raise
|
1584
1644
|
end
|
@@ -1586,7 +1646,7 @@ module Net #:nodoc:
|
|
1586
1646
|
end_transport req, res
|
1587
1647
|
res
|
1588
1648
|
rescue => exception
|
1589
|
-
|
1649
|
+
debug "Conn close because of error #{exception}"
|
1590
1650
|
@socket.close if @socket
|
1591
1651
|
raise exception
|
1592
1652
|
end
|
@@ -1596,11 +1656,11 @@ module Net #:nodoc:
|
|
1596
1656
|
connect
|
1597
1657
|
elsif @last_communicated
|
1598
1658
|
if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
1599
|
-
|
1659
|
+
debug 'Conn close because of keep_alive_timeout'
|
1600
1660
|
@socket.close
|
1601
1661
|
connect
|
1602
1662
|
elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
|
1603
|
-
|
1663
|
+
debug "Conn close because of EOF"
|
1604
1664
|
@socket.close
|
1605
1665
|
connect
|
1606
1666
|
end
|
@@ -1618,15 +1678,15 @@ module Net #:nodoc:
|
|
1618
1678
|
@curr_http_version = res.http_version
|
1619
1679
|
@last_communicated = nil
|
1620
1680
|
if @socket.closed?
|
1621
|
-
|
1681
|
+
debug 'Conn socket closed'
|
1622
1682
|
elsif not res.body and @close_on_empty_response
|
1623
|
-
|
1683
|
+
debug 'Conn close'
|
1624
1684
|
@socket.close
|
1625
1685
|
elsif keep_alive?(req, res)
|
1626
|
-
|
1686
|
+
debug 'Conn keep-alive'
|
1627
1687
|
@last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
1628
1688
|
else
|
1629
|
-
|
1689
|
+
debug 'Conn close'
|
1630
1690
|
@socket.close
|
1631
1691
|
end
|
1632
1692
|
end
|
@@ -1681,11 +1741,14 @@ module Net #:nodoc:
|
|
1681
1741
|
default_port == port ? addr : "#{addr}:#{port}"
|
1682
1742
|
end
|
1683
1743
|
|
1684
|
-
|
1744
|
+
# Adds a message to debugging output
|
1745
|
+
def debug(msg)
|
1685
1746
|
return unless @debug_output
|
1686
1747
|
@debug_output << msg
|
1687
1748
|
@debug_output << "\n"
|
1688
1749
|
end
|
1750
|
+
|
1751
|
+
alias_method :D, :debug
|
1689
1752
|
end
|
1690
1753
|
|
1691
1754
|
end
|
data/net-http.gemspec
CHANGED
@@ -28,9 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
`git ls-files -z 2>/dev/null`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
29
29
|
end
|
30
30
|
spec.bindir = "exe"
|
31
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
32
31
|
spec.require_paths = ["lib"]
|
33
32
|
|
34
|
-
spec.add_dependency "net-protocol"
|
35
33
|
spec.add_dependency "uri"
|
36
34
|
end
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- NARUSE, Yui
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: net-protocol
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: uri
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -45,10 +31,10 @@ executables: []
|
|
45
31
|
extensions: []
|
46
32
|
extra_rdoc_files: []
|
47
33
|
files:
|
34
|
+
- ".github/dependabot.yml"
|
48
35
|
- ".github/workflows/test.yml"
|
49
36
|
- ".gitignore"
|
50
37
|
- Gemfile
|
51
|
-
- Gemfile.lock
|
52
38
|
- LICENSE.txt
|
53
39
|
- README.md
|
54
40
|
- Rakefile
|
@@ -89,7 +75,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
75
|
- !ruby/object:Gem::Version
|
90
76
|
version: '0'
|
91
77
|
requirements: []
|
92
|
-
rubygems_version: 3.
|
78
|
+
rubygems_version: 3.4.0.dev
|
93
79
|
signing_key:
|
94
80
|
specification_version: 4
|
95
81
|
summary: HTTP client api for Ruby.
|
data/Gemfile.lock
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
net-http (0.1.0)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
power_assert (1.1.5)
|
10
|
-
rake (13.0.1)
|
11
|
-
test-unit (3.3.5)
|
12
|
-
power_assert
|
13
|
-
|
14
|
-
PLATFORMS
|
15
|
-
ruby
|
16
|
-
|
17
|
-
DEPENDENCIES
|
18
|
-
net-http!
|
19
|
-
rake
|
20
|
-
test-unit
|
21
|
-
|
22
|
-
BUNDLED WITH
|
23
|
-
2.1.4
|