Skip to content

Commit 837e805

Browse files
broadyandybons
authored andcommitted
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 <[email protected]> TryBot-Result: Gobot Gobot <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 59cd96f commit 837e805

File tree

2 files changed

+39
-10
lines changed

2 files changed

+39
-10
lines changed

cmd/godoc/regtest_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ func TestLiveServer(t *testing.T) {
3636
Regexp string
3737
NoAnalytics bool // expect the response to not contain GA.
3838
PostBody string
39+
StatusCode int // if 0, expect 2xx status code.
3940
}{
4041
{
4142
Path: "/doc/faq",
@@ -65,6 +66,7 @@ func TestLiveServer(t *testing.T) {
6566
Substring: "bdb10cf",
6667
Message: "no change redirect - hg to git mapping not registered?",
6768
NoAnalytics: true,
69+
StatusCode: 302,
6870
},
6971
{
7072
Path: "/dl/",
@@ -81,6 +83,7 @@ func TestLiveServer(t *testing.T) {
8183
Path: "/s/go2design",
8284
Regexp: "proposal.*Found",
8385
NoAnalytics: true,
86+
StatusCode: 302,
8487
},
8588
{
8689
Message: "incorrect search result - broken index?",
@@ -105,6 +108,12 @@ func TestLiveServer(t *testing.T) {
105108
Regexp: `^{"Errors":"","Events":\[{"Message":"A","Kind":"stdout","Delay":0},{"Message":"B","Kind":"stdout","Delay":1000000000}\]}$`,
106109
NoAnalytics: true,
107110
},
111+
{
112+
Path: "/share",
113+
PostBody: "package main",
114+
Substring: "", // just check it is a 2xx.
115+
NoAnalytics: true,
116+
},
108117
}
109118

110119
for _, tc := range substringTests {
@@ -126,6 +135,13 @@ func TestLiveServer(t *testing.T) {
126135
if err != nil {
127136
t.Fatalf("RoundTrip: %v", err)
128137
}
138+
if tc.StatusCode == 0 {
139+
if resp.StatusCode > 299 {
140+
t.Errorf("Non-OK status code: %v", resp.StatusCode)
141+
}
142+
} else if tc.StatusCode != resp.StatusCode {
143+
t.Errorf("StatusCode; got %v, want %v", resp.StatusCode, tc.StatusCode)
144+
}
129145
body, err := ioutil.ReadAll(resp.Body)
130146
if err != nil {
131147
t.Fatalf("ReadAll: %v", err)

godoc/proxy/proxy.go

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,10 @@ import (
1111
"context"
1212
"encoding/json"
1313
"fmt"
14+
"io"
1415
"io/ioutil"
1516
"log"
1617
"net/http"
17-
"net/http/httputil"
18-
"net/url"
1918
"strings"
2019
"time"
2120

@@ -24,13 +23,6 @@ import (
2423

2524
const playgroundURL = "https://play.golang.org"
2625

27-
var proxy *httputil.ReverseProxy
28-
29-
func init() {
30-
target, _ := url.Parse(playgroundURL)
31-
proxy = httputil.NewSingleHostReverseProxy(target)
32-
}
33-
3426
type Request struct {
3527
Body string
3628
}
@@ -136,7 +128,28 @@ func share(w http.ResponseWriter, r *http.Request) {
136128
http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden)
137129
return
138130
}
139-
proxy.ServeHTTP(w, r)
131+
132+
// HACK(cbro): use a simple proxy rather than httputil.ReverseProxy because of Issue #28168.
133+
// TODO: investigate using ReverseProxy with a Director, unsetting whatever's necessary to make that work.
134+
req, _ := http.NewRequest("POST", playgroundURL+"/share", r.Body)
135+
req.Header.Set("Content-Type", r.Header.Get("Content-Type"))
136+
req = req.WithContext(r.Context())
137+
resp, err := http.DefaultClient.Do(req)
138+
if err != nil {
139+
log.Printf("ERROR share error: %v", err)
140+
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
141+
return
142+
}
143+
copyHeader := func(k string) {
144+
if v := resp.Header.Get(k); v != "" {
145+
w.Header().Set(k, v)
146+
}
147+
}
148+
copyHeader("Content-Type")
149+
copyHeader("Content-Length")
150+
defer resp.Body.Close()
151+
w.WriteHeader(resp.StatusCode)
152+
io.Copy(w, resp.Body)
140153
}
141154

142155
func googleCN(r *http.Request) bool {

0 commit comments

Comments
 (0)