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

proposal: net/http: ResponseController.SetBidi to support concurrent Request.Body reads and ResponseWriter.Writes #57786

Open
neild opened this issue Jan 13, 2023 · 5 comments
Labels
Milestone

Comments

@neild
Copy link
Contributor

neild commented Jan 13, 2023

This proposal aims to address #15527.

The net/http HTTP/1 server does not permit reading from an inbound request body after starting to write the response. (See the ResponseWriter.Write documentation).

This limitation is because the server drains any unread portion of the request body before writing the response headers, to avoid deadlocking clients that attempt to write a complete request before reading the response. (See #15527 (comment) for more context.)

I propose that we offer an opt-in mechanism to disable this behavior, permitting a server handler to write some or all of the response interleaved with reads from the request.

// SetBidi indicates whether the request handler will interleave reads from Request.Body with
// writes to the ResponseWriter.
//
// For HTTP/1 requests, the Go HTTP server by default consumes any unread portion of the request
// body before beginning to write the response, preventing handlers from concurrently reading from
// the request and writing the response. Calling SetBidi(true) disables this behavior and permits
// handlers to continue to read from the request while concurrently writing the response.
//
// For HTTP/2 requests, the Go HTTP server always permits concurrent reads and responses.
func (c *ResponseController) SetBidi(bidi bool) error {}
@rsc
Copy link
Contributor

rsc commented Feb 1, 2023

"bidi" often means bidirectional text like Unicode LTR/RTL.
It seems like a very short name for a rarely used feature.
Is there a standard name for this behavior in the HTTP specs?
It's unclear from the docs whether c.SetBidi(false) has an effect on HTTP/2 (or returns an error?).

@rsc
Copy link
Contributor

rsc commented Feb 1, 2023

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

@neild
Copy link
Contributor Author

neild commented Feb 1, 2023

I don't believe there is a standard name for this behavior. I'm not committed to the name here; EnableInterleavedReadsAndWrites would be unambiguous if long. EnableResponseInterleaving? EnableInterleave? EnableConcurrentResponse?

SetBidi(false) will return an error for HTTP/2 requests. We already support interleaving for HTTP/2, and I don't see any value in disabling it. The reason for draining the inbound request before responding is to work better with naive clients, and a naive HTTP/2 client is somewhat of an oxymoron.

Ideally we wouldn't have a knob here, but I don't see how to avoid it; there are valid reasons to want both possible behaviors here, and changing our current default will break some users.

@seankhliao
Copy link
Member

informational rfc: bidirectional http
internet draft: full duplex

@neild
Copy link
Contributor Author

neild commented Feb 1, 2023

I like EnableFullDuplex.

And perhaps only permit enabling full duplex, to avoid any questions about what it means to disable it with HTTP/2 or HTTP/3.

func (c *ResponseController) EnableFullDuplex() error {}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
Status: Active
Development

No branches or pull requests

4 participants