Skip to content

Commit ad397b0

Browse files
authored
Merge branch 'master' into baweaver/http-pattern-matching
2 parents c850d7c + 8e08f34 commit ad397b0

12 files changed

Lines changed: 201 additions & 45 deletions

File tree

.document

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
BSDL
2+
COPYING
3+
README.md
4+
doc/
5+
lib/

.github/workflows/push_gem.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323

2424
steps:
2525
- name: Harden Runner
26-
uses: step-security/harden-runner@f4a75cfd619ee5ce8d5b864b0d183aff3c69b55a # v2.13.1
26+
uses: step-security/harden-runner@95d9a5deda9de15063e7595e9719c11c38c90ae2 # v2.13.2
2727
with:
2828
egress-policy: audit
2929

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
uses: ruby/actions/.github/workflows/ruby_versions.yml@master
88
with:
99
engine: cruby
10-
min_version: 2.6
10+
min_version: 2.7
1111

1212
test:
1313
needs: ruby-versions

lib/net/http.rb

Lines changed: 57 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -724,7 +724,7 @@ class HTTPHeaderSyntaxError < StandardError; end
724724
class HTTP < Protocol
725725

726726
# :stopdoc:
727-
VERSION = "0.7.0"
727+
VERSION = "0.8.0"
728728
HTTPVersion = '1.1'
729729
begin
730730
require 'zlib'
@@ -1182,6 +1182,7 @@ def initialize(address, port = nil) # :nodoc:
11821182
@debug_output = options[:debug_output]
11831183
@response_body_encoding = options[:response_body_encoding]
11841184
@ignore_eof = options[:ignore_eof]
1185+
@tcpsocket_supports_open_timeout = nil
11851186

11861187
@proxy_from_env = false
11871188
@proxy_uri = nil
@@ -1324,6 +1325,9 @@ def response_body_encoding=(value)
13241325
# Sets the proxy password;
13251326
# see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
13261327
attr_writer :proxy_pass
1328+
1329+
# Sets wheter the proxy uses SSL;
1330+
# see {Proxy Server}[rdoc-ref:Net::HTTP@Proxy+Server].
13271331
attr_writer :proxy_use_ssl
13281332

13291333
# Returns the IP address for the connection.
@@ -1653,6 +1657,21 @@ def start # :yield: http
16531657
self
16541658
end
16551659

1660+
# Finishes the \HTTP session:
1661+
#
1662+
# http = Net::HTTP.new(hostname)
1663+
# http.start
1664+
# http.started? # => true
1665+
# http.finish # => nil
1666+
# http.started? # => false
1667+
#
1668+
# Raises IOError if not in a session.
1669+
def finish
1670+
raise IOError, 'HTTP session not yet started' unless started?
1671+
do_finish
1672+
end
1673+
1674+
# :stopdoc:
16561675
def do_start
16571676
connect
16581677
@started = true
@@ -1675,14 +1694,36 @@ def connect
16751694
end
16761695

16771696
debug "opening connection to #{conn_addr}:#{conn_port}..."
1678-
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
1679-
begin
1680-
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
1681-
rescue => e
1682-
raise e, "Failed to open TCP connection to " +
1683-
"#{conn_addr}:#{conn_port} (#{e.message})"
1684-
end
1685-
}
1697+
begin
1698+
s =
1699+
case @tcpsocket_supports_open_timeout
1700+
when nil, true
1701+
begin
1702+
# Use built-in timeout in TCPSocket.open if available
1703+
sock = TCPSocket.open(conn_addr, conn_port, @local_host, @local_port, open_timeout: @open_timeout)
1704+
@tcpsocket_supports_open_timeout = true
1705+
sock
1706+
rescue ArgumentError => e
1707+
raise if !(e.message.include?('unknown keyword: :open_timeout') || e.message.include?('wrong number of arguments (given 5, expected 2..4)'))
1708+
@tcpsocket_supports_open_timeout = false
1709+
1710+
# Fallback to Timeout.timeout if TCPSocket.open does not support open_timeout
1711+
Timeout.timeout(@open_timeout, Net::OpenTimeout) {
1712+
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
1713+
}
1714+
end
1715+
when false
1716+
# The current Ruby is known to not support TCPSocket(open_timeout:).
1717+
# Directly fall back to Timeout.timeout to avoid performance penalty incured by rescue.
1718+
Timeout.timeout(@open_timeout, Net::OpenTimeout) {
1719+
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
1720+
}
1721+
end
1722+
rescue => e
1723+
e = Net::OpenTimeout.new(e) if e.is_a?(Errno::ETIMEDOUT) # for compatibility with previous versions
1724+
raise e, "Failed to open TCP connection to " +
1725+
"#{conn_addr}:#{conn_port} (#{e.message})"
1726+
end
16861727
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
16871728
debug "opened"
16881729
if use_ssl?
@@ -1779,20 +1820,6 @@ def on_connect
17791820
end
17801821
private :on_connect
17811822

