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

x/net/http2: client stream left unclosed after response status >=300 #48610

Open
neild opened this issue Sep 24, 2021 · 2 comments
Open

x/net/http2: client stream left unclosed after response status >=300 #48610

neild opened this issue Sep 24, 2021 · 2 comments
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@neild
Copy link
Contributor

neild commented Sep 24, 2021

On receiving a 3xx, 4xx, 5xx, etc. response while writing a request body, the HTTP/2 RoundTrip cancels the body write and returns:
https://go.googlesource.com/net/+/3ad01bbaa167859dcfbcce635f3c43f6e900be62/http2/transport.go#1171

In this case, the client does nothing to terminate its side of the stream--it doesn't send END_STREAM or RST_STREAM. The stream will remain open or in a half-closed state until the server resets it.

In addition, we remove the stream from ClientConn.streams in this case, which means we no longer count it against the stream concurrency limit.

We should either send a RST_STREAM when we've given up writing, or write the request body even on a 3xx etc response. (The server can still reset the stream if it doesn't care about the body.)

@gopherbot
Copy link

Change https://golang.org/cl/352113 mentions this issue: http2: reset streams when abandoning request body write

@neild
Copy link
Contributor Author

neild commented Sep 24, 2021

Hm, this is trickier than I thought.

I was mistaken about us removing the stream from ClientConn.streams upon receiving a response with a status >=300. We only remove the stream later, usually when Request.Body is closed.

When Request.Body is closed, we send a RST_STREAM if the server hasn't closed its side of the stream. If the server has closed its side of the stream, we forget the stream and send nothing.

If Request.Body is closed when the server has closed its side of the stream and we have not finished writing the request body, we will abandon the stream in a half-closed state. This is true whether we received a >= 300 status or not, but it is more likely to occur in this case because a 300 response halts the body write.

So a client-initiated stream is left unclosed if:

  • There is a request body.
  • The body is not fully written when Response.Body is closed.
  • The server half-closes the stream before Response.Body is closed.

I haven't found a way to demonstrate this condition with the x/net/http2 server, because our server implementation sends a RST_STREAM after sending any frame which half-closes a stream. (See *serverConn.wroteFrame.)

@mknyszek mknyszek added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Oct 4, 2021
@mknyszek mknyszek added this to the Unreleased milestone Oct 4, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

No branches or pull requests

3 participants