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.
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:
@@ -132,7 +133,7 @@ module Net #:nodoc:
132
133
  # puts res.class.name # => 'HTTPOK'
133
134
  #
134
135
  # # Body
135
- # puts res.body if res.response_body_permitted?
136
+ # puts res.body
136
137
  #
137
138
  # === Following Redirection
138
139
  #
@@ -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.3.0"
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,7 +1012,7 @@ module Net #:nodoc:
981
1012
  conn_port = port
982
1013
  end
983
1014
 
984
- D "opening connection to #{conn_addr}:#{conn_port}..."
1015
+ debug "opening connection to #{conn_addr}:#{conn_port}..."
985
1016
  s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
986
1017
  begin
987
1018
  TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
@@ -991,7 +1022,7 @@ module Net #:nodoc:
991
1022
  end
992
1023
  }
993
1024
  s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
994
- D "opened"
1025
+ debug "opened"
995
1026
  if use_ssl?
996
1027
  if proxy?
997
1028
  plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
@@ -1020,35 +1051,56 @@ module Net #:nodoc:
1020
1051
  end
1021
1052
  end
1022
1053
  end
1023
- @ssl_context = OpenSSL::SSL::SSLContext.new
1024
1054
  @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}..."
1055
+ unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
1056
+ @ssl_context.session_cache_mode =
1057
+ OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
1058
+ OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
1059
+ end
1060
+ if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
1061
+ @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
1062
+ end
1063
+
1064
+ # Still do the post_connection_check below even if connecting
1065
+ # to IP address
1066
+ verify_hostname = @ssl_context.verify_hostname
1067
+
1068
+ # Server Name Indication (SNI) RFC 3546/6066
1069
+ case @address
1070
+ when Resolv::IPv4::Regex, Resolv::IPv6::Regex
1071
+ # don't set SNI, as IP addresses in SNI is not valid
1072
+ # per RFC 6066, section 3.
1073
+
1074
+ # Avoid openssl warning
1075
+ @ssl_context.verify_hostname = false
1076
+ else
1077
+ ssl_host_address = @address
1078
+ end
1079
+
1080
+ debug "starting SSL for #{conn_addr}:#{conn_port}..."
1030
1081
  s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
1031
1082
  s.sync_close = true
1032
- # Server Name Indication (SNI) RFC 3546
1033
- s.hostname = @address if s.respond_to? :hostname=
1083
+ s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
1084
+
1034
1085
  if @ssl_session and
1035
1086
  Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
1036
1087
  s.session = @ssl_session
1037
1088
  end
1038
1089
  ssl_socket_connect(s, @open_timeout)
1039
- if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && @ssl_context.verify_hostname
1090
+ if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
1040
1091
  s.post_connection_check(@address)
1041
1092
  end
1042
- D "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
1093
+ debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
1043
1094
  end
1044
1095
  @socket = BufferedIO.new(s, read_timeout: @read_timeout,
1045
1096
  write_timeout: @write_timeout,
1046
1097
  continue_timeout: @continue_timeout,
1047
1098
  debug_output: @debug_output)
1099
+ @last_communicated = nil
1048
1100
  on_connect
1049
1101
  rescue => exception
1050
1102
  if s
1051
- D "Conn close because of connect error #{exception}"
1103
+ debug "Conn close because of connect error #{exception}"
1052
1104
  s.close
1053
1105
  end
1054
1106
  raise
@@ -1170,17 +1222,11 @@ module Net #:nodoc:
1170
1222
  end
1171
1223
  end
1172
1224
 
1173
- # [Bug #12921]
1174
- if /linux|freebsd|darwin/ =~ RUBY_PLATFORM
1175
- ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE = true
1176
- else
1177
- ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE = false
1178
- end
1179
-
1180
1225
  # The username of the proxy server, if one is configured.
1181
1226
  def proxy_user
1182
- if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env
1183
- proxy_uri&.user
1227
+ if @proxy_from_env
1228
+ user = proxy_uri&.user
1229
+ unescape(user) if user
1184
1230
  else
1185
1231
  @proxy_user
1186
1232
  end
@@ -1188,8 +1234,9 @@ module Net #:nodoc:
1188
1234
 
1189
1235
  # The password of the proxy server, if one is configured.
