Skip to content

Commit 2cc3473

Browse files
liggittbradfitz
authored andcommitted
net/http/httputil: make ReverseProxy flush headers on FlushInterval
A regression was introduced in CL 137335 (5440bfc) that caused FlushInterval to not be honored until the first Write() call was encountered. This change starts the flush timer as part of setting up the maxLatencyWriter. Fixes #31125 Fixes #31126 Change-Id: I75325bd926652922219bd1457b2b00ac6d0d41b0 Reviewed-on: https://go-review.googlesource.com/c/go/+/170066 Reviewed-by: Brad Fitzpatrick <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 70ea70e commit 2cc3473

File tree

2 files changed

+47
-0
lines changed

2 files changed

+47
-0
lines changed

src/net/http/httputil/reverseproxy.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,11 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader, flushInterval
389389
latency: flushInterval,
390390
}
391391
defer mlw.stop()
392+
393+
// set up initial timer so headers get flushed even if body writes are delayed
394+
mlw.flushPending = true
395+
mlw.t = time.AfterFunc(flushInterval, mlw.delayedFlush)
396+
392397
dst = mlw
393398
}
394399
}

src/net/http/httputil/reverseproxy_test.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package httputil
99
import (
1010
"bufio"
1111
"bytes"
12+
"context"
1213
"errors"
1314
"fmt"
1415
"io"
@@ -317,6 +318,47 @@ func TestReverseProxyFlushInterval(t *testing.T) {
317318
}
318319
}
319320

321+
func TestReverseProxyFlushIntervalHeaders(t *testing.T) {
322+
const expected = "hi"
323+
stopCh := make(chan struct{})
324+
backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
325+
w.Header().Add("MyHeader", expected)
326+
w.WriteHeader(200)
327+
w.(http.Flusher).Flush()
328+
<-stopCh
329+
}))
330+
defer backend.Close()
331+
defer close(stopCh)
332+
333+
backendURL, err := url.Parse(backend.URL)
334+
if err != nil {
335+
t.Fatal(err)
336+
}
337+
338+
proxyHandler := NewSingleHostReverseProxy(backendURL)
339+
proxyHandler.FlushInterval = time.Microsecond
340+
341+
frontend := httptest.NewServer(proxyHandler)
342+
defer frontend.Close()
343+
344+
req, _ := http.NewRequest("GET", frontend.URL, nil)
345+
req.Close = true
346+
347+
ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
348+
defer cancel()
349+
req = req.WithContext(ctx)
350+
351+
res, err := frontend.Client().Do(req)
352+
if err != nil {
353+
t.Fatalf("Get: %v", err)
354+
}
355+
defer res.Body.Close()
356+
357+
if res.Header.Get("MyHeader") != expected {
358+
t.Errorf("got header %q; expected %q", res.Header.Get("MyHeader"), expected)
359+
}
360+
}
361+
320362
func TestReverseProxyCancelation(t *testing.T) {
321363
const backendResponse = "I am the backend"
322364

0 commit comments

Comments
 (0)