]> Cypherpunks repositories - gostls13.git/commitdiff
net/http: Various fixes to Basic authentication
authorPieter Droogendijk <pieter@binky.org.uk>
Wed, 7 Aug 2013 18:58:59 +0000 (11:58 -0700)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 7 Aug 2013 18:58:59 +0000 (11:58 -0700)
There were some issues with the code sometimes using base64.StdEncoding,
and sometimes base64.URLEncoding.
Encoding basic authentication is now always done by the same code.

Fixes #5970.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/12397043

src/pkg/net/http/client.go
src/pkg/net/http/client_test.go
src/pkg/net/http/request.go
src/pkg/net/http/transport.go
src/pkg/net/url/url.go

index 331e8ad90e5e4188a4a46a47faed27eaeebbe707..22f2e865cf7d69ef3fc0e10f9bd9e621d517c692 100644 (file)
@@ -161,18 +161,9 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) {
        }
 
        if u := req.URL.User; u != nil {
-               auth := u.String()
-               // UserInfo.String() only returns the colon when the
-               // password is set, so we must add it here.
-               //
-               // See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt
-               // "To receive authorization, the client sends the userid and password,
-               // separated by a single colon (":") character, within a base64
-               // encoded string in the credentials."
-               if _, hasPassword := u.Password(); !hasPassword {
-                       auth += ":"
-               }
-               req.Header.Set("Authorization", "Basic "+base64.URLEncoding.EncodeToString([]byte(auth)))
+               username := u.Username()
+               password, _ := u.Password()
+               req.Header.Set("Authorization", "Basic "+basicAuth(username, password))
        }
        resp, err = t.RoundTrip(req)
        if err != nil {
@@ -184,6 +175,16 @@ func send(req *Request, t RoundTripper) (resp *Response, err error) {
        return resp, nil
 }
 
+// See 2 (end of page 4) http://www.ietf.org/rfc/rfc2617.txt
+// "To receive authorization, the client sends the userid and password,
+// separated by a single colon (":") character, within a base64
+// encoded string in the credentials."
+// It is not meant to be urlencoded.
+func basicAuth(username, password string) string {
+       auth := username + ":" + password
+       return base64.StdEncoding.EncodeToString([]byte(auth))
+}
+
 // True if the specified HTTP status code is one for which the Get utility should
 // automatically redirect.
 func shouldRedirectGet(statusCode int) bool {
index 69fa168dd479e8004bfe4cb6d929995786f480c4..997d04151c224eb1579c4a061352f152f07df48b 100644 (file)
@@ -765,3 +765,37 @@ func TestEmptyPasswordAuth(t *testing.T) {
        }
        defer resp.Body.Close()
 }
+
+func TestBasicAuth(t *testing.T) {
+       defer afterTest(t)
+       tr := &recordingTransport{}
+       client := &Client{Transport: tr}
+
+       url := "http://My%20User:My%20Pass@dummy.faketld/"
+       expected := "My User:My Pass"
+       client.Get(url)
+
+       if tr.req.Method != "GET" {
+               t.Errorf("got method %q, want %q", tr.req.Method, "GET")
+       }
+       if tr.req.URL.String() != url {
+               t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
+       }
+       if tr.req.Header == nil {
+               t.Fatalf("expected non-nil request Header")
+       }
+       auth := tr.req.Header.Get("Authorization")
+       if strings.HasPrefix(auth, "Basic ") {
+               encoded := auth[6:]
+               decoded, err := base64.StdEncoding.DecodeString(encoded)
+               if err != nil {
+                       t.Fatal(err)
+               }
+               s := string(decoded)
+               if expected != s {
+                       t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected)
+               }
+       } else {
+               t.Errorf("Invalid auth %q", auth)
+       }
+}
index 90e56225dd4e3d8f2e731f9e148cf74dd88babf2..603299df555455aea46c471f37190be52f785bf8 100644 (file)
@@ -10,7 +10,6 @@ import (
        "bufio"
        "bytes"
        "crypto/tls"
-       "encoding/base64"
        "errors"
        "fmt"
        "io"
@@ -467,8 +466,7 @@ func NewRequest(method, urlStr string, body io.Reader) (*Request, error) {
 // With HTTP Basic Authentication the provided username and password
 // are not encrypted.
 func (r *Request) SetBasicAuth(username, password string) {
-       s := username + ":" + password
-       r.Header.Set("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(s)))
+       r.Header.Set("Authorization", "Basic "+basicAuth(username, password))
 }
 
 // parseRequestLine parses "GET /foo HTTP/1.1" into its three parts.
index 49a034b9b5904ee81ddcd6d221ccce440b70ef73..f6871afacd7a3c26efc3d76350b314be29897da1 100644 (file)
@@ -13,7 +13,6 @@ import (
        "bufio"
        "compress/gzip"
        "crypto/tls"
-       "encoding/base64"
        "errors"
        "fmt"
        "io"
@@ -273,7 +272,9 @@ func (cm *connectMethod) proxyAuth() string {
                return ""
        }
        if u := cm.proxyURL.User; u != nil {
-               return "Basic " + base64.URLEncoding.EncodeToString([]byte(u.String()))
+               username := u.Username()
+               password, _ := u.Password()
+               return "Basic " + basicAuth(username, password)
        }
        return ""
 }
index 043fd485391fbf3089c78f098093d3443853322f..95432f43376e7336f3fc166f86f042ed54a78a8a 100644 (file)
@@ -451,8 +451,8 @@ func (u *URL) String() string {
        } else {
                if u.Scheme != "" || u.Host != "" || u.User != nil {
                        buf.WriteString("//")
-                       if u := u.User; u != nil {
-                               buf.WriteString(u.String())
+                       if ui := u.User; ui != nil {
+                               buf.WriteString(ui.String())
                                buf.WriteByte('@')
                        }
                        if h := u.Host; h != "" {