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 connectionLooking 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.