1782-
# Finishes the \HTTP session:
1783-
#
1784-
# http = Net::HTTP.new(hostname)
1785-
# http.start
1786-
# http.started? # => true
1787-
# http.finish # => nil
1788-
# http.started? # => false
1789-
#
1790-
# Raises IOError if not in a session.
1791-
def finish
1792-
raise IOError, 'HTTP session not yet started' unless started?
1793-
do_finish
1794-
end
1795-
17961823
def do_finish
17971824
@started = false
17981825
@socket.close if @socket
@@ -1842,6 +1869,8 @@ def HTTP.Proxy(p_addr = :ENV, p_port = nil, p_user = nil, p_pass = nil, p_use_ss
18421869
}
18431870
end
18441871

1872+
# :startdoc:
1873+
18451874
class << HTTP
18461875
# Returns true if self is a class which was created by HTTP::Proxy.
18471876
def proxy_class?
@@ -1936,6 +1965,7 @@ def proxy_pass
19361965
alias proxyport proxy_port #:nodoc: obsolete
19371966

19381967
private
1968+
# :stopdoc:
19391969

19401970
def unescape(value)
19411971
require 'cgi/escape'
@@ -1964,6 +1994,7 @@ def edit_path(path)
19641994
path
19651995
end
19661996
end
1997+
# :startdoc:
19671998

19681999
#
19692000
# HTTP operations
@@ -2418,6 +2449,8 @@ def send_entity(path, data, initheader, dest, type, &block)
24182449
res
24192450
end
24202451

2452+
# :stopdoc:
2453+
24212454
IDEMPOTENT_METHODS_ = %w/GET HEAD PUT DELETE OPTIONS TRACE/ # :nodoc:
24222455

24232456
def transport_request(req)
@@ -2575,7 +2608,7 @@ def debug(msg)
25752608
alias_method :D, :debug
25762609
end
25772610

2578-
# for backward compatibility until Ruby 3.5
2611+
# for backward compatibility until Ruby 4.0
25792612
# https://bugs.ruby-lang.org/issues/20900
25802613
# https://github.com/bblimke/webmock/pull/1081
25812614
HTTPSession = HTTP

lib/net/http/exceptions.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ module Net
33
# Net::HTTP exception class.
44
# You cannot use Net::HTTPExceptions directly; instead, you must use
55
# its subclasses.
6-
module HTTPExceptions
6+
module HTTPExceptions # :nodoc:
77
def initialize(msg, res) #:nodoc:
88
super msg
99
@response = res
@@ -12,6 +12,7 @@ def initialize(msg, res) #:nodoc:
1212
alias data response #:nodoc: obsolete
1313
end
1414

15+
# :stopdoc:
1516
class HTTPError < ProtocolError
1617
include HTTPExceptions
1718
end

lib/net/http/generic_request.rb

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,13 @@ def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) # :nodoc:
1919

