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
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
|
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.
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
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
|
-
|
1033
|
-
|
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) &&
|
1090
|
+
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
|
1040
1091
|
s.post_connection_check(@address)
|
1041
1092
|
end
|
1042
|
-
|
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
|
-
|
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
|
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
|
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
|
-
|
1632
|
+
debug "Conn close because of error #{exception}, and retry"
|
1579
1633
|
retry
|
1580
1634
|
end
|
1581
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1675
|
+
debug 'Conn socket closed'
|
1622
1676
|
elsif not res.body and @close_on_empty_response
|
1623
|
-
|
1677
|
+
debug 'Conn close'
|
1624
1678
|
@socket.close
|
1625
1679
|
elsif keep_alive?(req, res)
|
1626
|
-
|
1680
|
+
debug 'Conn keep-alive'
|
1627
1681
|
@last_communicated = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
1628
1682
|
else
|
1629
|
-
|
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
|
-
|
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.
|
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:
|
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.
|
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
|