From 8b29f158add964b788cea61ad608f042238f52ba Mon Sep 17 00:00:00 2001
From: Brad Fitzpatrick <bradfitz@golang.org>
Date: Sat, 20 Apr 2013 17:20:14 -0700
Subject: [PATCH] net/http: fix a panic in Redirect

R=golang-dev, dsymonds, r
CC=golang-dev
https://golang.org/cl/8721045
---
 src/pkg/net/http/client_test.go |  2 +-
 src/pkg/net/http/server.go      |  4 ++--
 src/pkg/net/http/server_test.go | 35 +++++++++++++++++++++------------
 3 files changed, 25 insertions(+), 16 deletions(-)

diff --git a/src/pkg/net/http/client_test.go b/src/pkg/net/http/client_test.go
index d7d2c187996..73f1fe3c10a 100644
--- a/src/pkg/net/http/client_test.go
+++ b/src/pkg/net/http/client_test.go
@@ -180,7 +180,7 @@ func TestPostFormRequestFormat(t *testing.T) {
 	}
 }
 
-func TestRedirects(t *testing.T) {
+func TestClientRedirects(t *testing.T) {
 	defer afterTest(t)
 	var ts *httptest.Server
 	ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index 4792bfba222..eebefbbbf48 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -1222,9 +1222,9 @@ func Redirect(w ResponseWriter, r *Request, urlStr string, code int) {
 			}
 
 			// clean up but preserve trailing slash
-			trailing := urlStr[len(urlStr)-1] == '/'
+			trailing := strings.HasSuffix(urlStr, "/")
 			urlStr = path.Clean(urlStr)
-			if trailing && urlStr[len(urlStr)-1] != '/' {
+			if trailing && !strings.HasSuffix(urlStr, "/") {
 				urlStr += "/"
 			}
 			urlStr += query
diff --git a/src/pkg/net/http/server_test.go b/src/pkg/net/http/server_test.go
index 8b4e8c6d6f6..e8b69f76cce 100644
--- a/src/pkg/net/http/server_test.go
+++ b/src/pkg/net/http/server_test.go
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-package http
+package http_test
 
 import (
+	. "net/http"
+	"net/http/httptest"
 	"net/url"
 	"testing"
 )
@@ -76,20 +78,27 @@ func TestServeMuxHandler(t *testing.T) {
 			},
 		}
 		h, pattern := mux.Handler(r)
-		cs := &codeSaver{h: Header{}}
-		h.ServeHTTP(cs, r)
-		if pattern != tt.pattern || cs.code != tt.code {
-			t.Errorf("%s %s %s = %d, %q, want %d, %q", tt.method, tt.host, tt.path, cs.code, pattern, tt.code, tt.pattern)
+		rr := httptest.NewRecorder()
+		h.ServeHTTP(rr, r)
+		if pattern != tt.pattern || rr.Code != tt.code {
+			t.Errorf("%s %s %s = %d, %q, want %d, %q", tt.method, tt.host, tt.path, rr.Code, pattern, tt.code, tt.pattern)
 		}
 	}
 }
 
-// A codeSaver is a ResponseWriter that saves the code passed to WriteHeader.
-type codeSaver struct {
-	h    Header
-	code int
+func TestServerRedirect(t *testing.T) {
+	// This used to crash. It's not valid input (bad path), but it
+	// shouldn't crash.
+	rr := httptest.NewRecorder()
+	req := &Request{
+		Method: "GET",
+		URL: &url.URL{
+			Scheme: "http",
+			Path:   "not-empty-but-no-leading-slash", // bogus
+		},
+	}
+	Redirect(rr, req, "", 304)
+	if rr.Code != 304 {
+		t.Errorf("Code = %d; want 304", rr.Code)
+	}
 }
-
-func (cs *codeSaver) Header() Header              { return cs.h }
-func (cs *codeSaver) Write(p []byte) (int, error) { return len(p), nil }
-func (cs *codeSaver) WriteHeader(code int)        { cs.code = code }
-- 
GitLab