From 147f5680bc29e57b5a2d5bbb40fe5878bb4a4744 Mon Sep 17 00:00:00 2001 From: Chris Broadfoot Date: Thu, 11 Oct 2018 17:31:38 -0700 Subject: [PATCH] [release-branch.go1.11] godoc/proxy: remove use of httputil.ReverseProxy for /share ReverseProxy doesn't re-set the Request's Host field, only Request.URL.Host. The HTTP/2 client prefers Request.Host over Request.URL.Host, so this results in the request being sent back to the host that originally accepted the request. This results in an infinite redirect (and consumption of many connections to itself). See Issue golang/go#28168 for details. Replace it with a simple proxy that drops all the headers (except Content-Type). I tried setting the proxy.Director, but it still didn't work. Could do with some more investigation. Fixes golang/go#28134. Change-Id: I5051ce72a379dcacfbe8484f58f8cf7d9385024d Reviewed-on: https://go-review.googlesource.com/c/141718 Run-TryBot: Chris Broadfoot TryBot-Result: Gobot Gobot Reviewed-by: Brad Fitzpatrick (cherry picked from commit 837e80568c097270a86b7410b4b6d2f8de427d2e) Reviewed-on: https://go-review.googlesource.com/c/153858 Run-TryBot: Andrew Bonventre --- cmd/godoc/regtest_test.go | 16 ++++++++++++++++ godoc/proxy/proxy.go | 33 +++++++++++++++++++++++---------- 2 files changed, 39 insertions(+), 10 deletions(-) diff --git a/cmd/godoc/regtest_test.go b/cmd/godoc/regtest_test.go index 7e760170..f7c7219a 100644 --- a/cmd/godoc/regtest_test.go +++ b/cmd/godoc/regtest_test.go @@ -36,6 +36,7 @@ func TestLiveServer(t *testing.T) { Regexp string NoAnalytics bool // expect the response to not contain GA. PostBody string + StatusCode int // if 0, expect 2xx status code. }{ { Path: "/doc/faq", @@ -65,6 +66,7 @@ func TestLiveServer(t *testing.T) { Substring: "bdb10cf", Message: "no change redirect - hg to git mapping not registered?", NoAnalytics: true, + StatusCode: 302, }, { Path: "/dl/", @@ -81,6 +83,7 @@ func TestLiveServer(t *testing.T) { Path: "/s/go2design", Regexp: "proposal.*Found", NoAnalytics: true, + StatusCode: 302, }, { Message: "incorrect search result - broken index?", @@ -105,6 +108,12 @@ func TestLiveServer(t *testing.T) { Regexp: `^{"Errors":"","Events":\[{"Message":"A","Kind":"stdout","Delay":0},{"Message":"B","Kind":"stdout","Delay":1000000000}\]}$`, NoAnalytics: true, }, + { + Path: "/share", + PostBody: "package main", + Substring: "", // just check it is a 2xx. + NoAnalytics: true, + }, } for _, tc := range substringTests { @@ -126,6 +135,13 @@ func TestLiveServer(t *testing.T) { if err != nil { t.Fatalf("RoundTrip: %v", err) } + if tc.StatusCode == 0 { + if resp.StatusCode > 299 { + t.Errorf("Non-OK status code: %v", resp.StatusCode) + } + } else if tc.StatusCode != resp.StatusCode { + t.Errorf("StatusCode; got %v, want %v", resp.StatusCode, tc.StatusCode) + } body, err := ioutil.ReadAll(resp.Body) if err != nil { t.Fatalf("ReadAll: %v", err) diff --git a/godoc/proxy/proxy.go b/godoc/proxy/proxy.go index f3023727..bd1ef006 100644 --- a/godoc/proxy/proxy.go +++ b/godoc/proxy/proxy.go @@ -10,11 +10,10 @@ import ( "bytes" "encoding/json" "fmt" + "io" "io/ioutil" "log" "net/http" - "net/http/httputil" - "net/url" "strings" "time" @@ -24,13 +23,6 @@ import ( const playgroundURL = "https://play.golang.org" -var proxy *httputil.ReverseProxy - -func init() { - target, _ := url.Parse(playgroundURL) - proxy = httputil.NewSingleHostReverseProxy(target) -} - type Request struct { Body string } @@ -136,7 +128,28 @@ func share(w http.ResponseWriter, r *http.Request) { http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) return } - proxy.ServeHTTP(w, r) + + // HACK(cbro): use a simple proxy rather than httputil.ReverseProxy because of Issue #28168. + // TODO: investigate using ReverseProxy with a Director, unsetting whatever's necessary to make that work. + req, _ := http.NewRequest("POST", playgroundURL+"/share", r.Body) + req.Header.Set("Content-Type", r.Header.Get("Content-Type")) + req = req.WithContext(r.Context()) + resp, err := http.DefaultClient.Do(req) + if err != nil { + log.Printf("ERROR share error: %v", err) + http.Error(w, "Internal Server Error", http.StatusInternalServerError) + return + } + copyHeader := func(k string) { + if v := resp.Header.Get(k); v != "" { + w.Header().Set(k, v) + } + } + copyHeader("Content-Type") + copyHeader("Content-Length") + defer resp.Body.Close() + w.WriteHeader(resp.StatusCode) + io.Copy(w, resp.Body) } func googleCN(r *http.Request) bool {