aboutsummaryrefslogtreecommitdiff
path: root/src/net/http
diff options
context:
space:
mode:
authorMikio Hara <mikioh.mikioh@gmail.com>2015-01-21 19:27:34 +0900
committerMikio Hara <mikioh.mikioh@gmail.com>2015-04-09 09:26:52 +0000
commit957255f5ab1ca4aff3195a20b80fe2aa4eb9e336 (patch)
tree46c339093e1054f689410b298f7e4272bc6e7f51 /src/net/http
parent92c57363e0b4d193c4324e2af6902fe56b7524a0 (diff)
downloadgo-957255f5ab1ca4aff3195a20b80fe2aa4eb9e336.tar.xz
net/http: don't send IPv6 zone identifier in outbound request, per RFC 6874
When making a request to an IPv6 address with a zone identifier, for exmaple [fe80::1%en0], RFC 6874 says HTTP clients must remove the zone identifier "%en0" before writing the request for security reason. This change removes any IPv6 zone identifer attached to URI in the Host header field in requests. Fixes #9544. Change-Id: I7406bd0aa961d260d96f1f887c2e45854e921452 Reviewed-on: https://go-review.googlesource.com/3111 Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/net/http')
-rw-r--r--src/net/http/request.go24
-rw-r--r--src/net/http/request_test.go30
-rw-r--r--src/net/http/requestwrite_test.go31
3 files changed, 77 insertions, 8 deletions
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 639a579bdf..a4e515c790 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -361,12 +361,15 @@ func (r *Request) WriteProxy(w io.Writer) error {
// extraHeaders may be nil
func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) error {
- host := req.Host
+ // According to RFC 6874, an HTTP client, proxy, or other
+ // intermediary must remove any IPv6 zone identifier attached
+ // to an outgoing URI.
+ host := removeZone(req.Host)
if host == "" {
if req.URL == nil {
return errors.New("http: Request.Write on Request with no Host or URL set")
}
- host = req.URL.Host
+ host = removeZone(req.URL.Host)
}
ruri := req.URL.RequestURI()
@@ -453,6 +456,23 @@ func (req *Request) write(w io.Writer, usingProxy bool, extraHeaders Header) err
return nil
}
+// removeZone removes IPv6 zone identifer from host.
+// E.g., "[fe80::1%en0]:8080" to "[fe80::1]:8080"
+func removeZone(host string) string {
+ if !strings.HasPrefix(host, "[") {
+ return host
+ }
+ i := strings.LastIndex(host, "]")
+ if i < 0 {
+ return host
+ }
+ j := strings.LastIndex(host[:i], "%")
+ if j < 0 {
+ return host
+ }
+ return host[:j] + host[i:]
+}
+
// ParseHTTPVersion parses a HTTP version string.
// "HTTP/1.0" returns (1, 0, true).
func ParseHTTPVersion(vers string) (major, minor int, ok bool) {
diff --git a/src/net/http/request_test.go b/src/net/http/request_test.go
index 671841ff70..9228d50ef7 100644
--- a/src/net/http/request_test.go
+++ b/src/net/http/request_test.go
@@ -326,13 +326,31 @@ func TestReadRequestErrors(t *testing.T) {
}
}
+var newRequestHostTests = []struct {
+ in, out string
+}{
+ {"http://www.example.com/", "www.example.com"},
+ {"http://www.example.com:8080/", "www.example.com:8080"},
+
+ {"http://192.168.0.1/", "192.168.0.1"},
+ {"http://192.168.0.1:8080/", "192.168.0.1:8080"},
+
+ {"http://[fe80::1]/", "[fe80::1]"},
+ {"http://[fe80::1]:8080/", "[fe80::1]:8080"},
+ {"http://[fe80::1%25en0]/", "[fe80::1%en0]"},
+ {"http://[fe80::1%25en0]:8080/", "[fe80::1%en0]:8080"},
+}
+
func TestNewRequestHost(t *testing.T) {
- req, err := NewRequest("GET", "http://localhost:1234/", nil)
- if err != nil {
- t.Fatal(err)
- }
- if req.Host != "localhost:1234" {
- t.Errorf("Host = %q; want localhost:1234", req.Host)
+ for i, tt := range newRequestHostTests {
+ req, err := NewRequest("GET", tt.in, nil)
+ if err != nil {
+ t.Errorf("#%v: %v", i, err)
+ continue
+ }
+ if req.Host != tt.out {
+ t.Errorf("got %q; want %q", req.Host, tt.out)
+ }
}
}
diff --git a/src/net/http/requestwrite_test.go b/src/net/http/requestwrite_test.go
index 7a6bd58786..e9a5f5f080 100644
--- a/src/net/http/requestwrite_test.go
+++ b/src/net/http/requestwrite_test.go
@@ -455,6 +455,37 @@ var reqWriteTests = []reqWriteTest{
"ALL-CAPS: x\r\n" +
"\r\n",
},
+
+ // Request with host header field; IPv6 address with zone identifier
+ {
+ Req: Request{
+ Method: "GET",
+ URL: &url.URL{
+ Host: "[fe80::1%en0]",
+ },
+ },
+
+ WantWrite: "GET / HTTP/1.1\r\n" +
+ "Host: [fe80::1]\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
+ "\r\n",
+ },
+
+ // Request with optional host header field; IPv6 address with zone identifier
+ {
+ Req: Request{
+ Method: "GET",
+ URL: &url.URL{
+ Host: "www.example.com",
+ },
+ Host: "[fe80::1%en0]:8080",
+ },
+
+ WantWrite: "GET / HTTP/1.1\r\n" +
+ "Host: [fe80::1]:8080\r\n" +
+ "User-Agent: Go 1.1 package http\r\n" +
+ "\r\n",
+ },
}
func TestRequestWrite(t *testing.T) {