mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Add ipaddr optional parameter to Net::HTTP#start
to replace the address for TCP/IP connection [Feature #5180] There're 3 layers of hostname: * host address for TCP/IP * TLS server name * HTTP Host header value To test DNS round robin or check server certificate from server local, people sometimes want to connect server with given IP address but keep TLS server name and HTTP Host header value. closes [Feature #15215] closes https://github.com/ruby/ruby/pull/1893 closes https://github.com/ruby/ruby/pull/1977
This commit is contained in:
parent
1943279426
commit
54072e329c
3 changed files with 57 additions and 8 deletions
5
NEWS
5
NEWS
|
@ -508,6 +508,11 @@ Net::FTP::
|
||||||
* Add Net::FTP#features to check available features, and Net::FTP#option to
|
* Add Net::FTP#features to check available features, and Net::FTP#option to
|
||||||
enable/disable each of them. [Feature #15964]
|
enable/disable each of them. [Feature #15964]
|
||||||
|
|
||||||
|
Net::HTTP::
|
||||||
|
|
||||||
|
* Add ipaddr optional parameter to Net::HTTP#start to replace the address for
|
||||||
|
TCP/IP connection [Feature #5180]
|
||||||
|
|
||||||
Net::IMAP::
|
Net::IMAP::
|
||||||
|
|
||||||
* Add Server Name Indication (SNI) support. [Feature #15594]
|
* Add Server Name Indication (SNI) support. [Feature #15594]
|
||||||
|
|
|
@ -571,7 +571,7 @@ module Net #:nodoc:
|
||||||
# _opt_ :: optional hash
|
# _opt_ :: optional hash
|
||||||
#
|
#
|
||||||
# _opt_ sets following values by its accessor.
|
# _opt_ sets following values by its accessor.
|
||||||
# The keys are ca_file, ca_path, cert, cert_store, ciphers,
|
# The keys are ipaddr, ca_file, ca_path, cert, cert_store, ciphers,
|
||||||
# close_on_empty_response, key, open_timeout, read_timeout, write_timeout, ssl_timeout,
|
# close_on_empty_response, key, open_timeout, read_timeout, write_timeout, ssl_timeout,
|
||||||
# ssl_version, use_ssl, verify_callback, verify_depth and verify_mode.
|
# ssl_version, use_ssl, verify_callback, verify_depth and verify_mode.
|
||||||
# If you set :use_ssl as true, you can use https and default value of
|
# If you set :use_ssl as true, you can use https and default value of
|
||||||
|
@ -590,6 +590,7 @@ module Net #:nodoc:
|
||||||
p_addr = :ENV if arg.size < 2
|
p_addr = :ENV if arg.size < 2
|
||||||
port = https_default_port if !port && opt && opt[:use_ssl]
|
port = https_default_port if !port && opt && opt[:use_ssl]
|
||||||
http = new(address, port, p_addr, p_port, p_user, p_pass)
|
http = new(address, port, p_addr, p_port, p_user, p_pass)
|
||||||
|
http.ipaddr = opt[:ipaddr] if opt[:ipaddr]
|
||||||
|
|
||||||
if opt
|
if opt
|
||||||
if opt[:use_ssl]
|
if opt[:use_ssl]
|
||||||
|
@ -660,6 +661,7 @@ module Net #:nodoc:
|
||||||
def initialize(address, port = nil)
|
def initialize(address, port = nil)
|
||||||
@address = address
|
@address = address
|
||||||
@port = (port || HTTP.default_port)
|
@port = (port || HTTP.default_port)
|
||||||
|
@ipaddr = nil
|
||||||
@local_host = nil
|
@local_host = nil
|
||||||
@local_port = nil
|
@local_port = nil
|
||||||
@curr_http_version = HTTPVersion
|
@curr_http_version = HTTPVersion
|
||||||
|
@ -727,6 +729,17 @@ module Net #:nodoc:
|
||||||
attr_writer :proxy_user
|
attr_writer :proxy_user
|
||||||
attr_writer :proxy_pass
|
attr_writer :proxy_pass
|
||||||
|
|
||||||
|
# The IP address to connect to/used to connect to
|
||||||
|
def ipaddr
|
||||||
|
started? ? @socket.io.peeraddr[3] : @ipaddr
|
||||||
|
end
|
||||||
|
|
||||||
|
# Set the IP address to connect to
|
||||||
|
def ipaddr=(addr)
|
||||||
|
raise IOError, "ipaddr value changed, but session already started" if started?
|
||||||
|
@ipaddr = addr
|
||||||
|
end
|
||||||
|
|
||||||
# Number of seconds to wait for the connection to open. Any number
|
# Number of seconds to wait for the connection to open. Any number
|
||||||
# may be used, including Floats for fractional seconds. If the HTTP
|
# may be used, including Floats for fractional seconds. If the HTTP
|
||||||
# object cannot open a connection in this many seconds, it raises a
|
# object cannot open a connection in this many seconds, it raises a
|
||||||
|
@ -934,20 +947,20 @@ module Net #:nodoc:
|
||||||
|
|
||||||
def connect
|
def connect
|
||||||
if proxy? then
|
if proxy? then
|
||||||
conn_address = proxy_address
|
conn_addr = proxy_address
|
||||||
conn_port = proxy_port
|
conn_port = proxy_port
|
||||||
else
|
else
|
||||||
conn_address = address
|
conn_addr = conn_address
|
||||||
conn_port = port
|
conn_port = port
|
||||||
end
|
end
|
||||||
|
|
||||||
D "opening connection to #{conn_address}:#{conn_port}..."
|
D "opening connection to #{conn_addr}:#{conn_port}..."
|
||||||
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
|
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
|
||||||
begin
|
begin
|
||||||
TCPSocket.open(conn_address, conn_port, @local_host, @local_port)
|
TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
|
||||||
rescue => e
|
rescue => e
|
||||||
raise e, "Failed to open TCP connection to " +
|
raise e, "Failed to open TCP connection to " +
|
||||||
"#{conn_address}:#{conn_port} (#{e.message})"
|
"#{conn_addr}:#{conn_port} (#{e.message})"
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
||||||
|
@ -984,7 +997,7 @@ module Net #:nodoc:
|
||||||
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
|
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
|
||||||
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
|
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
|
||||||
@ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
|
@ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
|
||||||
D "starting SSL for #{conn_address}:#{conn_port}..."
|
D "starting SSL for #{conn_addr}:#{conn_port}..."
|
||||||
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
|
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
|
||||||
s.sync_close = true
|
s.sync_close = true
|
||||||
# Server Name Indication (SNI) RFC 3546
|
# Server Name Indication (SNI) RFC 3546
|
||||||
|
@ -1161,7 +1174,7 @@ module Net #:nodoc:
|
||||||
# without proxy, obsolete
|
# without proxy, obsolete
|
||||||
|
|
||||||
def conn_address # :nodoc:
|
def conn_address # :nodoc:
|
||||||
address()
|
@ipaddr || address()
|
||||||
end
|
end
|
||||||
|
|
||||||
def conn_port # :nodoc:
|
def conn_port # :nodoc:
|
||||||
|
|
|
@ -50,6 +50,37 @@ class TestNetHTTPS < Test::Unit::TestCase
|
||||||
skip $!
|
skip $!
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_get_SNI
|
||||||
|
http = Net::HTTP.new("localhost", config("port"))
|
||||||
|
http.ipaddr = config('host')
|
||||||
|
http.use_ssl = true
|
||||||
|
http.cert_store = TEST_STORE
|
||||||
|
certs = []
|
||||||
|
http.verify_callback = Proc.new do |preverify_ok, store_ctx|
|
||||||
|
certs << store_ctx.current_cert
|
||||||
|
preverify_ok
|
||||||
|
end
|
||||||
|
http.request_get("/") {|res|
|
||||||
|
assert_equal($test_net_http_data, res.body)
|
||||||
|
}
|
||||||
|
assert_equal(CA_CERT.to_der, certs[0].to_der)
|
||||||
|
assert_equal(SERVER_CERT.to_der, certs[1].to_der)
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_get_SNI_failure
|
||||||
|
http = Net::HTTP.new("invalid_servername", config("port"))
|
||||||
|
http.ipaddr = config('host')
|
||||||
|
http.use_ssl = true
|
||||||
|
http.cert_store = TEST_STORE
|
||||||
|
certs = []
|
||||||
|
http.verify_callback = Proc.new do |preverify_ok, store_ctx|
|
||||||
|
certs << store_ctx.current_cert
|
||||||
|
preverify_ok
|
||||||
|
end
|
||||||
|
@log_tester = lambda {|_| }
|
||||||
|
assert_raise(OpenSSL::SSL::SSLError){ http.start }
|
||||||
|
end
|
||||||
|
|
||||||
def test_post
|
def test_post
|
||||||
http = Net::HTTP.new("localhost", config("port"))
|
http = Net::HTTP.new("localhost", config("port"))
|
||||||
http.use_ssl = true
|
http.use_ssl = true
|
||||||
|
|
Loading…
Add table
Reference in a new issue