HTTP Connect By Example
· 2 min read
networking
programming
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.
This allows the client and destination to utilize various application layer interactions supported over the transport layer.
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)
Links
I worked on the following small projects to familiarize myself with forward proxies:
- ForwardProxy - A 150 LOC proxy written in Ruby for learning and development.
- GoForward - A rate limiting proxy written in Go based on Michał Łowicki’s original code.
- Alpaca - A proxy supporting PAC scripts and NTLM authentication.