]> Cypherpunks repositories - gostls13.git/commitdiff
net/http/httputil: make ReverseProxy flush headers on FlushInterval
authorJordan Liggitt <liggitt@google.com>
Fri, 29 Mar 2019 03:37:54 +0000 (23:37 -0400)
committerBrad Fitzpatrick <bradfitz@golang.org>
Fri, 29 Mar 2019 15:56:57 +0000 (15:56 +0000)
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 <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/net/http/httputil/reverseproxy.go
src/net/http/httputil/reverseproxy_test.go

index 92d7f63af5d0281afe0f1212fb293f201105a418..0e0731b08f08c74b8b827bc0624d418496bbe9f6 100644 (file)
@@ -389,6 +389,11 @@ func (p *ReverseProxy) copyResponse(dst io.Writer, src io.Reader, flushInterval
                                latency: flushInterval,
                        }
                        defer mlw.stop()
+
+                       // set up initial timer so headers get flushed even if body writes are delayed
+                       mlw.flushPending = true
+                       mlw.t = time.AfterFunc(flushInterval, mlw.delayedFlush)
+
                        dst = mlw
                }
        }
index 5edefa08e55a3c1a17bda4d4957b12dbc4bfeb91..367ba73ae2497919748186a3ec886a0f17b8eef7 100644 (file)
@@ -9,6 +9,7 @@ package httputil
 import (
        "bufio"
        "bytes"
+       "context"
        "errors"
        "fmt"
        "io"
@@ -317,6 +318,47 @@ func TestReverseProxyFlushInterval(t *testing.T) {
        }
 }
 
+func TestReverseProxyFlushIntervalHeaders(t *testing.T) {
+       const expected = "hi"
+       stopCh := make(chan struct{})
+       backend := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+               w.Header().Add("MyHeader", expected)
+               w.WriteHeader(200)
+               w.(http.Flusher).Flush()
+               <-stopCh
+       }))
+       defer backend.Close()
+       defer close(stopCh)
+
+       backendURL, err := url.Parse(backend.URL)
+       if err != nil {
+               t.Fatal(err)
+       }
+
+       proxyHandler := NewSingleHostReverseProxy(backendURL)
+       proxyHandler.FlushInterval = time.Microsecond
+
+       frontend := httptest.NewServer(proxyHandler)
+       defer frontend.Close()
+
+       req, _ := http.NewRequest("GET", frontend.URL, nil)
+       req.Close = true
+
+       ctx, cancel := context.WithTimeout(req.Context(), 10*time.Second)
+       defer cancel()
+       req = req.WithContext(ctx)
+
+       res, err := frontend.Client().Do(req)
+       if err != nil {
+               t.Fatalf("Get: %v", err)
+       }
+       defer res.Body.Close()
+
+       if res.Header.Get("MyHeader") != expected {
+               t.Errorf("got header %q; expected %q", res.Header.Get("MyHeader"), expected)
+       }
+}
+
 func TestReverseProxyCancelation(t *testing.T) {
        const backendResponse = "I am the backend"