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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a306a97039eef1800016a611dee36fa0d342b5f234bf6e0a512d981abd12ce8d
4
- data.tar.gz: 39583accf1ec3b888c4e368eb0d3cf41add46ebfd18a6d7dcbea1cc69712f219
3
+ metadata.gz: ee3df6b6afad0f163708cc0fc0f0a16f4a3b394b56c3c389c55a55274f38c3e7
4
+ data.tar.gz: 17a0329a4c031e923cd597af5abcd31d08a853ffbb9d9a58308f6bb44b02b88d
5
5
  SHA512:
6
- metadata.gz: 21ab016c4d12100c405aec7b8426d81f4a88ac2bc7019353d729837d17e3a95899df04818f787319c32f29b349b7527b7903a65a897e8353382d5461070465c7
7
- data.tar.gz: 38593be710550d52aaf31d50d746e7f5da92fb1c3d4b451968bda3c0af9b033acefc2fd404f6a083025d340d8abebd7d2061fa77343f081b78bd48c19aa82b39
6
+ metadata.gz: 27b412cb8ea24d0a24bc5f3a835cef426481ca6f921323629b0bbabf0b9752373c5f6904179984068fd8a1e7c666f29c989636baa43989a835259252a0278eef
7
+ data.tar.gz: 52772055904e6f294fb72a13d270b269b37dc3b588c91afe517e3ea74fb639aac6b6586092cb1fa1de65eb9c518290e79ddde3b6804e65b5b532233d295e0d38
@@ -0,0 +1,6 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: 'github-actions'
4
+ directory: '/'
5
+ schedule:
6
+ interval: 'weekly'
@@ -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@master
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
@@ -4,3 +4,4 @@ gemspec
4
4
 
5
5
  gem "rake"
6
6
  gem "test-unit"
7
+ gem "webrick"
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Net::Http
1
+ # Net::HTTP
2
2
 
3
3
  Net::HTTP provides a rich library which can be used to build HTTP
4
4
  user-agents. For more details about HTTP see
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/test/unit/core_assertions.rb", "./test/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
@@ -5,22 +5,36 @@
5
5
 
6
6
  class Net::HTTP
7
7
  ProxyMod = ProxyDelta
8
- end
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
- Net::HTTPInformationCode = Net::HTTPInformation
19
- Net::HTTPSuccessCode = Net::HTTPSuccess
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 @response_has_body and Net::HTTP::HAVE_ZLIB then
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!(/:.*/s, ''.freeze)
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
- # copy_stream can sendfile() to sock.io unless we use SSL.
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
 
@@ -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, true # ignore EOF
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.1.1"
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 iff +url+.user exists.
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
- D "opening connection to #{conn_addr}:#{conn_port}..."
985
- s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
986
- begin
987
- TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
988
- rescue => e
989
- raise e, "Failed to open TCP connection to " +
990
- "#{conn_addr}:#{conn_port} (#{e.message})"
991
- end
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
- D "opened"
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
- OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
1027
- OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
1028
- @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
1029
- D "starting SSL for #{conn_addr}:#{conn_port}..."
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
- # Server Name Indication (SNI) RFC 3546
1033
- s.hostname = @address if s.respond_to? :hostname=
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) && @ssl_context.verify_hostname
1089
+ if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
1040
1090
  s.post_connection_check(@address)
1041
1091
  end
1042
- D "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
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
- D "Conn close because of connect error #{exception}"
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
- D "Conn close because of error #{exception}, and retry"
1638
+ debug "Conn close because of error #{exception}, and retry"
1579
1639
  retry
1580
1640
  end
1581
- D "Conn close because of error #{exception}"
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
- D "Conn close because of error #{exception}"
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
- D 'Conn close because of keep_alive_timeout'
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
- D "Conn close because of EOF"
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
- D 'Conn socket closed'
1681
+ debug 'Conn socket closed'
1622
1682
  elsif not res.body and @close_on_empty_response
1623
- D 'Conn close'
1683
+ debug 'Conn close'
1624
1684
  @socket.close
1625
1685
  elsif keep_alive?(req, res)
1626
- D 'Conn keep-alive'
1686
+ debug 'Conn keep-alive'
1627
1687
  @last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
1628
1688
  else
1629
- D 'Conn close'
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
- def D(msg)
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.1.1
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: 2020-12-22 00:00:00.000000000 Z
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.2.2
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