Skip to content

Instantly share code, notes, and snippets.

@aianus
Created January 9, 2019 02:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aianus/20930914155b270d66c404c1e43e89ed to your computer and use it in GitHub Desktop.
Save aianus/20930914155b270d66c404c1e43e89ed to your computer and use it in GitHub Desktop.
Net::HTTP with sni_host param
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