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 <cbro@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
Chris Broadfoot 2018-10-11 17:31:38 -07:00 коммит произвёл Andrew Bonventre
Родитель 59cd96f77e
Коммит 837e80568c
2 изменённых файлов: 39 добавлений и 10 удалений

Просмотреть файл

@ -36,6 +36,7 @@ func TestLiveServer(t *testing.T) {
Regexp string Regexp string
NoAnalytics bool // expect the response to not contain GA. NoAnalytics bool // expect the response to not contain GA.
PostBody string PostBody string
StatusCode int // if 0, expect 2xx status code.
}{ }{
{ {
Path: "/doc/faq", Path: "/doc/faq",
@ -65,6 +66,7 @@ func TestLiveServer(t *testing.T) {
Substring: "bdb10cf", Substring: "bdb10cf",
Message: "no change redirect - hg to git mapping not registered?", Message: "no change redirect - hg to git mapping not registered?",
NoAnalytics: true, NoAnalytics: true,
StatusCode: 302,
}, },
{ {
Path: "/dl/", Path: "/dl/",
@ -81,6 +83,7 @@ func TestLiveServer(t *testing.T) {
Path: "/s/go2design", Path: "/s/go2design",
Regexp: "proposal.*Found", Regexp: "proposal.*Found",
NoAnalytics: true, NoAnalytics: true,
StatusCode: 302,
}, },
{ {
Message: "incorrect search result - broken index?", 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}\]}$`, Regexp: `^{"Errors":"","Events":\[{"Message":"A","Kind":"stdout","Delay":0},{"Message":"B","Kind":"stdout","Delay":1000000000}\]}$`,
NoAnalytics: true, NoAnalytics: true,
}, },
{
Path: "/share",
PostBody: "package main",
Substring: "", // just check it is a 2xx.
NoAnalytics: true,
},
} }
for _, tc := range substringTests { for _, tc := range substringTests {
@ -126,6 +135,13 @@ func TestLiveServer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("RoundTrip: %v", err) 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) body, err := ioutil.ReadAll(resp.Body)
if err != nil { if err != nil {
t.Fatalf("ReadAll: %v", err) t.Fatalf("ReadAll: %v", err)

Просмотреть файл

@ -11,11 +11,10 @@ import (
"context" "context"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http" "net/http"
"net/http/httputil"
"net/url"
"strings" "strings"
"time" "time"
@ -24,13 +23,6 @@ import (
const playgroundURL = "https://play.golang.org" const playgroundURL = "https://play.golang.org"
var proxy *httputil.ReverseProxy
func init() {
target, _ := url.Parse(playgroundURL)
proxy = httputil.NewSingleHostReverseProxy(target)
}
type Request struct { type Request struct {
Body string Body string
} }
@ -136,7 +128,28 @@ func share(w http.ResponseWriter, r *http.Request) {
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
return 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 { func googleCN(r *http.Request) bool {