@@ -1121,6 +1121,45 @@ func TestReverseProxy_PanicBodyError(t *testing.T) {
1121
1121
rproxy .ServeHTTP (httptest .NewRecorder (), req )
1122
1122
}
1123
1123
1124
+ // Issue #46866: panic without closing incoming request body causes a panic
1125
+ func TestReverseProxy_PanicClosesIncomingBody (t * testing.T ) {
1126
+ backend := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
1127
+ out := "this call was relayed by the reverse proxy"
1128
+ // Coerce a wrong content length to induce io.ErrUnexpectedEOF
1129
+ w .Header ().Set ("Content-Length" , fmt .Sprintf ("%d" , len (out )* 2 ))
1130
+ fmt .Fprintln (w , out )
1131
+ }))
1132
+ defer backend .Close ()
1133
+ backendURL , err := url .Parse (backend .URL )
1134
+ if err != nil {
1135
+ t .Fatal (err )
1136
+ }
1137
+ proxyHandler := NewSingleHostReverseProxy (backendURL )
1138
+ proxyHandler .ErrorLog = log .New (io .Discard , "" , 0 ) // quiet for tests
1139
+ frontend := httptest .NewServer (proxyHandler )
1140
+ defer frontend .Close ()
1141
+ frontendClient := frontend .Client ()
1142
+
1143
+ var wg sync.WaitGroup
1144
+ for i := 0 ; i < 2 ; i ++ {
1145
+ wg .Add (1 )
1146
+ go func () {
1147
+ defer wg .Done ()
1148
+ for j := 0 ; j < 10 ; j ++ {
1149
+ const reqLen = 6 * 1024 * 1024
1150
+ req , _ := http .NewRequest ("POST" , frontend .URL , & io.LimitedReader {R : neverEnding ('x' ), N : reqLen })
1151
+ req .ContentLength = reqLen
1152
+ resp , _ := frontendClient .Transport .RoundTrip (req )
1153
+ if resp != nil {
1154
+ io .Copy (io .Discard , resp .Body )
1155
+ resp .Body .Close ()
1156
+ }
1157
+ }
1158
+ }()
1159
+ }
1160
+ wg .Wait ()
1161
+ }
1162
+
1124
1163
func TestSelectFlushInterval (t * testing.T ) {
1125
1164
tests := []struct {
1126
1165
name string
0 commit comments