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