1190
1236
  def proxy_pass
1191
- if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env
1192
- proxy_uri&.password
1237
+ if @proxy_from_env
1238
+ pass = proxy_uri&.password
1239
+ unescape(pass) if pass
1193
1240
  else
1194
1241
  @proxy_pass
1195
1242
  end
@@ -1200,6 +1247,11 @@ module Net #:nodoc:
1200
1247
 
1201
1248
  private
1202
1249
 
1250
+ def unescape(value)
1251
+ require 'cgi/util'
1252
+ CGI.unescape(value)
1253
+ end
1254
+
1203
1255
  # without proxy, obsolete
1204
1256
 
1205
1257
  def conn_address # :nodoc:
@@ -1556,6 +1608,8 @@ module Net #:nodoc:
1556
1608
  begin
1557
1609
  res = HTTPResponse.read_new(@socket)
1558
1610
  res.decode_content = req.decode_content
1611
+ res.body_encoding = @response_body_encoding
1612
+ res.ignore_eof = @ignore_eof
1559
1613
  end while res.kind_of?(HTTPInformation)
1560
1614
 
1561
1615
  res.uri = req.uri
@@ -1575,10 +1629,10 @@ module Net #:nodoc:
1575
1629
  if count < max_retries && IDEMPOTENT_METHODS_.include?(req.method)
1576
1630
  count += 1
1577
1631
  @socket.close if @socket
1578
- D "Conn close because of error #{exception}, and retry"
1632
+ debug "Conn close because of error #{exception}, and retry"
1579
1633
  retry
1580
1634
  end
1581
- D "Conn close because of error #{exception}"
1635
+ debug "Conn close because of error #{exception}"
1582
1636
  @socket.close if @socket
1583
1637
  raise
1584
1638
  end
@@ -1586,7 +1640,7 @@ module Net #:nodoc:
1586
1640
  end_transport req, res
1587
1641
  res
1588
1642
  rescue => exception
1589
- D "Conn close because of error #{exception}"
1643
+ debug "Conn close because of error #{exception}"
1590
1644
  @socket.close if @socket
1591
1645
  raise exception
1592
1646
  end
@@ -1596,11 +1650,11 @@ module Net #:nodoc:
1596
1650
  connect
1597
1651
  elsif @last_communicated
1598
1652
  if @last_communicated + @keep_alive_timeout < Process.clock_gettime(Process::CLOCK_MONOTONIC)
1599
- D 'Conn close because of keep_alive_timeout'
1653
+ debug 'Conn close because of keep_alive_timeout'
1600
1654
  @socket.close
1601
1655
  connect
1602
1656
  elsif @socket.io.to_io.wait_readable(0) && @socket.eof?
1603
- D "Conn close because of EOF"
1657
+ debug "Conn close because of EOF"
1604
1658
  @socket.close
1605
1659
  connect
1606
1660
  end
@@ -1618,15 +1672,15 @@ module Net #:nodoc:
1618
1672
  @curr_http_version = res.http_version
1619
1673
  @last_communicated = nil
1620
1674
  if @socket.closed?
1621
- D 'Conn socket closed'
1675
+ debug 'Conn socket closed'
1622
1676
  elsif not res.body and @close_on_empty_response
1623
- D 'Conn close'
1677
+ debug 'Conn close'
1624
1678
  @socket.close
1625
1679
  elsif keep_alive?(req, res)
1626
- D 'Conn keep-alive'
1680
+ debug 'Conn keep-alive'
1627
1681
  @last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
1628
1682
  else
1629
- D 'Conn close'
1683
+ debug 'Conn close'
1630
1684
  @socket.close
1631
1685
  end
1632
1686
  end
@@ -1681,11 +1735,14 @@ module Net #:nodoc:
1681
1735
  default_port == port ? addr : "#{addr}:#{port}"
1682
1736
  end
1683
1737
 
1684
- def D(msg)
1738
+ # Adds a message to debugging output
1739
+ def debug(msg)
1685
1740
  return unless @debug_output
1686
1741
  @debug_output << msg
1687
1742
  @debug_output << "\n"
1688
1743
  end
1744
+
1745
+ alias_method :D, :debug
1689
1746
  end
1690
1747
 
1691
1748
  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.3.0
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-10-24 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