Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chapter 20.3: Suggestion to add a note about Chrome spawning additional TCP connections #3545

Open
karen-sarkisyan opened this issue Feb 19, 2023 · 2 comments · May be fixed by #3753
Open

Comments

@karen-sarkisyan
Copy link

karen-sarkisyan commented Feb 19, 2023

Hi,

I’ve tried the final project in the book, and it’s really great stuff, I learned a lot. Thanks to everyone who took part in making it.

There was one thing that left me really confused though, and I’d like to make a humble suggestion. Maybe for book’s next edition, in case you agree.

In the final version, when we make 2 requests, the server goes to a shutdown. What I didn’t know, is that Chrome would randomly open TCP connections without sending any data. For example, that’s the output that made me wonder what's going on:

image

It looks as if server tries to go to a shut down after 1 request. Took me some digging, but as I understand it, here’s what actually happens:

  1. Chrome sends GET / request and then establishes a second TCP connection without sending anything over it. That second connection’s job goes to a thread as intended.
  2. Meanwhile, main thread is finished, because it registered 2 connections. Loop exits, ThreadPool goes out of scope and Drop trait is called.
  3. The thread that received the second TCP connection is executing handle_connection() function where stream.read() is waiting for data to come. So until it gets data or connection closes, the thread keeps working.

You can emulate this behavior using these commands in terminal.
To open TCP connection, send an invalid HTTP request, and close connection:

echo -n | nc 127.0.0.1 7878

To open a second TCP connection and keep it until further input, which seems like what Chrome does in the example:

nc 127.0.0.1 7878

My suggestion is to add a note about this, because in previous chapters a few valuable notes were made about particularities of browsers.

Most people probably use Chrome to try it out. They will see that something weird’s going on with graceful shutdown, and Chrome devtools don’t hint there’s something else is sent apart from a single GET request.

For example, a helpful note could be:

Another interesting thing you might notice is that when you use Chrome, you can see main thread going into shutdown before you make a second request, with one last thread still working. It happens because browsers can open up a few TCP connections without sending HTTP requests (or anything) over them. Our server shuts down after 2 connections, while handle_connection() function will wait on a given TCP connection until data comes.

To test your server in a more controlled fashion, use HTTP clients like Postman or Insomnia.

Or something along those lines.

Alternatively, it could certainly be left as it is. I learned something while trying to figure it out, others might also want to. 🙂

ludi317 added a commit to ludi317/hello_webserver that referenced this issue Oct 22, 2023
Someone opened an issue for different symptoms of the same underlying behavior. They noticed that Chrome's preconnections were delaying graceful server shutdown. rust-lang/book#3545
@ludi317
Copy link

ludi317 commented Oct 24, 2023

Hi @karen-sarkisyan, I saw the same behavior from Chrome as you describe here: Chrome opens TCP connections to the server without sending data. They delay graceful server shutdown until Chrome closes them -- at which point they cause the server to panic.

I did some digging and found out that these connections are due to a Chrome browser optimization called "TCP pre-connect". Chrome predicts you will make another request to the server in the near future based on your browsing history, and opens them ahead of time. You can read more here.

You can disable this behavior by using Chrome in Incognito mode. HTH.

@chriskrycho
Copy link
Contributor

Thanks for the note here! This is definitely kind of annoying! One of us will try to dig in and see about how to tackle it (the suggested revision over on #3753 being one possible approach, a more robust implementation that handles it correctly being another) before we get the next edition published.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants