Skip to content

Commit eca3618

Browse files
honsiorovskyibradfitz
authored andcommitted
net/http: support URLs without schemes in http.Redirect
Many browsers now support schemeless URLs in the Location headers and also it is allowed in the draft HTTP/1.1 specification (see http://stackoverflow.com/q/4831741#comment25926312_4831741), but Go standard library lacks support for them. This patch implements schemeless URLs support in http.Redirect(). Since url.Parse() correctly handles schemeless URLs, I've just added an extra condition to verify URL's Host part in the absoulute/relative check in the http.Redirect function. Also I've moved oldpath variable initialization inside the block of code where it is used. Change-Id: Ib8a6347816a83e16576f00c4aa13224a89d610b5 Reviewed-on: https://go-review.googlesource.com/14172 Reviewed-by: Brad Fitzpatrick <[email protected]> Run-TryBot: Brad Fitzpatrick <[email protected]> TryBot-Result: Gobot Gobot <[email protected]>
1 parent 27df2e3 commit eca3618

File tree

2 files changed

+41
-5
lines changed

2 files changed

+41
-5
lines changed

src/net/http/serve_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,41 @@ func TestRedirectBadPath(t *testing.T) {
19061906
}
19071907
}
19081908

1909+
// Test different URL formats and schemes
1910+
func TestRedirectURLFormat(t *testing.T) {
1911+
req, _ := NewRequest("GET", "http://example.com/qux/", nil)
1912+
1913+
var tests = []struct {
1914+
in string
1915+
want string
1916+
}{
1917+
// normal http
1918+
{"http://foobar.com/baz", "http://foobar.com/baz"},
1919+
// normal https
1920+
{"https://foobar.com/baz", "https://foobar.com/baz"},
1921+
// custom scheme
1922+
{"test://foobar.com/baz", "test://foobar.com/baz"},
1923+
// schemeless
1924+
{"//foobar.com/baz", "//foobar.com/baz"},
1925+
// relative to the root
1926+
{"/foobar.com/baz", "/foobar.com/baz"},
1927+
// relative to the current path
1928+
{"foobar.com/baz", "/qux/foobar.com/baz"},
1929+
// relative to the current path (+ going upwards)
1930+
{"../quux/foobar.com/baz", "/quux/foobar.com/baz"},
1931+
// incorrect number of slashes
1932+
{"///foobar.com/baz", "/foobar.com/baz"},
1933+
}
1934+
1935+
for _, tt := range tests {
1936+
rec := httptest.NewRecorder()
1937+
Redirect(rec, req, tt.in, 302)
1938+
if got := rec.Header().Get("Location"); got != tt.want {
1939+
t.Errorf("Redirect(%q) generated Location header %q; want %q", tt.in, got, tt.want)
1940+
}
1941+
}
1942+
}
1943+
19091944
// TestZeroLengthPostAndResponse exercises an optimization done by the Transport:
19101945
// when there is no body (either because the method doesn't permit a body, or an
19111946
// explicit Content-Length of zero is present), then the transport can re-use the

src/net/http/server.go

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,11 +1665,12 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
16651665
// Because of this problem, no one pays attention
16661666
// to the RFC; they all send back just a new path.
16671667
// So do we.
1668-
oldpath := r.URL.Path
1669-
if oldpath == "" { // should not happen, but avoid a crash if it does
1670-
oldpath = "/"
1671-
}
1672-
if u.Scheme == "" {
1668+
if u.Scheme == "" && u.Host == "" {
1669+
oldpath := r.URL.Path
1670+
if oldpath == "" { // should not happen, but avoid a crash if it does
1671+
oldpath = "/"
1672+
}
1673+
16731674
// no leading http://server
16741675
if urlStr == "" || urlStr[0] != '/' {
16751676
// make relative path absolute

0 commit comments

Comments
 (0)