Skip to content

Commit 0c0da29

Browse files
committed
Refactor Net::HTTP#connect
The method was getting large, and in preparation for #141, I thought it would be easier to break up the method into several other methods.
1 parent edc99a5 commit 0c0da29

File tree

1 file changed

+78
-64
lines changed

1 file changed

+78
-64
lines changed

lib/net/http.rb

Lines changed: 78 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,73 +1613,20 @@ def connect
16131613
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
16141614
debug "opened"
16151615
if use_ssl?
1616-
if proxy?
1617-
plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
1618-
write_timeout: @write_timeout,
1619-
continue_timeout: @continue_timeout,
1620-
debug_output: @debug_output)
1621-
buf = +"CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n" \
1622-
"Host: #{@address}:#{@port}\r\n"
1623-
if proxy_user
1624-
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0')
1625-
buf << "Proxy-Authorization: Basic #{credential}\r\n"
1616+
proxy_connect(s, conn_address) if proxy?
1617+
setup_ssl_context
1618+
with_ssl_socket(s, conn_addr, conn_port) do |socket, verify_hostname|
1619+
if @ssl_session and
1620+
Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
1621+
s.session = @ssl_session
16261622
end
1627-
buf << "\r\n"
1628-
plain_sock.write(buf)
1629-
HTTPResponse.read_new(plain_sock).value
1630-
# assuming nothing left in buffers after successful CONNECT response
1631-
end
1632-
1633-
ssl_parameters = Hash.new
1634-
iv_list = instance_variables
1635-
SSL_IVNAMES.each_with_index do |ivname, i|
1636-
if iv_list.include?(ivname)
1637-
value = instance_variable_get(ivname)
1638-
unless value.nil?
1639-
ssl_parameters[SSL_ATTRIBUTES[i]] = value
1640-
end
1623+
ssl_socket_connect(s, @open_timeout)
1624+
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
1625+
s.post_connection_check(@address)
16411626
end
1627+
debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
16421628
end
1643-
@ssl_context.set_params(ssl_parameters)
1644-
unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
1645-
@ssl_context.session_cache_mode =
1646-
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
1647-
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
1648-
end
1649-
if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
1650-
@ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
1651-
end
1652-
1653-
# Still do the post_connection_check below even if connecting
1654-
# to IP address
1655-
verify_hostname = @ssl_context.verify_hostname
1656-
1657-
# Server Name Indication (SNI) RFC 3546/6066
1658-
case @address
1659-
when Resolv::IPv4::Regex, Resolv::IPv6::Regex
1660-
# don't set SNI, as IP addresses in SNI is not valid
1661-
# per RFC 6066, section 3.
1662-
1663-
# Avoid openssl warning
1664-
@ssl_context.verify_hostname = false
1665-
else
1666-
ssl_host_address = @address
1667-
end
1668-
1669-
debug "starting SSL for #{conn_addr}:#{conn_port}..."
1670-
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
1671-
s.sync_close = true
1672-
s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
1673-
1674-
if @ssl_session and
1675-
Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout
1676-
s.session = @ssl_session
1677-
end
1678-
ssl_socket_connect(s, @open_timeout)
1679-
if (@ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE) && verify_hostname
1680-
s.post_connection_check(@address)
1681-
end
1682-
debug "SSL established, protocol: #{s.ssl_version}, cipher: #{s.cipher[0]}"
1629+
ssl_connect(s)
16831630
end
16841631
@socket = BufferedIO.new(s, read_timeout: @read_timeout,
16851632
write_timeout: @write_timeout,
@@ -1696,6 +1643,73 @@ def connect
16961643
end
16971644
private :connect
16981645

1646+
def proxy_connect(s, conn_address)
1647+
plain_sock = BufferedIO.new(s, read_timeout: @read_timeout,
1648+
write_timeout: @write_timeout,
1649+
continue_timeout: @continue_timeout,
1650+
debug_output: @debug_output)
1651+
buf = "CONNECT #{conn_address}:#{@port} HTTP/#{HTTPVersion}\r\n"
1652+
buf << "Host: #{@address}:#{@port}\r\n"
1653+
if proxy_user
1654+
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0')
1655+
buf << "Proxy-Authorization: Basic #{credential}\r\n"
1656+
end
1657+
buf << "\r\n"
1658+
plain_sock.write(buf)
1659+
HTTPResponse.read_new(plain_sock).value
1660+
# assuming nothing left in buffers after successful CONNECT response
1661+
end
1662+
private :proxy_connect
1663+
1664+
def setup_ssl_context
1665+
ssl_parameters = Hash.new
1666+
iv_list = instance_variables
1667+
SSL_IVNAMES.each_with_index do |ivname, i|
1668+
if iv_list.include?(ivname)
1669+
value = instance_variable_get(ivname)
1670+
unless value.nil?
1671+
ssl_parameters[SSL_ATTRIBUTES[i]] = value
1672+
end
1673+
end
1674+
end
1675+
@ssl_context.set_params(ssl_parameters)
1676+
unless @ssl_context.session_cache_mode.nil? # a dummy method on JRuby
1677+
@ssl_context.session_cache_mode =
1678+
OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT |
1679+
OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE
1680+
end
1681+
if @ssl_context.respond_to?(:session_new_cb) # not implemented under JRuby
1682+
@ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess }
1683+
end
1684+
end
1685+
private :setup_ssl_context
1686+
1687+
def with_ssl_socket(s, conn_addr, conn_port)
1688+
# Still do the post_connection_check below even if connecting
1689+
# to IP address
1690+
verify_hostname = @ssl_context.verify_hostname
1691+
1692+
# Server Name Indication (SNI) RFC 3546/6066
1693+
case @address
1694+
when Resolv::IPv4::Regex, Resolv::IPv6::Regex
1695+
# don't set SNI, as IP addresses in SNI is not valid
1696+
# per RFC 6066, section 3.
1697+
1698+
# Avoid openssl warning
1699+
@ssl_context.verify_hostname = false
1700+
else
1701+
ssl_host_address = @address
1702+
end
1703+
1704+
debug "starting SSL for #{conn_addr}:#{conn_port}..."
1705+
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context)
1706+
s.sync_close = true
1707+
s.hostname = ssl_host_address if s.respond_to?(:hostname=) && ssl_host_address
1708+
1709+
yield s, verify_hostname
1710+
end
1711+
private :with_ssl_socket
1712+
16991713
def on_connect
17001714
end
17011715
private :on_connect

0 commit comments

Comments
 (0)