HTTP Connect By Example

HTTP CONNECT is used to establish a tunnel. Tunnels are commonly used to create an end-to-end virtual connection, through one or more proxies, which can then be secured using TLS (Transport Layer Security).

Diagrams

The following application layer interaction establishes a transport layer.

Interaction diagram

This allows the client and destination to utilize various application layer interactions supported over the transport layer.

TCP / IP model interaction diagram

Example

The following example consists of the curl output and corresponding proxy code:

$ https_proxy=http://127.0.0.1:9292 \
    curl -v https://google.com
require 'socket'

listen_socket = TCPServer.new('127.0.0.1', 9292)
> CONNECT google.com:443 HTTP/1.1
client_conn = listen_socket.accept
request_line = client_conn.gets
> Host: google.com:443
> User-Agent: curl/7.54.0
> Proxy-Connection: Keep-Alive
>
while(line = client_conn.gets) do
  break unless line.include?(':')
end
< HTTP/1.1 200 OK
<
host, port = *request_line.split[1].split(':')
dest_conn = TCPSocket.new(host, port)
client_conn.write "HTTP/1.1 200 OK\r\n"
* Proxy replied OK to CONNECT request
...
> GET / HTTP/2
> Host: google.com
> User-Agent: curl/7.54.0
> Accept: */*
>
...
< HTTP/2 301
< location: https://www.google.com/
...
<
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="https://www.google.com/">here</A>.
</BODY></HTML>
def transfer(src_conn, dest_conn)
  IO.copy_stream(src_conn, dest_conn)
rescue => e
  puts e.message
end

[
  Thread.new { transfer(client_conn, dest_conn) },
  Thread.new { transfer(dest_conn, client_conn) }
].each(&:join)

I worked on the following small projects to familiarize myself with forward proxies: