github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/net/http/client_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Tests for client.go
     6  
     7  package http_test
     8  
     9  import (
    10  	"bytes"
    11  	"crypto/tls"
    12  	"crypto/x509"
    13  	"encoding/base64"
    14  	"errors"
    15  	"fmt"
    16  	"io"
    17  	"io/ioutil"
    18  	"net"
    19  	. "net/http"
    20  	"net/http/httptest"
    21  	"net/url"
    22  	"strconv"
    23  	"strings"
    24  	"sync"
    25  	"testing"
    26  )
    27  
    28  var robotsTxtHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
    29  	w.Header().Set("Last-Modified", "sometime")
    30  	fmt.Fprintf(w, "User-agent: go\nDisallow: /something/")
    31  })
    32  
    33  // pedanticReadAll works like ioutil.ReadAll but additionally
    34  // verifies that r obeys the documented io.Reader contract.
    35  func pedanticReadAll(r io.Reader) (b []byte, err error) {
    36  	var bufa [64]byte
    37  	buf := bufa[:]
    38  	for {
    39  		n, err := r.Read(buf)
    40  		if n == 0 && err == nil {
    41  			return nil, fmt.Errorf("Read: n=0 with err=nil")
    42  		}
    43  		b = append(b, buf[:n]...)
    44  		if err == io.EOF {
    45  			n, err := r.Read(buf)
    46  			if n != 0 || err != io.EOF {
    47  				return nil, fmt.Errorf("Read: n=%d err=%#v after EOF", n, err)
    48  			}
    49  			return b, nil
    50  		}
    51  		if err != nil {
    52  			return b, err
    53  		}
    54  	}
    55  }
    56  
    57  func TestClient(t *testing.T) {
    58  	defer afterTest(t)
    59  	ts := httptest.NewServer(robotsTxtHandler)
    60  	defer ts.Close()
    61  
    62  	r, err := Get(ts.URL)
    63  	var b []byte
    64  	if err == nil {
    65  		b, err = pedanticReadAll(r.Body)
    66  		r.Body.Close()
    67  	}
    68  	if err != nil {
    69  		t.Error(err)
    70  	} else if s := string(b); !strings.HasPrefix(s, "User-agent:") {
    71  		t.Errorf("Incorrect page body (did not begin with User-agent): %q", s)
    72  	}
    73  }
    74  
    75  func TestClientHead(t *testing.T) {
    76  	defer afterTest(t)
    77  	ts := httptest.NewServer(robotsTxtHandler)
    78  	defer ts.Close()
    79  
    80  	r, err := Head(ts.URL)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  	if _, ok := r.Header["Last-Modified"]; !ok {
    85  		t.Error("Last-Modified header not found.")
    86  	}
    87  }
    88  
    89  type recordingTransport struct {
    90  	req *Request
    91  }
    92  
    93  func (t *recordingTransport) RoundTrip(req *Request) (resp *Response, err error) {
    94  	t.req = req
    95  	return nil, errors.New("dummy impl")
    96  }
    97  
    98  func TestGetRequestFormat(t *testing.T) {
    99  	defer afterTest(t)
   100  	tr := &recordingTransport{}
   101  	client := &Client{Transport: tr}
   102  	url := "http://dummy.faketld/"
   103  	client.Get(url) // Note: doesn't hit network
   104  	if tr.req.Method != "GET" {
   105  		t.Errorf("expected method %q; got %q", "GET", tr.req.Method)
   106  	}
   107  	if tr.req.URL.String() != url {
   108  		t.Errorf("expected URL %q; got %q", url, tr.req.URL.String())
   109  	}
   110  	if tr.req.Header == nil {
   111  		t.Errorf("expected non-nil request Header")
   112  	}
   113  }
   114  
   115  func TestPostRequestFormat(t *testing.T) {
   116  	defer afterTest(t)
   117  	tr := &recordingTransport{}
   118  	client := &Client{Transport: tr}
   119  
   120  	url := "http://dummy.faketld/"
   121  	json := `{"key":"value"}`
   122  	b := strings.NewReader(json)
   123  	client.Post(url, "application/json", b) // Note: doesn't hit network
   124  
   125  	if tr.req.Method != "POST" {
   126  		t.Errorf("got method %q, want %q", tr.req.Method, "POST")
   127  	}
   128  	if tr.req.URL.String() != url {
   129  		t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
   130  	}
   131  	if tr.req.Header == nil {
   132  		t.Fatalf("expected non-nil request Header")
   133  	}
   134  	if tr.req.Close {
   135  		t.Error("got Close true, want false")
   136  	}
   137  	if g, e := tr.req.ContentLength, int64(len(json)); g != e {
   138  		t.Errorf("got ContentLength %d, want %d", g, e)
   139  	}
   140  }
   141  
   142  func TestPostFormRequestFormat(t *testing.T) {
   143  	defer afterTest(t)
   144  	tr := &recordingTransport{}
   145  	client := &Client{Transport: tr}
   146  
   147  	urlStr := "http://dummy.faketld/"
   148  	form := make(url.Values)
   149  	form.Set("foo", "bar")
   150  	form.Add("foo", "bar2")
   151  	form.Set("bar", "baz")
   152  	client.PostForm(urlStr, form) // Note: doesn't hit network
   153  
   154  	if tr.req.Method != "POST" {
   155  		t.Errorf("got method %q, want %q", tr.req.Method, "POST")
   156  	}
   157  	if tr.req.URL.String() != urlStr {
   158  		t.Errorf("got URL %q, want %q", tr.req.URL.String(), urlStr)
   159  	}
   160  	if tr.req.Header == nil {
   161  		t.Fatalf("expected non-nil request Header")
   162  	}
   163  	if g, e := tr.req.Header.Get("Content-Type"), "application/x-www-form-urlencoded"; g != e {
   164  		t.Errorf("got Content-Type %q, want %q", g, e)
   165  	}
   166  	if tr.req.Close {
   167  		t.Error("got Close true, want false")
   168  	}
   169  	// Depending on map iteration, body can be either of these.
   170  	expectedBody := "foo=bar&foo=bar2&bar=baz"
   171  	expectedBody1 := "bar=baz&foo=bar&foo=bar2"
   172  	if g, e := tr.req.ContentLength, int64(len(expectedBody)); g != e {
   173  		t.Errorf("got ContentLength %d, want %d", g, e)
   174  	}
   175  	bodyb, err := ioutil.ReadAll(tr.req.Body)
   176  	if err != nil {
   177  		t.Fatalf("ReadAll on req.Body: %v", err)
   178  	}
   179  	if g := string(bodyb); g != expectedBody && g != expectedBody1 {
   180  		t.Errorf("got body %q, want %q or %q", g, expectedBody, expectedBody1)
   181  	}
   182  }
   183  
   184  func TestClientRedirects(t *testing.T) {
   185  	defer afterTest(t)
   186  	var ts *httptest.Server
   187  	ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   188  		n, _ := strconv.Atoi(r.FormValue("n"))
   189  		// Test Referer header. (7 is arbitrary position to test at)
   190  		if n == 7 {
   191  			if g, e := r.Referer(), ts.URL+"/?n=6"; e != g {
   192  				t.Errorf("on request ?n=7, expected referer of %q; got %q", e, g)
   193  			}
   194  		}
   195  		if n < 15 {
   196  			Redirect(w, r, fmt.Sprintf("/?n=%d", n+1), StatusFound)
   197  			return
   198  		}
   199  		fmt.Fprintf(w, "n=%d", n)
   200  	}))
   201  	defer ts.Close()
   202  
   203  	c := &Client{}
   204  	_, err := c.Get(ts.URL)
   205  	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
   206  		t.Errorf("with default client Get, expected error %q, got %q", e, g)
   207  	}
   208  
   209  	// HEAD request should also have the ability to follow redirects.
   210  	_, err = c.Head(ts.URL)
   211  	if e, g := "Head /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
   212  		t.Errorf("with default client Head, expected error %q, got %q", e, g)
   213  	}
   214  
   215  	// Do should also follow redirects.
   216  	greq, _ := NewRequest("GET", ts.URL, nil)
   217  	_, err = c.Do(greq)
   218  	if e, g := "Get /?n=10: stopped after 10 redirects", fmt.Sprintf("%v", err); e != g {
   219  		t.Errorf("with default client Do, expected error %q, got %q", e, g)
   220  	}
   221  
   222  	var checkErr error
   223  	var lastVia []*Request
   224  	c = &Client{CheckRedirect: func(_ *Request, via []*Request) error {
   225  		lastVia = via
   226  		return checkErr
   227  	}}
   228  	res, err := c.Get(ts.URL)
   229  	if err != nil {
   230  		t.Fatalf("Get error: %v", err)
   231  	}
   232  	res.Body.Close()
   233  	finalUrl := res.Request.URL.String()
   234  	if e, g := "<nil>", fmt.Sprintf("%v", err); e != g {
   235  		t.Errorf("with custom client, expected error %q, got %q", e, g)
   236  	}
   237  	if !strings.HasSuffix(finalUrl, "/?n=15") {
   238  		t.Errorf("expected final url to end in /?n=15; got url %q", finalUrl)
   239  	}
   240  	if e, g := 15, len(lastVia); e != g {
   241  		t.Errorf("expected lastVia to have contained %d elements; got %d", e, g)
   242  	}
   243  
   244  	checkErr = errors.New("no redirects allowed")
   245  	res, err = c.Get(ts.URL)
   246  	if urlError, ok := err.(*url.Error); !ok || urlError.Err != checkErr {
   247  		t.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err, err)
   248  	}
   249  	if res == nil {
   250  		t.Fatalf("Expected a non-nil Response on CheckRedirect failure (http://golang.org/issue/3795)")
   251  	}
   252  	res.Body.Close()
   253  	if res.Header.Get("Location") == "" {
   254  		t.Errorf("no Location header in Response")
   255  	}
   256  }
   257  
   258  func TestPostRedirects(t *testing.T) {
   259  	defer afterTest(t)
   260  	var log struct {
   261  		sync.Mutex
   262  		bytes.Buffer
   263  	}
   264  	var ts *httptest.Server
   265  	ts = httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   266  		log.Lock()
   267  		fmt.Fprintf(&log.Buffer, "%s %s ", r.Method, r.RequestURI)
   268  		log.Unlock()
   269  		if v := r.URL.Query().Get("code"); v != "" {
   270  			code, _ := strconv.Atoi(v)
   271  			if code/100 == 3 {
   272  				w.Header().Set("Location", ts.URL)
   273  			}
   274  			w.WriteHeader(code)
   275  		}
   276  	}))
   277  	defer ts.Close()
   278  	tests := []struct {
   279  		suffix string
   280  		want   int // response code
   281  	}{
   282  		{"/", 200},
   283  		{"/?code=301", 301},
   284  		{"/?code=302", 200},
   285  		{"/?code=303", 200},
   286  		{"/?code=404", 404},
   287  	}
   288  	for _, tt := range tests {
   289  		res, err := Post(ts.URL+tt.suffix, "text/plain", strings.NewReader("Some content"))
   290  		if err != nil {
   291  			t.Fatal(err)
   292  		}
   293  		if res.StatusCode != tt.want {
   294  			t.Errorf("POST %s: status code = %d; want %d", tt.suffix, res.StatusCode, tt.want)
   295  		}
   296  	}
   297  	log.Lock()
   298  	got := log.String()
   299  	log.Unlock()
   300  	want := "POST / POST /?code=301 POST /?code=302 GET / POST /?code=303 GET / POST /?code=404 "
   301  	if got != want {
   302  		t.Errorf("Log differs.\n Got: %q\nWant: %q", got, want)
   303  	}
   304  }
   305  
   306  var expectedCookies = []*Cookie{
   307  	{Name: "ChocolateChip", Value: "tasty"},
   308  	{Name: "First", Value: "Hit"},
   309  	{Name: "Second", Value: "Hit"},
   310  }
   311  
   312  var echoCookiesRedirectHandler = HandlerFunc(func(w ResponseWriter, r *Request) {
   313  	for _, cookie := range r.Cookies() {
   314  		SetCookie(w, cookie)
   315  	}
   316  	if r.URL.Path == "/" {
   317  		SetCookie(w, expectedCookies[1])
   318  		Redirect(w, r, "/second", StatusMovedPermanently)
   319  	} else {
   320  		SetCookie(w, expectedCookies[2])
   321  		w.Write([]byte("hello"))
   322  	}
   323  })
   324  
   325  func TestClientSendsCookieFromJar(t *testing.T) {
   326  	tr := &recordingTransport{}
   327  	client := &Client{Transport: tr}
   328  	client.Jar = &TestJar{perURL: make(map[string][]*Cookie)}
   329  	us := "http://dummy.faketld/"
   330  	u, _ := url.Parse(us)
   331  	client.Jar.SetCookies(u, expectedCookies)
   332  
   333  	client.Get(us) // Note: doesn't hit network
   334  	matchReturnedCookies(t, expectedCookies, tr.req.Cookies())
   335  
   336  	client.Head(us) // Note: doesn't hit network
   337  	matchReturnedCookies(t, expectedCookies, tr.req.Cookies())
   338  
   339  	client.Post(us, "text/plain", strings.NewReader("body")) // Note: doesn't hit network
   340  	matchReturnedCookies(t, expectedCookies, tr.req.Cookies())
   341  
   342  	client.PostForm(us, url.Values{}) // Note: doesn't hit network
   343  	matchReturnedCookies(t, expectedCookies, tr.req.Cookies())
   344  
   345  	req, _ := NewRequest("GET", us, nil)
   346  	client.Do(req) // Note: doesn't hit network
   347  	matchReturnedCookies(t, expectedCookies, tr.req.Cookies())
   348  
   349  	req, _ = NewRequest("POST", us, nil)
   350  	client.Do(req) // Note: doesn't hit network
   351  	matchReturnedCookies(t, expectedCookies, tr.req.Cookies())
   352  }
   353  
   354  // Just enough correctness for our redirect tests. Uses the URL.Host as the
   355  // scope of all cookies.
   356  type TestJar struct {
   357  	m      sync.Mutex
   358  	perURL map[string][]*Cookie
   359  }
   360  
   361  func (j *TestJar) SetCookies(u *url.URL, cookies []*Cookie) {
   362  	j.m.Lock()
   363  	defer j.m.Unlock()
   364  	if j.perURL == nil {
   365  		j.perURL = make(map[string][]*Cookie)
   366  	}
   367  	j.perURL[u.Host] = cookies
   368  }
   369  
   370  func (j *TestJar) Cookies(u *url.URL) []*Cookie {
   371  	j.m.Lock()
   372  	defer j.m.Unlock()
   373  	return j.perURL[u.Host]
   374  }
   375  
   376  func TestRedirectCookiesOnRequest(t *testing.T) {
   377  	defer afterTest(t)
   378  	var ts *httptest.Server
   379  	ts = httptest.NewServer(echoCookiesRedirectHandler)
   380  	defer ts.Close()
   381  	c := &Client{}
   382  	req, _ := NewRequest("GET", ts.URL, nil)
   383  	req.AddCookie(expectedCookies[0])
   384  	// TODO: Uncomment when an implementation of a RFC6265 cookie jar lands.
   385  	_ = c
   386  	// resp, _ := c.Do(req)
   387  	// matchReturnedCookies(t, expectedCookies, resp.Cookies())
   388  
   389  	req, _ = NewRequest("GET", ts.URL, nil)
   390  	// resp, _ = c.Do(req)
   391  	// matchReturnedCookies(t, expectedCookies[1:], resp.Cookies())
   392  }
   393  
   394  func TestRedirectCookiesJar(t *testing.T) {
   395  	defer afterTest(t)
   396  	var ts *httptest.Server
   397  	ts = httptest.NewServer(echoCookiesRedirectHandler)
   398  	defer ts.Close()
   399  	c := &Client{
   400  		Jar: new(TestJar),
   401  	}
   402  	u, _ := url.Parse(ts.URL)
   403  	c.Jar.SetCookies(u, []*Cookie{expectedCookies[0]})
   404  	resp, err := c.Get(ts.URL)
   405  	if err != nil {
   406  		t.Fatalf("Get: %v", err)
   407  	}
   408  	resp.Body.Close()
   409  	matchReturnedCookies(t, expectedCookies, resp.Cookies())
   410  }
   411  
   412  func matchReturnedCookies(t *testing.T, expected, given []*Cookie) {
   413  	t.Logf("Received cookies: %v", given)
   414  	if len(given) != len(expected) {
   415  		t.Errorf("Expected %d cookies, got %d", len(expected), len(given))
   416  	}
   417  	for _, ec := range expected {
   418  		foundC := false
   419  		for _, c := range given {
   420  			if ec.Name == c.Name && ec.Value == c.Value {
   421  				foundC = true
   422  				break
   423  			}
   424  		}
   425  		if !foundC {
   426  			t.Errorf("Missing cookie %v", ec)
   427  		}
   428  	}
   429  }
   430  
   431  func TestJarCalls(t *testing.T) {
   432  	defer afterTest(t)
   433  	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   434  		pathSuffix := r.RequestURI[1:]
   435  		if r.RequestURI == "/nosetcookie" {
   436  			return // dont set cookies for this path
   437  		}
   438  		SetCookie(w, &Cookie{Name: "name" + pathSuffix, Value: "val" + pathSuffix})
   439  		if r.RequestURI == "/" {
   440  			Redirect(w, r, "http://secondhost.fake/secondpath", 302)
   441  		}
   442  	}))
   443  	defer ts.Close()
   444  	jar := new(RecordingJar)
   445  	c := &Client{
   446  		Jar: jar,
   447  		Transport: &Transport{
   448  			Dial: func(_ string, _ string) (net.Conn, error) {
   449  				return net.Dial("tcp", ts.Listener.Addr().String())
   450  			},
   451  		},
   452  	}
   453  	_, err := c.Get("http://firsthost.fake/")
   454  	if err != nil {
   455  		t.Fatal(err)
   456  	}
   457  	_, err = c.Get("http://firsthost.fake/nosetcookie")
   458  	if err != nil {
   459  		t.Fatal(err)
   460  	}
   461  	got := jar.log.String()
   462  	want := `Cookies("http://firsthost.fake/")
   463  SetCookie("http://firsthost.fake/", [name=val])
   464  Cookies("http://secondhost.fake/secondpath")
   465  SetCookie("http://secondhost.fake/secondpath", [namesecondpath=valsecondpath])
   466  Cookies("http://firsthost.fake/nosetcookie")
   467  `
   468  	if got != want {
   469  		t.Errorf("Got Jar calls:\n%s\nWant:\n%s", got, want)
   470  	}
   471  }
   472  
   473  // RecordingJar keeps a log of calls made to it, without
   474  // tracking any cookies.
   475  type RecordingJar struct {
   476  	mu  sync.Mutex
   477  	log bytes.Buffer
   478  }
   479  
   480  func (j *RecordingJar) SetCookies(u *url.URL, cookies []*Cookie) {
   481  	j.logf("SetCookie(%q, %v)\n", u, cookies)
   482  }
   483  
   484  func (j *RecordingJar) Cookies(u *url.URL) []*Cookie {
   485  	j.logf("Cookies(%q)\n", u)
   486  	return nil
   487  }
   488  
   489  func (j *RecordingJar) logf(format string, args ...interface{}) {
   490  	j.mu.Lock()
   491  	defer j.mu.Unlock()
   492  	fmt.Fprintf(&j.log, format, args...)
   493  }
   494  
   495  func TestStreamingGet(t *testing.T) {
   496  	defer afterTest(t)
   497  	say := make(chan string)
   498  	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   499  		w.(Flusher).Flush()
   500  		for str := range say {
   501  			w.Write([]byte(str))
   502  			w.(Flusher).Flush()
   503  		}
   504  	}))
   505  	defer ts.Close()
   506  
   507  	c := &Client{}
   508  	res, err := c.Get(ts.URL)
   509  	if err != nil {
   510  		t.Fatal(err)
   511  	}
   512  	var buf [10]byte
   513  	for _, str := range []string{"i", "am", "also", "known", "as", "comet"} {
   514  		say <- str
   515  		n, err := io.ReadFull(res.Body, buf[0:len(str)])
   516  		if err != nil {
   517  			t.Fatalf("ReadFull on %q: %v", str, err)
   518  		}
   519  		if n != len(str) {
   520  			t.Fatalf("Receiving %q, only read %d bytes", str, n)
   521  		}
   522  		got := string(buf[0:n])
   523  		if got != str {
   524  			t.Fatalf("Expected %q, got %q", str, got)
   525  		}
   526  	}
   527  	close(say)
   528  	_, err = io.ReadFull(res.Body, buf[0:1])
   529  	if err != io.EOF {
   530  		t.Fatalf("at end expected EOF, got %v", err)
   531  	}
   532  }
   533  
   534  type writeCountingConn struct {
   535  	net.Conn
   536  	count *int
   537  }
   538  
   539  func (c *writeCountingConn) Write(p []byte) (int, error) {
   540  	*c.count++
   541  	return c.Conn.Write(p)
   542  }
   543  
   544  // TestClientWrites verifies that client requests are buffered and we
   545  // don't send a TCP packet per line of the http request + body.
   546  func TestClientWrites(t *testing.T) {
   547  	defer afterTest(t)
   548  	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   549  	}))
   550  	defer ts.Close()
   551  
   552  	writes := 0
   553  	dialer := func(netz string, addr string) (net.Conn, error) {
   554  		c, err := net.Dial(netz, addr)
   555  		if err == nil {
   556  			c = &writeCountingConn{c, &writes}
   557  		}
   558  		return c, err
   559  	}
   560  	c := &Client{Transport: &Transport{Dial: dialer}}
   561  
   562  	_, err := c.Get(ts.URL)
   563  	if err != nil {
   564  		t.Fatal(err)
   565  	}
   566  	if writes != 1 {
   567  		t.Errorf("Get request did %d Write calls, want 1", writes)
   568  	}
   569  
   570  	writes = 0
   571  	_, err = c.PostForm(ts.URL, url.Values{"foo": {"bar"}})
   572  	if err != nil {
   573  		t.Fatal(err)
   574  	}
   575  	if writes != 1 {
   576  		t.Errorf("Post request did %d Write calls, want 1", writes)
   577  	}
   578  }
   579  
   580  func TestClientInsecureTransport(t *testing.T) {
   581  	defer afterTest(t)
   582  	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   583  		w.Write([]byte("Hello"))
   584  	}))
   585  	defer ts.Close()
   586  
   587  	// TODO(bradfitz): add tests for skipping hostname checks too?
   588  	// would require a new cert for testing, and probably
   589  	// redundant with these tests.
   590  	for _, insecure := range []bool{true, false} {
   591  		tr := &Transport{
   592  			TLSClientConfig: &tls.Config{
   593  				InsecureSkipVerify: insecure,
   594  			},
   595  		}
   596  		defer tr.CloseIdleConnections()
   597  		c := &Client{Transport: tr}
   598  		res, err := c.Get(ts.URL)
   599  		if (err == nil) != insecure {
   600  			t.Errorf("insecure=%v: got unexpected err=%v", insecure, err)
   601  		}
   602  		if res != nil {
   603  			res.Body.Close()
   604  		}
   605  	}
   606  }
   607  
   608  func TestClientErrorWithRequestURI(t *testing.T) {
   609  	defer afterTest(t)
   610  	req, _ := NewRequest("GET", "http://localhost:1234/", nil)
   611  	req.RequestURI = "/this/field/is/illegal/and/should/error/"
   612  	_, err := DefaultClient.Do(req)
   613  	if err == nil {
   614  		t.Fatalf("expected an error")
   615  	}
   616  	if !strings.Contains(err.Error(), "RequestURI") {
   617  		t.Errorf("wanted error mentioning RequestURI; got error: %v", err)
   618  	}
   619  }
   620  
   621  func newTLSTransport(t *testing.T, ts *httptest.Server) *Transport {
   622  	certs := x509.NewCertPool()
   623  	for _, c := range ts.TLS.Certificates {
   624  		roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1])
   625  		if err != nil {
   626  			t.Fatalf("error parsing server's root cert: %v", err)
   627  		}
   628  		for _, root := range roots {
   629  			certs.AddCert(root)
   630  		}
   631  	}
   632  	return &Transport{
   633  		TLSClientConfig: &tls.Config{RootCAs: certs},
   634  	}
   635  }
   636  
   637  func TestClientWithCorrectTLSServerName(t *testing.T) {
   638  	defer afterTest(t)
   639  	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   640  		if r.TLS.ServerName != "127.0.0.1" {
   641  			t.Errorf("expected client to set ServerName 127.0.0.1, got: %q", r.TLS.ServerName)
   642  		}
   643  	}))
   644  	defer ts.Close()
   645  
   646  	c := &Client{Transport: newTLSTransport(t, ts)}
   647  	if _, err := c.Get(ts.URL); err != nil {
   648  		t.Fatalf("expected successful TLS connection, got error: %v", err)
   649  	}
   650  }
   651  
   652  func TestClientWithIncorrectTLSServerName(t *testing.T) {
   653  	defer afterTest(t)
   654  	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {}))
   655  	defer ts.Close()
   656  
   657  	trans := newTLSTransport(t, ts)
   658  	trans.TLSClientConfig.ServerName = "badserver"
   659  	c := &Client{Transport: trans}
   660  	_, err := c.Get(ts.URL)
   661  	if err == nil {
   662  		t.Fatalf("expected an error")
   663  	}
   664  	if !strings.Contains(err.Error(), "127.0.0.1") || !strings.Contains(err.Error(), "badserver") {
   665  		t.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err)
   666  	}
   667  }
   668  
   669  // Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName
   670  // when not empty.
   671  //
   672  // tls.Config.ServerName (non-empty, set to "example.com") takes
   673  // precedence over "some-other-host.tld" which previously incorrectly
   674  // took precedence. We don't actually connect to (or even resolve)
   675  // "some-other-host.tld", though, because of the Transport.Dial hook.
   676  //
   677  // The httptest.Server has a cert with "example.com" as its name.
   678  func TestTransportUsesTLSConfigServerName(t *testing.T) {
   679  	defer afterTest(t)
   680  	ts := httptest.NewTLSServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   681  		w.Write([]byte("Hello"))
   682  	}))
   683  	defer ts.Close()
   684  
   685  	tr := newTLSTransport(t, ts)
   686  	tr.TLSClientConfig.ServerName = "example.com" // one of httptest's Server cert names
   687  	tr.Dial = func(netw, addr string) (net.Conn, error) {
   688  		return net.Dial(netw, ts.Listener.Addr().String())
   689  	}
   690  	defer tr.CloseIdleConnections()
   691  	c := &Client{Transport: tr}
   692  	res, err := c.Get("https://some-other-host.tld/")
   693  	if err != nil {
   694  		t.Fatal(err)
   695  	}
   696  	res.Body.Close()
   697  }
   698  
   699  // Verify Response.ContentLength is populated. http://golang.org/issue/4126
   700  func TestClientHeadContentLength(t *testing.T) {
   701  	defer afterTest(t)
   702  	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   703  		if v := r.FormValue("cl"); v != "" {
   704  			w.Header().Set("Content-Length", v)
   705  		}
   706  	}))
   707  	defer ts.Close()
   708  	tests := []struct {
   709  		suffix string
   710  		want   int64
   711  	}{
   712  		{"/?cl=1234", 1234},
   713  		{"/?cl=0", 0},
   714  		{"", -1},
   715  	}
   716  	for _, tt := range tests {
   717  		req, _ := NewRequest("HEAD", ts.URL+tt.suffix, nil)
   718  		res, err := DefaultClient.Do(req)
   719  		if err != nil {
   720  			t.Fatal(err)
   721  		}
   722  		if res.ContentLength != tt.want {
   723  			t.Errorf("Content-Length = %d; want %d", res.ContentLength, tt.want)
   724  		}
   725  		bs, err := ioutil.ReadAll(res.Body)
   726  		if err != nil {
   727  			t.Fatal(err)
   728  		}
   729  		if len(bs) != 0 {
   730  			t.Errorf("Unexpected content: %q", bs)
   731  		}
   732  	}
   733  }
   734  
   735  func TestEmptyPasswordAuth(t *testing.T) {
   736  	defer afterTest(t)
   737  	gopher := "gopher"
   738  	ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
   739  		auth := r.Header.Get("Authorization")
   740  		if strings.HasPrefix(auth, "Basic ") {
   741  			encoded := auth[6:]
   742  			decoded, err := base64.StdEncoding.DecodeString(encoded)
   743  			if err != nil {
   744  				t.Fatal(err)
   745  			}
   746  			expected := gopher + ":"
   747  			s := string(decoded)
   748  			if expected != s {
   749  				t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected)
   750  			}
   751  		} else {
   752  			t.Errorf("Invalid auth %q", auth)
   753  		}
   754  	}))
   755  	defer ts.Close()
   756  	c := &Client{}
   757  	req, err := NewRequest("GET", ts.URL, nil)
   758  	if err != nil {
   759  		t.Fatal(err)
   760  	}
   761  	req.URL.User = url.User(gopher)
   762  	resp, err := c.Do(req)
   763  	if err != nil {
   764  		t.Fatal(err)
   765  	}
   766  	defer resp.Body.Close()
   767  }
   768  
   769  func TestBasicAuth(t *testing.T) {
   770  	defer afterTest(t)
   771  	tr := &recordingTransport{}
   772  	client := &Client{Transport: tr}
   773  
   774  	url := "http://My%20User:My%20Pass@dummy.faketld/"
   775  	expected := "My User:My Pass"
   776  	client.Get(url)
   777  
   778  	if tr.req.Method != "GET" {
   779  		t.Errorf("got method %q, want %q", tr.req.Method, "GET")
   780  	}
   781  	if tr.req.URL.String() != url {
   782  		t.Errorf("got URL %q, want %q", tr.req.URL.String(), url)
   783  	}
   784  	if tr.req.Header == nil {
   785  		t.Fatalf("expected non-nil request Header")
   786  	}
   787  	auth := tr.req.Header.Get("Authorization")
   788  	if strings.HasPrefix(auth, "Basic ") {
   789  		encoded := auth[6:]
   790  		decoded, err := base64.StdEncoding.DecodeString(encoded)
   791  		if err != nil {
   792  			t.Fatal(err)
   793  		}
   794  		s := string(decoded)
   795  		if expected != s {
   796  			t.Errorf("Invalid Authorization header. Got %q, wanted %q", s, expected)
   797  		}
   798  	} else {
   799  		t.Errorf("Invalid auth %q", auth)
   800  	}
   801  }