@@ -203,6 +203,9 @@ type Hijacker interface {
203
203
//
204
204
// This mechanism can be used to cancel long operations on the server
205
205
// if the client has disconnected before the response is ready.
206
+ //
207
+ // Deprecated: the CloseNotifier interface predates Go's context package.
208
+ // New code should use Request.Context instead.
206
209
type CloseNotifier interface {
207
210
// CloseNotify returns a channel that receives at most a
208
211
// single value (true) when the client connection has gone
@@ -674,10 +677,28 @@ func (cr *connReader) backgroundRead() {
674
677
cr .lock ()
675
678
if n == 1 {
676
679
cr .hasByte = true
677
- // We were at EOF already (since we wouldn't be in a
678
- // background read otherwise), so this is a pipelined
679
- // HTTP request.
680
- cr .closeNotifyFromPipelinedRequest ()
680
+ // We were past the end of the previous request's body already
681
+ // (since we wouldn't be in a background read otherwise), so
682
+ // this is a pipelined HTTP request. Prior to Go 1.11 we used to
683
+ // send on the CloseNotify channel and cancel the context here,
684
+ // but the behavior was documented as only "may", and we only
685
+ // did that because that's how CloseNotify accidentally behaved
686
+ // in very early Go releases prior to context support. Once we
687
+ // added context support, people used a Handler's
688
+ // Request.Context() and passed it along. Having that context
689
+ // cancel on pipelined HTTP requests caused problems.
690
+ // Fortunately, almost nothing uses HTTP/1.x pipelining.
691
+ // Unfortunately, apt-get does, or sometimes does.
692
+ // New Go 1.11 behavior: don't fire CloseNotify or cancel
693
+ // contexts on pipelined requests. Shouldn't affect people, but
694
+ // fixes cases like Issue 23921. This does mean that a client
695
+ // closing their TCP connection after sending a pipelined
696
+ // request won't cancel the context, but we'll catch that on any
697
+ // write failure (in checkConnErrorWriter.Write).
698
+ // If the server never writes, yes, there are still contrived
699
+ // server & client behaviors where this fails to ever cancel the
700
+ // context, but that's kinda why HTTP/1.x pipelining died
701
+ // anyway.
681
702
}
682
703
if ne , ok := err .(net.Error ); ok && cr .aborted && ne .Timeout () {
683
704
// Ignore this error. It's the expected error from
@@ -724,19 +745,6 @@ func (cr *connReader) handleReadError(_ error) {
724
745
cr .closeNotify ()
725
746
}
726
747
727
- // closeNotifyFromPipelinedRequest simply calls closeNotify.
728
- //
729
- // This method wrapper is here for documentation. The callers are the
730
- // cases where we send on the closenotify channel because of a
731
- // pipelined HTTP request, per the previous Go behavior and
732
- // documentation (that this "MAY" happen).
733
- //
734
- // TODO: consider changing this behavior and making context
735
- // cancelation and closenotify work the same.
736
- func (cr * connReader ) closeNotifyFromPipelinedRequest () {
737
- cr .closeNotify ()
738
- }
739
-
740
748
// may be called from multiple goroutines.
741
749
func (cr * connReader ) closeNotify () {
742
750
res , _ := cr .conn .curReq .Load ().(* response )
@@ -1834,9 +1842,6 @@ func (c *conn) serve(ctx context.Context) {
1834
1842
if requestBodyRemains (req .Body ) {
1835
1843
registerOnHitEOF (req .Body , w .conn .r .startBackgroundRead )
1836
1844
} else {
1837
- if w .conn .bufr .Buffered () > 0 {
1838
- w .conn .r .closeNotifyFromPipelinedRequest ()
1839
- }
1840
1845
w .conn .r .startBackgroundRead ()
1841
1846
}
1842
1847
0 commit comments