Created
January 9, 2019 02:58
-
-
Save aianus/20930914155b270d66c404c1e43e89ed to your computer and use it in GitHub Desktop.
Net::HTTP with sni_host param
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Net #:nodoc: | |
class HTTP < Protocol | |
# Override the SNI hostname used during SSL handshake | |
attr_accessor :sni_host | |
def connect | |
if proxy? then | |
conn_address = proxy_address | |
conn_port = proxy_port | |
else | |
conn_address = address | |
conn_port = port | |
end | |
D "opening connection to #{conn_address}:#{conn_port}..." | |
s = Timeout.timeout(@open_timeout, Net::OpenTimeout) { | |
begin | |
TCPSocket.open(conn_address, conn_port, @local_host, @local_port) | |
rescue => e | |
raise e, "Failed to open TCP connection to " + | |
"#{conn_address}:#{conn_port} (#{e.message})" | |
end | |
} | |
s.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1) | |
D "opened" | |
if use_ssl? | |
if proxy? | |
plain_sock = BufferedIO.new(s, read_timeout: @read_timeout, | |
continue_timeout: @continue_timeout, | |
debug_output: @debug_output) | |
buf = "CONNECT #{@address}:#{@port} HTTP/#{HTTPVersion}\r\n" | |
buf << "Host: #{@address}:#{@port}\r\n" | |
if proxy_user | |
credential = ["#{proxy_user}:#{proxy_pass}"].pack('m0') | |
buf << "Proxy-Authorization: Basic #{credential}\r\n" | |
end | |
buf << "\r\n" | |
plain_sock.write(buf) | |
HTTPResponse.read_new(plain_sock).value | |
# assuming nothing left in buffers after successful CONNECT response | |
end | |
ssl_parameters = Hash.new | |
iv_list = instance_variables | |
SSL_IVNAMES.each_with_index do |ivname, i| | |
if iv_list.include?(ivname) and | |
value = instance_variable_get(ivname) | |
ssl_parameters[SSL_ATTRIBUTES[i]] = value if value | |
end | |
end | |
@ssl_context = OpenSSL::SSL::SSLContext.new | |
@ssl_context.set_params(ssl_parameters) | |
D "starting SSL for #{conn_address}:#{conn_port}..." | |
s = OpenSSL::SSL::SSLSocket.new(s, @ssl_context) | |
s.sync_close = true | |
# Server Name Indication (SNI) RFC 3546 | |
s.hostname = (@sni_host || @address) if s.respond_to? :hostname= | |
if @ssl_session and | |
Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout | |
s.session = @ssl_session if @ssl_session | |
end | |
ssl_socket_connect(s, @open_timeout) | |
if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE | |
s.post_connection_check(@sni_host || @address) | |
end | |
@ssl_session = s.session | |
D "SSL established" | |
end | |
@socket = BufferedIO.new(s, read_timeout: @read_timeout, | |
continue_timeout: @continue_timeout, | |
debug_output: @debug_output) | |
on_connect | |
rescue => exception | |
if s | |
D "Conn close because of connect error #{exception}" | |
s.close | |
end | |
raise | |
end | |
private :connect | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment