Module: NetHttp2::Socket

Defined in:
lib/net-http2/socket.rb

Class Method Summary collapse

Class Method Details

.create(uri, options) ⇒ Object



5
6
7
8
9
10
# File 'lib/net-http2/socket.rb', line 5

def self.create(uri, options)
  return ssl_socket(uri, options) if options[:ssl]
  return proxy_tcp_socket(uri, options) if options[:proxy_addr]

  tcp_socket(uri, options)
end

.proxy_tcp_socket(uri, options) ⇒ Object



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# File 'lib/net-http2/socket.rb', line 57

def self.proxy_tcp_socket(uri, options)
  proxy_addr = options[:proxy_addr]
  proxy_port = options[:proxy_port]
  proxy_user = options[:proxy_user]
  proxy_pass = options[:proxy_pass]

  proxy_uri = URI.parse("#{proxy_addr}:#{proxy_port}")
  proxy_socket = tcp_socket(proxy_uri, options)

  # The majority of proxies do not explicitly support HTTP/2 protocol,
  # while they successfully create a TCP tunnel
  # which can pass through binary data of HTTP/2 connection.
  # So we’ll keep HTTP/1.1
  http_version = '1.1'

  buf = "CONNECT #{uri.host}:#{uri.port} HTTP/#{http_version}\r\n"
  buf << "Host: #{uri.host}:#{uri.port}\r\n"
  if proxy_user
    credential = ["#{proxy_user}:#{proxy_pass}"].pack('m')
    credential.delete!("\r\n")
    buf << "Proxy-Authorization: Basic #{credential}\r\n"
  end
  buf << "\r\n"
  proxy_socket.write(buf)
  validate_proxy_response!(proxy_socket)

  proxy_socket
end

.ssl_socket(uri, options) ⇒ Object



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/net-http2/socket.rb', line 12

def self.ssl_socket(uri, options)
  tcp = if options[:proxy_addr]
    proxy_tcp_socket(uri, options)
  else
    tcp_socket(uri, options)
  end

  socket            = OpenSSL::SSL::SSLSocket.new(tcp, options[:ssl_context])
  socket.sync_close = true
  socket.hostname   = options[:proxy_addr] || uri.host

  socket.connect

  socket
end

.tcp_socket(uri, options) ⇒ Object



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/net-http2/socket.rb', line 28

def self.tcp_socket(uri, options)
  family   = ::Socket::AF_INET
  address  = ::Socket.getaddrinfo(uri.host, nil, family).first[3]
  sockaddr = ::Socket.pack_sockaddr_in(uri.port, address)

  socket = ::Socket.new(family, ::Socket::SOCK_STREAM, 0)
  socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)

  begin
    socket.connect_nonblock(sockaddr)
  rescue IO::WaitWritable
    if IO.select(nil, [socket], nil, options[:connect_timeout])
      begin
        socket.connect_nonblock(sockaddr)
      rescue Errno::EISCONN
        # socket is connected
      rescue
        socket.close
        raise
      end
    else
      socket.close
      raise Errno::ETIMEDOUT
    end
  end

  socket
end