Checking https://github.com/diracdeltas/FastestWebsiteEver was on my TODO list. Let’s see some details in Wireshark and review some TCP/IP details.
You can check http://packet.city/ if you want to avoid setting up the service yourself.
So you open Wireshark and you start capturing. Visit http://packet.city and you can use a Wireshark filter for the resolved IP for packet.city.
The project states that it is “the greatest website to ever fit in a single TCP packet”.
Is it true? Let’see what it needs: I can see 9 packets and some details.
First 3 packets (handshake)
Like any normal TCP connection we start with a 3-way handshake:
- First, my laptop sends a SYN packet with an Initial Sequence Number which can be seen 0 in Wireshark but that’s actually a relative over a random. This is my laptop requesting proof that its message can get through.
- The server needs to send an ACK packet (to prove SYN received) and its own SYN (to prove it can reach the client). We can see it’s actually done in the same sent packet: SYN-ACK
- My laptop receives the SYN-ACK: as its an ACK it knows it can send a packet to the server and as its a SYN it knows that the server needs an ACK, so it sends such ACK.
- Once the server receives that ACK handshake has finished and the channel is considered feasible. However it might have been like, but this is the minimum to start trying to communicate.
Packet #4 (GET)
We’ve finished with the 3 first packets. The fourth one is the GET request.
Notice that Push flag is enabled (PSH) and also ACK as with any exchanged packet during the communication.
In HyperText Transport Protocol we can see the sent HTTP request:
#5 and #6 packets
Packet #5 is an ACK:
Next packet is the HTTP GET response:
I guess this is what the project describes as “send response immediately after TCP session init”
I think PSH is enabled because Nagle’s algorithm is disabled as the project describes too.
See that Response is “200 k” instead of “200 OK”: 1 byte saved there.
Content encoded is 1163 bytes (1547 bytes decoded), far from needing fragmentation:
The maximum would be 1460 bytes for content and 40 bytes for IP and TCP headers.
In this case, the frame is 1292 bytes, TCP segment length is 1226 bytes and HTTP Content-Length is 1163 bytes, in detail:
- Frame header (14 bytes): 7 bytes for preamble, 1 byte for SFD, 12 bytes for source and destination MACs and 2 bytes for packet type (IP) –> 22 bytes (14 ignoring preamble and SFD)
- IP header (20 bytes): 1 byte for ip.version (4), 1 byte for ip.dsfield, 2 bytes for ip.len (Length), 2 bytes for ip.id (ID), 1 byte for ip.flags (0x02, ip.flags.df (Don’t Fragment )is set), 2 bytes for ip.frag_offset (Fragment Offset), 1 byte for ip.ttl (TTL), 1 byte for ip.proto (Protocol), 2 bytes for ip.checksum (Header checksum) and 8 bytes for ip.src and ip.dst.
- TCP header (32 bytes): 4 bytes for tcp.srcport and tcp.dstport, 4 bytes for tcp.seq (Sequence Number), 4 bytes for tcp.ack (Ack Number), 2 bytes for tcp.flags, 2 bytes for tcp.window_size_value, 2 bytes for tcp.checksum, 2 bytes for tcp.urgent_pointer, 12 bytes for tcp.options
- HTTP (1226 bytes): 15 bytes for “HTTP/1.1 200 k\n”, 21 bytes for http.content_length_header, 26 bytes for http.content_encoding_header, 1 byte of “\n” and 1163 bytes for Content (encoded)
About the HTTP response content, it’s easier seeing the source code in the browser, there you’ll see:
Last 3 packets
Finally last 3 packets. Server resets the connection with RST packet. I guess they could use FIN but RST is quicker. More about FIN vs RST.
That’s all 🙂