net-http 0.1.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
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