summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS5
-rw-r--r--lib/net/http.rb29
-rw-r--r--test/net/http/test_https.rb31
3 files changed, 57 insertions, 8 deletions
diff --git a/NEWS b/NEWS
index 782060a7f3..46ab24277b 100644
--- a/NEWS
+++ b/NEWS
@@ -508,6 +508,11 @@ Net::FTP::
* Add Net::FTP#features to check available features, and Net::FTP#option to
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::
* Add Server Name Indication (SNI) support. [Feature #15594]
diff --git a/lib/net/http.rb b/lib/net/http.rb
index 663b901a96..283263b323 100644
--- a/lib/net/http.rb
+++ b/lib/net/http.rb
@@ -571,7 +571,7 @@ module Net #:nodoc:
# _opt_ :: optional hash
#
# _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,
# 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
@@ -590,6 +590,7 @@ module Net #:nodoc:
p_addr = :ENV if arg.size < 2
port = https_default_port if !port && opt && opt[:use_ssl]
http = new(address, port, p_addr, p_port, p_user, p_pass)
+ http.ipaddr = opt[:ipaddr] if opt[:ipaddr]
if opt
if opt[:use_ssl]
@@ -660,6 +661,7 @@ module Net #:nodoc:
def initialize(address, port = nil)
@address = address
@port = (port || HTTP.default_port)
+ @ipaddr = nil
@local_host = nil
@local_port = nil
@curr_http_version = HTTPVersion
@@ -727,6 +729,17 @@ module Net #:nodoc:
attr_writer :proxy_user
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
# may be used, including Floats for fractional seconds. If the HTTP
# object cannot open a connection in this many seconds, it raises a
@@ -934,20 +947,20 @@ module Net #:nodoc:
def connect
if proxy? then
- conn_address = proxy_address
+ conn_addr = proxy_address
conn_port = proxy_port
else
- conn_address = address
+ conn_addr = conn_address
conn_port = port
end
- D "opening connection to #{conn_address}:#{conn_port}..."
+ D "opening connection to #{conn_addr}:#{conn_port}..."
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) {
begin
- TCPSocket.open(conn_address, conn_port, @local_host, @local_port)
+ TCPSocket.open(conn_addr, conn_port, @local_host, @local_port)
rescue => e
raise e, "Failed to open TCP connection to " +
- "#{conn_address}:#{conn_port} (#{e.message})"
+ "#{conn_addr}:#{conn_port} (#{e.message})"
end
}
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_NO_INTERNAL_STORE
@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.sync_close = true
# Server Name Indication (SNI) RFC 3546
@@ -1161,7 +1174,7 @@ module Net #:nodoc:
# without proxy, obsolete
def conn_address # :nodoc:
- address()
+ @ipaddr || address()
end
def conn_port # :nodoc:
diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb
index c1d486470a..9058387070 100644
--- a/test/net/http/test_https.rb
+++ b/test/net/http/test_https.rb
@@ -50,6 +50,37 @@ class TestNetHTTPS < Test::Unit::TestCase
skip $!
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
http = Net::HTTP.new("localhost", config("port"))
http.use_ssl = true