Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.Sign up
x/net/http2: decide what to do about Transport.CancelRequest #13540
The net/http.Transport.CancelRequest method is an old feature & wart.
There is no interface which defines it, but it's sniffed for by many RoundTrippers and users of RoundTrippers (including net/http.Client for its Client.Timeout feature), and it's a thorn in the side of people trying to write composable RoundTripper implementations.
The modern replacement is the net/http.Request.Cancel receive-only channel to do cancelations. (closed by caller on cancel)
Unfortunately, net/http.Client doesn't use the Cancel channel. Perhaps it could. But that would require mutating the caller's *Request, at least for Do. But for net/http.Client methods like Get, Head, Post, and PostForm, we create the *http.Request, so we could set the Cancel channel appropriately.
That leaves net/http.Client.Do, which takes a raw *Request. Is it allowed to set the Cancel channel if it's nil? Probably not? Or maybe there is precedent in mutating the Request: we read from the Request.Body, so it's not safe to use concurrently already. So maybe we can just save/restore the Request.Cancel field.
Related to that debate is whether x/net/http2.Transport should have an old-style CancelRequest method. It would really be nice to stop letting that mistake infect things, though, spreading the idea that everybody needs to implement CancelRequest.
But unfortunately as-is, Client Timeouts are failing with http2: https://go-review.googlesource.com/#/c/17528/1 From the second comment:
Could we make CancelRequest do nothing? It is already racy, so it's effectively best effort and we could just drop the effort. That would mean that net/http.Client doesn't have to change except to use the channel. I'm not sure I see why that would imply it has to mutate the request.
Or make CancelRequest close the Cancel channel?
No, that's not really a great option. It does work mostly work today. It's only in some edge cases that it doesn't work.
So you're okay with Client using the channel? That means temporarily mutating & restoring the field on the Request because a Client uses a RoundTripper (e.g. Transport) (or potentially N RoundTripper composed deep) and passes down a Request (which has a Cancel). The Cancel (read: "context") is not a separate argument.