2020
if URI === uri_or_path then
2121
raise ArgumentError, "not an HTTP URI" unless URI::HTTP === uri_or_path
22-
hostname = uri_or_path.hostname
22+
hostname = uri_or_path.host
2323
raise ArgumentError, "no host component for URI" unless (hostname && hostname.length > 0)
2424
@uri = uri_or_path.dup
25-
host = @uri.hostname.dup
26-
host << ":" << @uri.port.to_s if @uri.port != @uri.default_port
2725
@path = uri_or_path.request_uri
2826
raise ArgumentError, "no HTTP request path given" unless @path
2927
else
3028
@uri = nil
31-
host = nil
3229
raise ArgumentError, "no HTTP request path given" unless uri_or_path
3330
raise ArgumentError, "HTTP request path is empty" if uri_or_path.empty?
3431
@path = uri_or_path.dup
@@ -51,7 +48,7 @@ def initialize(m, reqbody, resbody, uri_or_path, initheader = nil) # :nodoc:
5148
initialize_http_header initheader
5249
self['Accept'] ||= '*/*'
5350
self['User-Agent'] ||= 'Ruby'
54-
self['Host'] ||= host if host
51+
self['Host'] ||= @uri.authority if @uri
5552
@body = nil
5653
@body_stream = nil
5754
@body_data = nil
@@ -245,7 +242,7 @@ def update_uri(addr, port, ssl) # :nodoc: internal use only
245242
end
246243

247244
if host = self['host']
248-
host.sub!(/:.*/m, '')
245+
host = URI.parse("//#{host}").host # Remove a port component from the existing Host header
249246
elsif host = @uri.host
250247
else
251248
host = addr
@@ -264,6 +261,8 @@ def update_uri(addr, port, ssl) # :nodoc: internal use only
264261

265262
private
266263

264+
# :stopdoc:
265+
267266
class Chunker #:nodoc:
268267
def initialize(sock)
269268
@sock = sock

lib/net/http/header.rb

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,9 @@
179179
# - #each_value: Passes each string field value to the block.
180180
#
181181
module Net::HTTPHeader
182+
# The maximum length of HTTP header keys.
182183
MAX_KEY_LENGTH = 1024
184+
# The maximum length of HTTP header values.
183185
MAX_FIELD_LENGTH = 65536
184186

185187
def initialize_http_header(initheader) #:nodoc:
@@ -267,6 +269,7 @@ def add_field(key, val)
267269
end
268270
end
269271

272+
# :stopdoc:
270273
private def set_field(key, val)
271274
case val
272275
when Enumerable
@@ -294,6 +297,7 @@ def add_field(key, val)
294297
ary.push val
295298
end
296299
end
300+
# :startdoc:
297301

298302
# Returns the array field value for the given +key+,
299303
# or +nil+ if there is no such field;
@@ -490,7 +494,7 @@ def each_capitalized
490494

491495
alias canonical_each each_capitalized
492496

493-
def capitalize(name)
497+
def capitalize(name) # :nodoc:
494498
name.to_s.split('-'.freeze).map {|s| s.capitalize }.join('-'.freeze)
495499
end
496500
private :capitalize
@@ -957,20 +961,20 @@ def proxy_basic_auth(account, password)
957961
@header['proxy-authorization'] = [basic_encode(account, password)]
958962
end
959963

960-
def basic_encode(account, password)
964+
def basic_encode(account, password) # :nodoc:
961965
'Basic ' + ["#{account}:#{password}"].pack('m0')
962966
end
963967
private :basic_encode
964968

965-
# Returns whether the HTTP session is to be closed.
969+
# Returns whether the HTTP session is to be closed.
966970
def connection_close?
967971
token = /(?:\A|,)\s*close\s*(?:\z|,)/i
968972
@header['connection']&.grep(token) {return true}
969973
@header['proxy-connection']&.grep(token) {return true}
970974
false
971975
end
972976

973-
# Returns whether the HTTP session is to be kept alive.
977+
# Returns whether the HTTP session is to be kept alive.
974978
def connection_keep_alive?
975979
token = /(?:\A|,)\s*keep-alive\s*(?:\z|,)/i
976980
@header['connection']&.grep(token) {return true}

0 commit comments

Comments
 (0)