Looking at an HTTP/1.1 Session
Our recent foray into TCP/IP led us to look at HTTP as a prime example of an application layer protocol. Today I thought it would be fun to look at an HTTP request/response interaction with Wireshark. Let’s break it down step by step and see exactly how HTTP/1.1 plays out over TCP.
When I run:
1curl -v http://google.com -H "Connection: close"
I see the following:
* Host google.com:80 was resolved.
* IPv6: (none)
* IPv4: 142.250.72.174
* Trying 142.250.72.174:80...
* Connected to google.com (142.250.72.174) port 80
> GET / HTTP/1.1
> Host: google.com
> User-Agent: curl/8.7.1
> Accept: */*
> Connection: close
>
* Request completely sent off
< HTTP/1.1 301 Moved Permanently
< Location: http://www.google.com/
< Content-Type: text/html; charset=UTF-8
< Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-EB7GxjMVJsa5Mr_7PWB0yA' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
< Date: Wed, 12 Feb 2025 01:43:25 GMT
< Expires: Fri, 14 Mar 2025 01:43:25 GMT
< Cache-Control: public, max-age=2592000
< Server: gws
< Content-Length: 219
< X-XSS-Protection: 0
< X-Frame-Options: SAMEORIGIN
< Connection: close
<
<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="http://www.google.com/">here</A>.
</BODY></HTML>
* Closing connection
Looking at Wireshark, I see the following capture:
The first few segments set up the TCP connection. You can see the “three-way handshake” in action:
With the TCP connection established we make the HTTP GET
request. The server acknowledges this before sending the response:
In principle, the server could bundle the above ACK
with the actual
HTTP response, but doing so would introduce a delay if the response
isn’t ready immediately. So it plays it safe: first, it sends an
ACK
, then it responds to the request.
The next segment has the actual HTTP response, which we acknowledge:
Finally, the TCP connection is torn down. I ran this experiment twice, and the next screenshot is from the second run, but the behavior and relative sequence numbers are the same. I was expecting to see a three-way handshake, but there are four segments here:
Recall that I asked curl to use the Connection: close
header in my
request. This tells Google that it is free to close the connection
once it has served a response. What we see in the above screenshot is
that both sides of the TCP connection initiate a close
simultaneously. Because of this, each FIN
is sent before receiving
the other’s. Since a FIN
gets its own sequence number, it requires a
separate ACK
. So we need an extra acknowledgment to fully close
this connection.
The takeaway here is that we can see HTTP riding on TCP just by sniffing packets. This gives a solid sanity check for what we have already learned about these protocols.