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.
33 var robotsTxtHandler
= HandlerFunc(func(w ResponseWriter
, r
*Request
) {
34 w
.Header().Set("Last-Modified", "sometime")
35 fmt
.Fprintf(w
, "User-agent: go\nDisallow: /something/")
38 // pedanticReadAll works like ioutil.ReadAll but additionally
39 // verifies that r obeys the documented io.Reader contract.
40 func pedanticReadAll(r io
.Reader
) (b
[]byte, err error
) {
45 if n
== 0 && err
== nil {
46 return nil, fmt
.Errorf("Read: n=0 with err=nil")
48 b
= append(b
, buf
[:n
]...)
51 if n
!= 0 || err
!= io
.EOF
{
52 return nil, fmt
.Errorf("Read: n=%d err=%#v after EOF", n
, err
)
62 type chanWriter
chan string
64 func (w chanWriter
) Write(p
[]byte) (n
int, err error
) {
69 func TestClient(t
*testing
.T
) {
72 ts
:= httptest
.NewServer(robotsTxtHandler
)
76 r
, err
:= c
.Get(ts
.URL
)
79 b
, err
= pedanticReadAll(r
.Body
)
84 } else if s
:= string(b
); !strings
.HasPrefix(s
, "User-agent:") {
85 t
.Errorf("Incorrect page body (did not begin with User-agent): %q", s
)
89 func TestClientHead_h1(t
*testing
.T
) { testClientHead(t
, h1Mode
) }
90 func TestClientHead_h2(t
*testing
.T
) { testClientHead(t
, h2Mode
) }
92 func testClientHead(t
*testing
.T
, h2
bool) {
94 cst
:= newClientServerTest(t
, h2
, robotsTxtHandler
)
97 r
, err
:= cst
.c
.Head(cst
.ts
.URL
)
101 if _
, ok
:= r
.Header
["Last-Modified"]; !ok
{
102 t
.Error("Last-Modified header not found.")
106 type recordingTransport
struct {
110 func (t
*recordingTransport
) RoundTrip(req
*Request
) (resp
*Response
, err error
) {
112 return nil, errors
.New("dummy impl")
115 func TestGetRequestFormat(t
*testing
.T
) {
118 tr
:= &recordingTransport
{}
119 client
:= &Client
{Transport
: tr
}
120 url
:= "http://dummy.faketld/"
121 client
.Get(url
) // Note: doesn't hit network
122 if tr
.req
.Method
!= "GET" {
123 t
.Errorf("expected method %q; got %q", "GET", tr
.req
.Method
)
125 if tr
.req
.URL
.String() != url
{
126 t
.Errorf("expected URL %q; got %q", url
, tr
.req
.URL
.String())
128 if tr
.req
.Header
== nil {
129 t
.Errorf("expected non-nil request Header")
133 func TestPostRequestFormat(t
*testing
.T
) {
135 tr
:= &recordingTransport
{}
136 client
:= &Client
{Transport
: tr
}
138 url
:= "http://dummy.faketld/"
139 json
:= `{"key":"value"}`
140 b
:= strings
.NewReader(json
)
141 client
.Post(url
, "application/json", b
) // Note: doesn't hit network
143 if tr
.req
.Method
!= "POST" {
144 t
.Errorf("got method %q, want %q", tr
.req
.Method
, "POST")
146 if tr
.req
.URL
.String() != url
{
147 t
.Errorf("got URL %q, want %q", tr
.req
.URL
.String(), url
)
149 if tr
.req
.Header
== nil {
150 t
.Fatalf("expected non-nil request Header")
153 t
.Error("got Close true, want false")
155 if g
, e
:= tr
.req
.ContentLength
, int64(len(json
)); g
!= e
{
156 t
.Errorf("got ContentLength %d, want %d", g
, e
)
160 func TestPostFormRequestFormat(t
*testing
.T
) {
162 tr
:= &recordingTransport
{}
163 client
:= &Client
{Transport
: tr
}
165 urlStr
:= "http://dummy.faketld/"
166 form
:= make(url
.Values
)
167 form
.Set("foo", "bar")
168 form
.Add("foo", "bar2")
169 form
.Set("bar", "baz")
170 client
.PostForm(urlStr
, form
) // Note: doesn't hit network
172 if tr
.req
.Method
!= "POST" {
173 t
.Errorf("got method %q, want %q", tr
.req
.Method
, "POST")
175 if tr
.req
.URL
.String() != urlStr
{
176 t
.Errorf("got URL %q, want %q", tr
.req
.URL
.String(), urlStr
)
178 if tr
.req
.Header
== nil {
179 t
.Fatalf("expected non-nil request Header")
181 if g
, e
:= tr
.req
.Header
.Get("Content-Type"), "application/x-www-form-urlencoded"; g
!= e
{
182 t
.Errorf("got Content-Type %q, want %q", g
, e
)
185 t
.Error("got Close true, want false")
187 // Depending on map iteration, body can be either of these.
188 expectedBody
:= "foo=bar&foo=bar2&bar=baz"
189 expectedBody1
:= "bar=baz&foo=bar&foo=bar2"
190 if g
, e
:= tr
.req
.ContentLength
, int64(len(expectedBody
)); g
!= e
{
191 t
.Errorf("got ContentLength %d, want %d", g
, e
)
193 bodyb
, err
:= ioutil
.ReadAll(tr
.req
.Body
)
195 t
.Fatalf("ReadAll on req.Body: %v", err
)
197 if g
:= string(bodyb
); g
!= expectedBody
&& g
!= expectedBody1
{
198 t
.Errorf("got body %q, want %q or %q", g
, expectedBody
, expectedBody1
)
202 func TestClientRedirects(t
*testing
.T
) {
205 var ts
*httptest
.Server
206 ts
= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
207 n
, _
:= strconv
.Atoi(r
.FormValue("n"))
208 // Test Referer header. (7 is arbitrary position to test at)
210 if g
, e
:= r
.Referer(), ts
.URL
+"/?n=6"; e
!= g
{
211 t
.Errorf("on request ?n=7, expected referer of %q; got %q", e
, g
)
215 Redirect(w
, r
, fmt
.Sprintf("/?n=%d", n
+1), StatusTemporaryRedirect
)
218 fmt
.Fprintf(w
, "n=%d", n
)
223 _
, err
:= c
.Get(ts
.URL
)
224 if e
, g
:= "Get /?n=10: stopped after 10 redirects", fmt
.Sprintf("%v", err
); e
!= g
{
225 t
.Errorf("with default client Get, expected error %q, got %q", e
, g
)
228 // HEAD request should also have the ability to follow redirects.
229 _
, err
= c
.Head(ts
.URL
)
230 if e
, g
:= "Head /?n=10: stopped after 10 redirects", fmt
.Sprintf("%v", err
); e
!= g
{
231 t
.Errorf("with default client Head, expected error %q, got %q", e
, g
)
234 // Do should also follow redirects.
235 greq
, _
:= NewRequest("GET", ts
.URL
, nil)
237 if e
, g
:= "Get /?n=10: stopped after 10 redirects", fmt
.Sprintf("%v", err
); e
!= g
{
238 t
.Errorf("with default client Do, expected error %q, got %q", e
, g
)
241 // Requests with an empty Method should also redirect (Issue 12705)
244 if e
, g
:= "Get /?n=10: stopped after 10 redirects", fmt
.Sprintf("%v", err
); e
!= g
{
245 t
.Errorf("with default client Do and empty Method, expected error %q, got %q", e
, g
)
249 var lastVia
[]*Request
251 c
.CheckRedirect
= func(req
*Request
, via
[]*Request
) error
{
256 res
, err
:= c
.Get(ts
.URL
)
258 t
.Fatalf("Get error: %v", err
)
261 finalUrl
:= res
.Request
.URL
.String()
262 if e
, g
:= "<nil>", fmt
.Sprintf("%v", err
); e
!= g
{
263 t
.Errorf("with custom client, expected error %q, got %q", e
, g
)
265 if !strings
.HasSuffix(finalUrl
, "/?n=15") {
266 t
.Errorf("expected final url to end in /?n=15; got url %q", finalUrl
)
268 if e
, g
:= 15, len(lastVia
); e
!= g
{
269 t
.Errorf("expected lastVia to have contained %d elements; got %d", e
, g
)
272 // Test that Request.Cancel is propagated between requests (Issue 14053)
273 creq
, _
:= NewRequest("HEAD", ts
.URL
, nil)
274 cancel
:= make(chan struct{})
276 if _
, err
:= c
.Do(creq
); err
!= nil {
280 t
.Fatal("didn't see redirect")
282 if lastReq
.Cancel
!= cancel
{
283 t
.Errorf("expected lastReq to have the cancel channel set on the initial req")
286 checkErr
= errors
.New("no redirects allowed")
287 res
, err
= c
.Get(ts
.URL
)
288 if urlError
, ok
:= err
.(*url
.Error
); !ok || urlError
.Err
!= checkErr
{
289 t
.Errorf("with redirects forbidden, expected a *url.Error with our 'no redirects allowed' error inside; got %#v (%q)", err
, err
)
292 t
.Fatalf("Expected a non-nil Response on CheckRedirect failure (https://golang.org/issue/3795)")
295 if res
.Header
.Get("Location") == "" {
296 t
.Errorf("no Location header in Response")
300 // Tests that Client redirects' contexts are derived from the original request's context.
301 func TestClientRedirectContext(t
*testing
.T
) {
304 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
305 Redirect(w
, r
, "/", StatusTemporaryRedirect
)
309 ctx
, cancel
:= context
.WithCancel(context
.Background())
311 c
.CheckRedirect
= func(req
*Request
, via
[]*Request
) error
{
314 case <-req
.Context().Done():
316 case <-time
.After(5 * time
.Second
):
317 return errors
.New("redirected request's context never expired after root request canceled")
320 req
, _
:= NewRequest("GET", ts
.URL
, nil)
321 req
= req
.WithContext(ctx
)
323 ue
, ok
:= err
.(*url
.Error
)
325 t
.Fatalf("got error %T; want *url.Error", err
)
327 if ue
.Err
!= context
.Canceled
{
328 t
.Errorf("url.Error.Err = %v; want %v", ue
.Err
, context
.Canceled
)
332 type redirectTest
struct {
334 want
int // response code
338 func TestPostRedirects(t
*testing
.T
) {
339 postRedirectTests
:= []redirectTest
{
341 {"/?code=301&next=302", 200, "c301"},
342 {"/?code=302&next=302", 200, "c302"},
343 {"/?code=303&next=301", 200, "c303wc301"}, // Issue 9348
344 {"/?code=304", 304, "c304"},
345 {"/?code=305", 305, "c305"},
346 {"/?code=307&next=303,308,302", 200, "c307"},
347 {"/?code=308&next=302,301", 200, "c308"},
348 {"/?code=404", 404, "c404"},
351 wantSegments
:= []string{
353 `POST /?code=301&next=302 "c301"`,
356 `POST /?code=302&next=302 "c302"`,
359 `POST /?code=303&next=301 "c303wc301"`,
362 `POST /?code=304 "c304"`,
363 `POST /?code=305 "c305"`,
364 `POST /?code=307&next=303,308,302 "c307"`,
365 `POST /?code=303&next=308,302 "c307"`,
366 `GET /?code=308&next=302 ""`,
367 `GET /?code=302 "c307"`,
369 `POST /?code=308&next=302,301 "c308"`,
370 `POST /?code=302&next=301 "c308"`,
373 `POST /?code=404 "c404"`,
375 want
:= strings
.Join(wantSegments
, "\n")
376 testRedirectsByMethod(t
, "POST", postRedirectTests
, want
)
379 func TestDeleteRedirects(t
*testing
.T
) {
380 deleteRedirectTests
:= []redirectTest
{
382 {"/?code=301&next=302,308", 200, "c301"},
383 {"/?code=302&next=302", 200, "c302"},
384 {"/?code=303", 200, "c303"},
385 {"/?code=307&next=301,308,303,302,304", 304, "c307"},
386 {"/?code=308&next=307", 200, "c308"},
387 {"/?code=404", 404, "c404"},
390 wantSegments
:= []string{
392 `DELETE /?code=301&next=302,308 "c301"`,
393 `GET /?code=302&next=308 ""`,
396 `DELETE /?code=302&next=302 "c302"`,
399 `DELETE /?code=303 "c303"`,
401 `DELETE /?code=307&next=301,308,303,302,304 "c307"`,
402 `DELETE /?code=301&next=308,303,302,304 "c307"`,
403 `GET /?code=308&next=303,302,304 ""`,
404 `GET /?code=303&next=302,304 "c307"`,
405 `GET /?code=302&next=304 ""`,
407 `DELETE /?code=308&next=307 "c308"`,
408 `DELETE /?code=307 "c308"`,
410 `DELETE /?code=404 "c404"`,
412 want
:= strings
.Join(wantSegments
, "\n")
413 testRedirectsByMethod(t
, "DELETE", deleteRedirectTests
, want
)
416 func testRedirectsByMethod(t
*testing
.T
, method
string, table
[]redirectTest
, want
string) {
422 var ts
*httptest
.Server
423 ts
= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
425 slurp
, _
:= ioutil
.ReadAll(r
.Body
)
426 fmt
.Fprintf(&log
.Buffer
, "%s %s %q", r
.Method
, r
.RequestURI
, slurp
)
427 if cl
:= r
.Header
.Get("Content-Length"); r
.Method
== "GET" && len(slurp
) == 0 && (r
.ContentLength
!= 0 || cl
!= "") {
428 fmt
.Fprintf(&log
.Buffer
, " (but with body=%T, content-length = %v, %q)", r
.Body
, r
.ContentLength
, cl
)
432 urlQuery
:= r
.URL
.Query()
433 if v
:= urlQuery
.Get("code"); v
!= "" {
435 if final
:= urlQuery
.Get("next"); final
!= "" {
436 splits
:= strings
.Split(final
, ",")
437 first
, rest
:= splits
[0], splits
[1:]
438 location
= fmt
.Sprintf("%s?code=%s", location
, first
)
440 location
= fmt
.Sprintf("%s&next=%s", location
, strings
.Join(rest
, ","))
443 code
, _
:= strconv
.Atoi(v
)
445 w
.Header().Set("Location", location
)
453 for _
, tt
:= range table
{
454 content
:= tt
.redirectBody
455 req
, _
:= NewRequest(method
, ts
.URL
+tt
.suffix
, strings
.NewReader(content
))
456 req
.GetBody
= func() (io
.ReadCloser
, error
) { return ioutil
.NopCloser(strings
.NewReader(content
)), nil }
457 res
, err
:= c
.Do(req
)
462 if res
.StatusCode
!= tt
.want
{
463 t
.Errorf("POST %s: status code = %d; want %d", tt
.suffix
, res
.StatusCode
, tt
.want
)
470 got
= strings
.TrimSpace(got
)
471 want
= strings
.TrimSpace(want
)
474 got
, want
, lines
:= removeCommonLines(got
, want
)
475 t
.Errorf("Log differs after %d common lines.\n\nGot:\n%s\n\nWant:\n%s\n", lines
, got
, want
)
479 func removeCommonLines(a
, b
string) (asuffix
, bsuffix
string, commonLines
int) {
481 nl
:= strings
.IndexByte(a
, '\n')
483 return a
, b
, commonLines
486 if !strings
.HasPrefix(b
, line
) {
487 return a
, b
, commonLines
495 func TestClientRedirectUseResponse(t
*testing
.T
) {
498 const body
= "Hello, world."
499 var ts
*httptest
.Server
500 ts
= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
501 if strings
.Contains(r
.URL
.Path
, "/other") {
502 io
.WriteString(w
, "wrong body")
504 w
.Header().Set("Location", ts
.URL
+"/other")
505 w
.WriteHeader(StatusFound
)
506 io
.WriteString(w
, body
)
512 c
.CheckRedirect
= func(req
*Request
, via
[]*Request
) error
{
513 if req
.Response
== nil {
514 t
.Error("expected non-nil Request.Response")
516 return ErrUseLastResponse
518 res
, err
:= c
.Get(ts
.URL
)
522 if res
.StatusCode
!= StatusFound
{
523 t
.Errorf("status = %d; want %d", res
.StatusCode
, StatusFound
)
525 defer res
.Body
.Close()
526 slurp
, err
:= ioutil
.ReadAll(res
.Body
)
530 if string(slurp
) != body
{
531 t
.Errorf("body = %q; want %q", slurp
, body
)
535 // Issue 17773: don't follow a 308 (or 307) if the response doesn't
536 // have a Location header.
537 func TestClientRedirect308NoLocation(t
*testing
.T
) {
540 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
541 w
.Header().Set("Foo", "Bar")
546 res
, err
:= c
.Get(ts
.URL
)
551 if res
.StatusCode
!= 308 {
552 t
.Errorf("status = %d; want %d", res
.StatusCode
, 308)
554 if got
:= res
.Header
.Get("Foo"); got
!= "Bar" {
555 t
.Errorf("Foo header = %q; want Bar", got
)
559 // Don't follow a 307/308 if we can't resent the request body.
560 func TestClientRedirect308NoGetBody(t
*testing
.T
) {
563 const fakeURL
= "https://localhost:1234/" // won't be hit
564 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
565 w
.Header().Set("Location", fakeURL
)
569 req
, err
:= NewRequest("POST", ts
.URL
, strings
.NewReader("some body"))
574 req
.GetBody
= nil // so it can't rewind.
575 res
, err
:= c
.Do(req
)
580 if res
.StatusCode
!= 308 {
581 t
.Errorf("status = %d; want %d", res
.StatusCode
, 308)
583 if got
:= res
.Header
.Get("Location"); got
!= fakeURL
{
584 t
.Errorf("Location header = %q; want %q", got
, fakeURL
)
588 var expectedCookies
= []*Cookie
{
589 {Name
: "ChocolateChip", Value
: "tasty"},
590 {Name
: "First", Value
: "Hit"},
591 {Name
: "Second", Value
: "Hit"},
594 var echoCookiesRedirectHandler
= HandlerFunc(func(w ResponseWriter
, r
*Request
) {
595 for _
, cookie
:= range r
.Cookies() {
598 if r
.URL
.Path
== "/" {
599 SetCookie(w
, expectedCookies
[1])
600 Redirect(w
, r
, "/second", StatusMovedPermanently
)
602 SetCookie(w
, expectedCookies
[2])
603 w
.Write([]byte("hello"))
607 func TestClientSendsCookieFromJar(t
*testing
.T
) {
609 tr
:= &recordingTransport
{}
610 client
:= &Client
{Transport
: tr
}
611 client
.Jar
= &TestJar
{perURL
: make(map[string][]*Cookie
)}
612 us
:= "http://dummy.faketld/"
613 u
, _
:= url
.Parse(us
)
614 client
.Jar
.SetCookies(u
, expectedCookies
)
616 client
.Get(us
) // Note: doesn't hit network
617 matchReturnedCookies(t
, expectedCookies
, tr
.req
.Cookies())
619 client
.Head(us
) // Note: doesn't hit network
620 matchReturnedCookies(t
, expectedCookies
, tr
.req
.Cookies())
622 client
.Post(us
, "text/plain", strings
.NewReader("body")) // Note: doesn't hit network
623 matchReturnedCookies(t
, expectedCookies
, tr
.req
.Cookies())
625 client
.PostForm(us
, url
.Values
{}) // Note: doesn't hit network
626 matchReturnedCookies(t
, expectedCookies
, tr
.req
.Cookies())
628 req
, _
:= NewRequest("GET", us
, nil)
629 client
.Do(req
) // Note: doesn't hit network
630 matchReturnedCookies(t
, expectedCookies
, tr
.req
.Cookies())
632 req
, _
= NewRequest("POST", us
, nil)
633 client
.Do(req
) // Note: doesn't hit network
634 matchReturnedCookies(t
, expectedCookies
, tr
.req
.Cookies())
637 // Just enough correctness for our redirect tests. Uses the URL.Host as the
638 // scope of all cookies.
639 type TestJar
struct {
641 perURL
map[string][]*Cookie
644 func (j
*TestJar
) SetCookies(u
*url
.URL
, cookies
[]*Cookie
) {
648 j
.perURL
= make(map[string][]*Cookie
)
650 j
.perURL
[u
.Host
] = cookies
653 func (j
*TestJar
) Cookies(u
*url
.URL
) []*Cookie
{
656 return j
.perURL
[u
.Host
]
659 func TestRedirectCookiesJar(t
*testing
.T
) {
662 var ts
*httptest
.Server
663 ts
= httptest
.NewServer(echoCookiesRedirectHandler
)
667 u
, _
:= url
.Parse(ts
.URL
)
668 c
.Jar
.SetCookies(u
, []*Cookie
{expectedCookies
[0]})
669 resp
, err
:= c
.Get(ts
.URL
)
671 t
.Fatalf("Get: %v", err
)
674 matchReturnedCookies(t
, expectedCookies
, resp
.Cookies())
677 func matchReturnedCookies(t
*testing
.T
, expected
, given
[]*Cookie
) {
678 if len(given
) != len(expected
) {
679 t
.Logf("Received cookies: %v", given
)
680 t
.Errorf("Expected %d cookies, got %d", len(expected
), len(given
))
682 for _
, ec
:= range expected
{
684 for _
, c
:= range given
{
685 if ec
.Name
== c
.Name
&& ec
.Value
== c
.Value
{
691 t
.Errorf("Missing cookie %v", ec
)
696 func TestJarCalls(t
*testing
.T
) {
698 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
699 pathSuffix
:= r
.RequestURI
[1:]
700 if r
.RequestURI
== "/nosetcookie" {
701 return // don't set cookies for this path
703 SetCookie(w
, &Cookie
{Name
: "name" + pathSuffix
, Value
: "val" + pathSuffix
})
704 if r
.RequestURI
== "/" {
705 Redirect(w
, r
, "http://secondhost.fake/secondpath", 302)
709 jar
:= new(RecordingJar
)
712 c
.Transport
.(*Transport
).Dial
= func(_
string, _
string) (net
.Conn
, error
) {
713 return net
.Dial("tcp", ts
.Listener
.Addr().String())
715 _
, err
:= c
.Get("http://firsthost.fake/")
719 _
, err
= c
.Get("http://firsthost.fake/nosetcookie")
723 got
:= jar
.log
.String()
724 want
:= `Cookies("http://firsthost.fake/")
725 SetCookie("http://firsthost.fake/", [name=val])
726 Cookies("http://secondhost.fake/secondpath")
727 SetCookie("http://secondhost.fake/secondpath", [namesecondpath=valsecondpath])
728 Cookies("http://firsthost.fake/nosetcookie")
731 t
.Errorf("Got Jar calls:\n%s\nWant:\n%s", got
, want
)
735 // RecordingJar keeps a log of calls made to it, without
736 // tracking any cookies.
737 type RecordingJar
struct {
742 func (j
*RecordingJar
) SetCookies(u
*url
.URL
, cookies
[]*Cookie
) {
743 j
.logf("SetCookie(%q, %v)\n", u
, cookies
)
746 func (j
*RecordingJar
) Cookies(u
*url
.URL
) []*Cookie
{
747 j
.logf("Cookies(%q)\n", u
)
751 func (j
*RecordingJar
) logf(format
string, args
...interface{}) {
754 fmt
.Fprintf(&j
.log
, format
, args
...)
757 func TestStreamingGet_h1(t
*testing
.T
) { testStreamingGet(t
, h1Mode
) }
758 func TestStreamingGet_h2(t
*testing
.T
) { testStreamingGet(t
, h2Mode
) }
760 func testStreamingGet(t
*testing
.T
, h2
bool) {
762 say
:= make(chan string)
763 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
765 for str
:= range say
{
773 res
, err
:= c
.Get(cst
.ts
.URL
)
778 for _
, str
:= range []string{"i", "am", "also", "known", "as", "comet"} {
780 n
, err
:= io
.ReadFull(res
.Body
, buf
[0:len(str
)])
782 t
.Fatalf("ReadFull on %q: %v", str
, err
)
785 t
.Fatalf("Receiving %q, only read %d bytes", str
, n
)
787 got
:= string(buf
[0:n
])
789 t
.Fatalf("Expected %q, got %q", str
, got
)
793 _
, err
= io
.ReadFull(res
.Body
, buf
[0:1])
795 t
.Fatalf("at end expected EOF, got %v", err
)
799 type writeCountingConn
struct {
804 func (c
*writeCountingConn
) Write(p
[]byte) (int, error
) {
806 return c
.Conn
.Write(p
)
809 // TestClientWrites verifies that client requests are buffered and we
810 // don't send a TCP packet per line of the http request + body.
811 func TestClientWrites(t
*testing
.T
) {
813 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
818 dialer
:= func(netz
string, addr
string) (net
.Conn
, error
) {
819 c
, err
:= net
.Dial(netz
, addr
)
821 c
= &writeCountingConn
{c
, &writes
}
826 c
.Transport
.(*Transport
).Dial
= dialer
828 _
, err
:= c
.Get(ts
.URL
)
833 t
.Errorf("Get request did %d Write calls, want 1", writes
)
837 _
, err
= c
.PostForm(ts
.URL
, url
.Values
{"foo": {"bar"}})
842 t
.Errorf("Post request did %d Write calls, want 1", writes
)
846 func TestClientInsecureTransport(t
*testing
.T
) {
849 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
850 w
.Write([]byte("Hello"))
852 errc
:= make(chanWriter
, 10) // but only expecting 1
853 ts
.Config
.ErrorLog
= log
.New(errc
, "", 0)
856 // TODO(bradfitz): add tests for skipping hostname checks too?
857 // would require a new cert for testing, and probably
858 // redundant with these tests.
860 for _
, insecure
:= range []bool{true, false} {
861 c
.Transport
.(*Transport
).TLSClientConfig
= &tls
.Config
{
862 InsecureSkipVerify
: insecure
,
864 res
, err
:= c
.Get(ts
.URL
)
865 if (err
== nil) != insecure
{
866 t
.Errorf("insecure=%v: got unexpected err=%v", insecure
, err
)
875 if !strings
.Contains(v
, "TLS handshake error") {
876 t
.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v
)
878 case <-time
.After(5 * time
.Second
):
879 t
.Errorf("timeout waiting for logged error")
884 func TestClientErrorWithRequestURI(t
*testing
.T
) {
886 req
, _
:= NewRequest("GET", "http://localhost:1234/", nil)
887 req
.RequestURI
= "/this/field/is/illegal/and/should/error/"
888 _
, err
:= DefaultClient
.Do(req
)
890 t
.Fatalf("expected an error")
892 if !strings
.Contains(err
.Error(), "RequestURI") {
893 t
.Errorf("wanted error mentioning RequestURI; got error: %v", err
)
897 func TestClientWithCorrectTLSServerName(t
*testing
.T
) {
900 const serverName
= "example.com"
901 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
902 if r
.TLS
.ServerName
!= serverName
{
903 t
.Errorf("expected client to set ServerName %q, got: %q", serverName
, r
.TLS
.ServerName
)
909 c
.Transport
.(*Transport
).TLSClientConfig
.ServerName
= serverName
910 if _
, err
:= c
.Get(ts
.URL
); err
!= nil {
911 t
.Fatalf("expected successful TLS connection, got error: %v", err
)
915 func TestClientWithIncorrectTLSServerName(t
*testing
.T
) {
917 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {}))
919 errc
:= make(chanWriter
, 10) // but only expecting 1
920 ts
.Config
.ErrorLog
= log
.New(errc
, "", 0)
923 c
.Transport
.(*Transport
).TLSClientConfig
.ServerName
= "badserver"
924 _
, err
:= c
.Get(ts
.URL
)
926 t
.Fatalf("expected an error")
928 if !strings
.Contains(err
.Error(), "127.0.0.1") ||
!strings
.Contains(err
.Error(), "badserver") {
929 t
.Errorf("wanted error mentioning 127.0.0.1 and badserver; got error: %v", err
)
933 if !strings
.Contains(v
, "TLS handshake error") {
934 t
.Errorf("expected an error log message containing 'TLS handshake error'; got %q", v
)
936 case <-time
.After(5 * time
.Second
):
937 t
.Errorf("timeout waiting for logged error")
941 // Test for golang.org/issue/5829; the Transport should respect TLSClientConfig.ServerName
944 // tls.Config.ServerName (non-empty, set to "example.com") takes
945 // precedence over "some-other-host.tld" which previously incorrectly
946 // took precedence. We don't actually connect to (or even resolve)
947 // "some-other-host.tld", though, because of the Transport.Dial hook.
949 // The httptest.Server has a cert with "example.com" as its name.
950 func TestTransportUsesTLSConfigServerName(t
*testing
.T
) {
952 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
953 w
.Write([]byte("Hello"))
958 tr
:= c
.Transport
.(*Transport
)
959 tr
.TLSClientConfig
.ServerName
= "example.com" // one of httptest's Server cert names
960 tr
.Dial
= func(netw
, addr
string) (net
.Conn
, error
) {
961 return net
.Dial(netw
, ts
.Listener
.Addr().String())
963 res
, err
:= c
.Get("https://some-other-host.tld/")
970 func TestResponseSetsTLSConnectionState(t
*testing
.T
) {
972 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
973 w
.Write([]byte("Hello"))
978 tr
:= c
.Transport
.(*Transport
)
979 tr
.TLSClientConfig
.CipherSuites
= []uint16{tls
.TLS_RSA_WITH_3DES_EDE_CBC_SHA
}
980 tr
.Dial
= func(netw
, addr
string) (net
.Conn
, error
) {
981 return net
.Dial(netw
, ts
.Listener
.Addr().String())
983 res
, err
:= c
.Get("https://example.com/")
987 defer res
.Body
.Close()
989 t
.Fatal("Response didn't set TLS Connection State.")
991 if got
, want
:= res
.TLS
.CipherSuite
, tls
.TLS_RSA_WITH_3DES_EDE_CBC_SHA
; got
!= want
{
992 t
.Errorf("TLS Cipher Suite = %d; want %d", got
, want
)
996 // Check that an HTTPS client can interpret a particular TLS error
997 // to determine that the server is speaking HTTP.
998 // See golang.org/issue/11111.
999 func TestHTTPSClientDetectsHTTPServer(t
*testing
.T
) {
1001 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {}))
1002 ts
.Config
.ErrorLog
= quietLog
1005 _
, err
:= Get(strings
.Replace(ts
.URL
, "http", "https", 1))
1006 if got
:= err
.Error(); !strings
.Contains(got
, "HTTP response to HTTPS client") {
1007 t
.Fatalf("error = %q; want error indicating HTTP response to HTTPS request", got
)
1011 // Verify Response.ContentLength is populated. https://golang.org/issue/4126
1012 func TestClientHeadContentLength_h1(t
*testing
.T
) {
1013 testClientHeadContentLength(t
, h1Mode
)
1016 func TestClientHeadContentLength_h2(t
*testing
.T
) {
1017 testClientHeadContentLength(t
, h2Mode
)
1020 func testClientHeadContentLength(t
*testing
.T
, h2
bool) {
1022 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1023 if v
:= r
.FormValue("cl"); v
!= "" {
1024 w
.Header().Set("Content-Length", v
)
1032 {"/?cl=1234", 1234},
1036 for _
, tt
:= range tests
{
1037 req
, _
:= NewRequest("HEAD", cst
.ts
.URL
+tt
.suffix
, nil)
1038 res
, err
:= cst
.c
.Do(req
)
1042 if res
.ContentLength
!= tt
.want
{
1043 t
.Errorf("Content-Length = %d; want %d", res
.ContentLength
, tt
.want
)
1045 bs
, err
:= ioutil
.ReadAll(res
.Body
)
1050 t
.Errorf("Unexpected content: %q", bs
)
1055 func TestEmptyPasswordAuth(t
*testing
.T
) {
1059 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1060 auth
:= r
.Header
.Get("Authorization")
1061 if strings
.HasPrefix(auth
, "Basic ") {
1063 decoded
, err
:= base64
.StdEncoding
.DecodeString(encoded
)
1067 expected
:= gopher
+ ":"
1068 s
:= string(decoded
)
1070 t
.Errorf("Invalid Authorization header. Got %q, wanted %q", s
, expected
)
1073 t
.Errorf("Invalid auth %q", auth
)
1077 req
, err
:= NewRequest("GET", ts
.URL
, nil)
1081 req
.URL
.User
= url
.User(gopher
)
1083 resp
, err
:= c
.Do(req
)
1087 defer resp
.Body
.Close()
1090 func TestBasicAuth(t
*testing
.T
) {
1092 tr
:= &recordingTransport
{}
1093 client
:= &Client
{Transport
: tr
}
1095 url
:= "http://My%20User:My%20Pass@dummy.faketld/"
1096 expected
:= "My User:My Pass"
1099 if tr
.req
.Method
!= "GET" {
1100 t
.Errorf("got method %q, want %q", tr
.req
.Method
, "GET")
1102 if tr
.req
.URL
.String() != url
{
1103 t
.Errorf("got URL %q, want %q", tr
.req
.URL
.String(), url
)
1105 if tr
.req
.Header
== nil {
1106 t
.Fatalf("expected non-nil request Header")
1108 auth
:= tr
.req
.Header
.Get("Authorization")
1109 if strings
.HasPrefix(auth
, "Basic ") {
1111 decoded
, err
:= base64
.StdEncoding
.DecodeString(encoded
)
1115 s
:= string(decoded
)
1117 t
.Errorf("Invalid Authorization header. Got %q, wanted %q", s
, expected
)
1120 t
.Errorf("Invalid auth %q", auth
)
1124 func TestBasicAuthHeadersPreserved(t
*testing
.T
) {
1126 tr
:= &recordingTransport
{}
1127 client
:= &Client
{Transport
: tr
}
1129 // If Authorization header is provided, username in URL should not override it
1130 url
:= "http://My%20User@dummy.faketld/"
1131 req
, err
:= NewRequest("GET", url
, nil)
1135 req
.SetBasicAuth("My User", "My Pass")
1136 expected
:= "My User:My Pass"
1139 if tr
.req
.Method
!= "GET" {
1140 t
.Errorf("got method %q, want %q", tr
.req
.Method
, "GET")
1142 if tr
.req
.URL
.String() != url
{
1143 t
.Errorf("got URL %q, want %q", tr
.req
.URL
.String(), url
)
1145 if tr
.req
.Header
== nil {
1146 t
.Fatalf("expected non-nil request Header")
1148 auth
:= tr
.req
.Header
.Get("Authorization")
1149 if strings
.HasPrefix(auth
, "Basic ") {
1151 decoded
, err
:= base64
.StdEncoding
.DecodeString(encoded
)
1155 s
:= string(decoded
)
1157 t
.Errorf("Invalid Authorization header. Got %q, wanted %q", s
, expected
)
1160 t
.Errorf("Invalid auth %q", auth
)
1165 func TestClientTimeout_h1(t
*testing
.T
) { testClientTimeout(t
, h1Mode
) }
1166 func TestClientTimeout_h2(t
*testing
.T
) { testClientTimeout(t
, h2Mode
) }
1168 func testClientTimeout(t
*testing
.T
, h2
bool) {
1171 testDone
:= make(chan struct{}) // closed in defer below
1173 sawRoot
:= make(chan bool, 1)
1174 sawSlow
:= make(chan bool, 1)
1175 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1176 if r
.URL
.Path
== "/" {
1178 Redirect(w
, r
, "/slow", StatusFound
)
1181 if r
.URL
.Path
== "/slow" {
1183 w
.Write([]byte("Hello"))
1190 defer close(testDone
) // before cst.close, to unblock /slow handler
1192 // 200ms should be long enough to get a normal request (the /
1193 // handler), but not so long that it makes the test slow.
1194 const timeout
= 200 * time
.Millisecond
1195 cst
.c
.Timeout
= timeout
1197 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
1199 if strings
.Contains(err
.Error(), "Client.Timeout") {
1200 t
.Skipf("host too slow to get fast resource in %v", timeout
)
1209 t
.Fatal("handler never got / request")
1216 t
.Fatal("handler never got /slow request")
1219 errc
:= make(chan error
, 1)
1221 _
, err
:= ioutil
.ReadAll(res
.Body
)
1226 const failTime
= 5 * time
.Second
1230 t
.Fatal("expected error from ReadAll")
1232 ne
, ok
:= err
.(net
.Error
)
1234 t
.Errorf("error value from ReadAll was %T; expected some net.Error", err
)
1235 } else if !ne
.Timeout() {
1236 t
.Errorf("net.Error.Timeout = false; want true")
1238 if got
:= ne
.Error(); !strings
.Contains(got
, "Client.Timeout exceeded") {
1239 t
.Errorf("error string = %q; missing timeout substring", got
)
1241 case <-time
.After(failTime
):
1242 t
.Errorf("timeout after %v waiting for timeout of %v", failTime
, timeout
)
1246 func TestClientTimeout_Headers_h1(t
*testing
.T
) { testClientTimeout_Headers(t
, h1Mode
) }
1247 func TestClientTimeout_Headers_h2(t
*testing
.T
) { testClientTimeout_Headers(t
, h2Mode
) }
1249 // Client.Timeout firing before getting to the body
1250 func testClientTimeout_Headers(t
*testing
.T
, h2
bool) {
1253 donec
:= make(chan bool, 1)
1254 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1258 // Note that we use a channel send here and not a close.
1259 // The race detector doesn't know that we're waiting for a timeout
1260 // and thinks that the waitgroup inside httptest.Server is added to concurrently
1261 // with us closing it. If we timed out immediately, we could close the testserver
1262 // before we entered the handler. We're not timing out immediately and there's
1263 // no way we would be done before we entered the handler, but the race detector
1264 // doesn't know this, so synchronize explicitly.
1265 defer func() { donec
<- true }()
1267 cst
.c
.Timeout
= 5 * time
.Millisecond
1268 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
1271 t
.Fatal("got response from Get; expected error")
1273 if _
, ok
:= err
.(*url
.Error
); !ok
{
1274 t
.Fatalf("Got error of type %T; want *url.Error", err
)
1276 ne
, ok
:= err
.(net
.Error
)
1278 t
.Fatalf("Got error of type %T; want some net.Error", err
)
1281 t
.Error("net.Error.Timeout = false; want true")
1283 if got
:= ne
.Error(); !strings
.Contains(got
, "Client.Timeout exceeded") {
1284 t
.Errorf("error string = %q; missing timeout substring", got
)
1288 // Issue 16094: if Client.Timeout is set but not hit, a Timeout error shouldn't be
1290 func TestClientTimeoutCancel(t
*testing
.T
) {
1294 testDone
:= make(chan struct{})
1295 ctx
, cancel
:= context
.WithCancel(context
.Background())
1297 cst
:= newClientServerTest(t
, h1Mode
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1302 defer close(testDone
)
1304 cst
.c
.Timeout
= 1 * time
.Hour
1305 req
, _
:= NewRequest("GET", cst
.ts
.URL
, nil)
1306 req
.Cancel
= ctx
.Done()
1307 res
, err
:= cst
.c
.Do(req
)
1312 _
, err
= io
.Copy(ioutil
.Discard
, res
.Body
)
1313 if err
!= ExportErrRequestCanceled
{
1314 t
.Fatalf("error = %v; want errRequestCanceled", err
)
1318 func TestClientRedirectEatsBody_h1(t
*testing
.T
) { testClientRedirectEatsBody(t
, h1Mode
) }
1319 func TestClientRedirectEatsBody_h2(t
*testing
.T
) { testClientRedirectEatsBody(t
, h2Mode
) }
1320 func testClientRedirectEatsBody(t
*testing
.T
, h2
bool) {
1323 saw
:= make(chan string, 2)
1324 cst
:= newClientServerTest(t
, h2
, HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1326 if r
.URL
.Path
== "/" {
1327 Redirect(w
, r
, "/foo", StatusFound
) // which includes a body
1332 res
, err
:= cst
.c
.Get(cst
.ts
.URL
)
1336 _
, err
= ioutil
.ReadAll(res
.Body
)
1346 t
.Fatal("server didn't see a request")
1351 case second
= <-saw
:
1353 t
.Fatal("server didn't see a second request")
1356 if first
!= second
{
1357 t
.Fatal("server saw different client ports before & after the redirect")
1361 // eofReaderFunc is an io.Reader that runs itself, and then returns io.EOF.
1362 type eofReaderFunc
func()
1364 func (f eofReaderFunc
) Read(p
[]byte) (n
int, err error
) {
1369 func TestReferer(t
*testing
.T
) {
1371 lastReq
, newReq
string // from -> to URLs
1375 {"http://gopher@test.com", "http://link.com", "http://test.com"},
1376 {"https://gopher@test.com", "https://link.com", "https://test.com"},
1378 // don't send a user and password:
1379 {"http://gopher:go@test.com", "http://link.com", "http://test.com"},
1380 {"https://gopher:go@test.com", "https://link.com", "https://test.com"},
1383 {"http://test.com", "http://link.com", "http://test.com"},
1384 {"https://test.com", "https://link.com", "https://test.com"},
1386 // https to http doesn't send a referer:
1387 {"https://test.com", "http://link.com", ""},
1388 {"https://gopher:go@test.com", "http://link.com", ""},
1390 for _
, tt
:= range tests
{
1391 l
, err
:= url
.Parse(tt
.lastReq
)
1395 n
, err
:= url
.Parse(tt
.newReq
)
1399 r
:= ExportRefererForURL(l
, n
)
1401 t
.Errorf("refererForURL(%q, %q) = %q; want %q", tt
.lastReq
, tt
.newReq
, r
, tt
.want
)
1406 // issue15577Tripper returns a Response with a redirect response
1407 // header and doesn't populate its Response.Request field.
1408 type issue15577Tripper
struct{}
1410 func (issue15577Tripper
) RoundTrip(*Request
) (*Response
, error
) {
1413 Header
: map[string][]string{"Location": {"http://www.example.com/"}},
1414 Body
: ioutil
.NopCloser(strings
.NewReader("")),
1419 // Issue 15577: don't assume the roundtripper's response populates its Request field.
1420 func TestClientRedirectResponseWithoutRequest(t
*testing
.T
) {
1422 CheckRedirect
: func(*Request
, []*Request
) error
{ return fmt
.Errorf("no redirects!") },
1423 Transport
: issue15577Tripper
{},
1425 // Check that this doesn't crash:
1426 c
.Get("http://dummy.tld")
1429 // Issue 4800: copy (some) headers when Client follows a redirect
1430 func TestClientCopyHeadersOnRedirect(t
*testing
.T
) {
1432 ua
= "some-agent/1.2"
1436 ts1
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1438 "User-Agent": []string{ua
},
1439 "X-Foo": []string{xfoo
},
1440 "Referer": []string{ts2URL
},
1441 "Accept-Encoding": []string{"gzip"},
1443 if !reflect
.DeepEqual(r
.Header
, want
) {
1444 t
.Errorf("Request.Header = %#v; want %#v", r
.Header
, want
)
1447 w
.Header().Set("Result", "got errors")
1449 w
.Header().Set("Result", "ok")
1453 ts2
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1454 Redirect(w
, r
, ts1
.URL
, StatusFound
)
1460 c
.CheckRedirect
= func(r
*Request
, via
[]*Request
) error
{
1462 "User-Agent": []string{ua
},
1463 "X-Foo": []string{xfoo
},
1464 "Referer": []string{ts2URL
},
1466 if !reflect
.DeepEqual(r
.Header
, want
) {
1467 t
.Errorf("CheckRedirect Request.Header = %#v; want %#v", r
.Header
, want
)
1472 req
, _
:= NewRequest("GET", ts2
.URL
, nil)
1473 req
.Header
.Add("User-Agent", ua
)
1474 req
.Header
.Add("X-Foo", xfoo
)
1475 req
.Header
.Add("Cookie", "foo=bar")
1476 req
.Header
.Add("Authorization", "secretpassword")
1477 res
, err
:= c
.Do(req
)
1481 defer res
.Body
.Close()
1482 if res
.StatusCode
!= 200 {
1485 if got
:= res
.Header
.Get("Result"); got
!= "ok" {
1486 t
.Errorf("result = %q; want ok", got
)
1490 // Issue 17494: cookies should be altered when Client follows redirects.
1491 func TestClientAltersCookiesOnRedirect(t
*testing
.T
) {
1492 cookieMap
:= func(cs
[]*Cookie
) map[string][]string {
1493 m
:= make(map[string][]string)
1494 for _
, c
:= range cs
{
1495 m
[c
.Name
] = append(m
[c
.Name
], c
.Value
)
1500 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1501 var want
map[string][]string
1502 got
:= cookieMap(r
.Cookies())
1504 c
, _
:= r
.Cookie("Cycle")
1507 want
= map[string][]string{
1508 "Cookie1": {"OldValue1a", "OldValue1b"},
1509 "Cookie2": {"OldValue2"},
1510 "Cookie3": {"OldValue3a", "OldValue3b"},
1511 "Cookie4": {"OldValue4"},
1514 SetCookie(w
, &Cookie
{Name
: "Cycle", Value
: "1", Path
: "/"})
1515 SetCookie(w
, &Cookie
{Name
: "Cookie2", Path
: "/", MaxAge
: -1}) // Delete cookie from Header
1516 Redirect(w
, r
, "/", StatusFound
)
1518 want
= map[string][]string{
1519 "Cookie1": {"OldValue1a", "OldValue1b"},
1520 "Cookie3": {"OldValue3a", "OldValue3b"},
1521 "Cookie4": {"OldValue4"},
1524 SetCookie(w
, &Cookie
{Name
: "Cycle", Value
: "2", Path
: "/"})
1525 SetCookie(w
, &Cookie
{Name
: "Cookie3", Value
: "NewValue3", Path
: "/"}) // Modify cookie in Header
1526 SetCookie(w
, &Cookie
{Name
: "Cookie4", Value
: "NewValue4", Path
: "/"}) // Modify cookie in Jar
1527 Redirect(w
, r
, "/", StatusFound
)
1529 want
= map[string][]string{
1530 "Cookie1": {"OldValue1a", "OldValue1b"},
1531 "Cookie3": {"NewValue3"},
1532 "Cookie4": {"NewValue4"},
1535 SetCookie(w
, &Cookie
{Name
: "Cycle", Value
: "3", Path
: "/"})
1536 SetCookie(w
, &Cookie
{Name
: "Cookie5", Value
: "NewValue5", Path
: "/"}) // Insert cookie into Jar
1537 Redirect(w
, r
, "/", StatusFound
)
1539 want
= map[string][]string{
1540 "Cookie1": {"OldValue1a", "OldValue1b"},
1541 "Cookie3": {"NewValue3"},
1542 "Cookie4": {"NewValue4"},
1543 "Cookie5": {"NewValue5"},
1546 // Don't redirect to ensure the loop ends.
1548 t
.Errorf("unexpected redirect cycle")
1552 if !reflect
.DeepEqual(got
, want
) {
1553 t
.Errorf("redirect %s, Cookie = %v, want %v", c
.Value
, got
, want
)
1558 jar
, _
:= cookiejar
.New(nil)
1562 u
, _
:= url
.Parse(ts
.URL
)
1563 req
, _
:= NewRequest("GET", ts
.URL
, nil)
1564 req
.AddCookie(&Cookie
{Name
: "Cookie1", Value
: "OldValue1a"})
1565 req
.AddCookie(&Cookie
{Name
: "Cookie1", Value
: "OldValue1b"})
1566 req
.AddCookie(&Cookie
{Name
: "Cookie2", Value
: "OldValue2"})
1567 req
.AddCookie(&Cookie
{Name
: "Cookie3", Value
: "OldValue3a"})
1568 req
.AddCookie(&Cookie
{Name
: "Cookie3", Value
: "OldValue3b"})
1569 jar
.SetCookies(u
, []*Cookie
{{Name
: "Cookie4", Value
: "OldValue4", Path
: "/"}})
1570 jar
.SetCookies(u
, []*Cookie
{{Name
: "Cycle", Value
: "0", Path
: "/"}})
1571 res
, err
:= c
.Do(req
)
1575 defer res
.Body
.Close()
1576 if res
.StatusCode
!= 200 {
1581 // Part of Issue 4800
1582 func TestShouldCopyHeaderOnRedirect(t
*testing
.T
) {
1589 {"User-Agent", "http://foo.com/", "http://bar.com/", true},
1590 {"X-Foo", "http://foo.com/", "http://bar.com/", true},
1592 // Sensitive headers:
1593 {"cookie", "http://foo.com/", "http://bar.com/", false},
1594 {"cookie2", "http://foo.com/", "http://bar.com/", false},
1595 {"authorization", "http://foo.com/", "http://bar.com/", false},
1596 {"www-authenticate", "http://foo.com/", "http://bar.com/", false},
1598 // But subdomains should work:
1599 {"www-authenticate", "http://foo.com/", "http://foo.com/", true},
1600 {"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true},
1601 {"www-authenticate", "http://foo.com/", "http://notfoo.com/", false},
1602 // TODO(bradfitz): make this test work, once issue 16142 is fixed:
1603 // {"www-authenticate", "http://foo.com:80/", "http://foo.com/", true},
1605 for i
, tt
:= range tests
{
1606 u0
, err
:= url
.Parse(tt
.initialURL
)
1608 t
.Errorf("%d. initial URL %q parse error: %v", i
, tt
.initialURL
, err
)
1611 u1
, err
:= url
.Parse(tt
.destURL
)
1613 t
.Errorf("%d. dest URL %q parse error: %v", i
, tt
.destURL
, err
)
1616 got
:= Export_shouldCopyHeaderOnRedirect(tt
.header
, u0
, u1
)
1618 t
.Errorf("%d. shouldCopyHeaderOnRedirect(%q, %q => %q) = %v; want %v",
1619 i
, tt
.header
, tt
.initialURL
, tt
.destURL
, got
, tt
.want
)
1624 func TestClientRedirectTypes(t
*testing
.T
) {
1628 tests
:= [...]struct {
1631 wantMethod
string // desired subsequent client method
1633 0: {method
: "POST", serverStatus
: 301, wantMethod
: "GET"},
1634 1: {method
: "POST", serverStatus
: 302, wantMethod
: "GET"},
1635 2: {method
: "POST", serverStatus
: 303, wantMethod
: "GET"},
1636 3: {method
: "POST", serverStatus
: 307, wantMethod
: "POST"},
1637 4: {method
: "POST", serverStatus
: 308, wantMethod
: "POST"},
1639 5: {method
: "HEAD", serverStatus
: 301, wantMethod
: "HEAD"},
1640 6: {method
: "HEAD", serverStatus
: 302, wantMethod
: "HEAD"},
1641 7: {method
: "HEAD", serverStatus
: 303, wantMethod
: "HEAD"},
1642 8: {method
: "HEAD", serverStatus
: 307, wantMethod
: "HEAD"},
1643 9: {method
: "HEAD", serverStatus
: 308, wantMethod
: "HEAD"},
1645 10: {method
: "GET", serverStatus
: 301, wantMethod
: "GET"},
1646 11: {method
: "GET", serverStatus
: 302, wantMethod
: "GET"},
1647 12: {method
: "GET", serverStatus
: 303, wantMethod
: "GET"},
1648 13: {method
: "GET", serverStatus
: 307, wantMethod
: "GET"},
1649 14: {method
: "GET", serverStatus
: 308, wantMethod
: "GET"},
1651 15: {method
: "DELETE", serverStatus
: 301, wantMethod
: "GET"},
1652 16: {method
: "DELETE", serverStatus
: 302, wantMethod
: "GET"},
1653 17: {method
: "DELETE", serverStatus
: 303, wantMethod
: "GET"},
1654 18: {method
: "DELETE", serverStatus
: 307, wantMethod
: "DELETE"},
1655 19: {method
: "DELETE", serverStatus
: 308, wantMethod
: "DELETE"},
1657 20: {method
: "PUT", serverStatus
: 301, wantMethod
: "GET"},
1658 21: {method
: "PUT", serverStatus
: 302, wantMethod
: "GET"},
1659 22: {method
: "PUT", serverStatus
: 303, wantMethod
: "GET"},
1660 23: {method
: "PUT", serverStatus
: 307, wantMethod
: "PUT"},
1661 24: {method
: "PUT", serverStatus
: 308, wantMethod
: "PUT"},
1663 25: {method
: "MADEUPMETHOD", serverStatus
: 301, wantMethod
: "GET"},
1664 26: {method
: "MADEUPMETHOD", serverStatus
: 302, wantMethod
: "GET"},
1665 27: {method
: "MADEUPMETHOD", serverStatus
: 303, wantMethod
: "GET"},
1666 28: {method
: "MADEUPMETHOD", serverStatus
: 307, wantMethod
: "MADEUPMETHOD"},
1667 29: {method
: "MADEUPMETHOD", serverStatus
: 308, wantMethod
: "MADEUPMETHOD"},
1670 handlerc
:= make(chan HandlerFunc
, 1)
1672 ts
:= httptest
.NewServer(HandlerFunc(func(rw ResponseWriter
, req
*Request
) {
1679 for i
, tt
:= range tests
{
1680 handlerc
<- func(w ResponseWriter
, r
*Request
) {
1681 w
.Header().Set("Location", ts
.URL
)
1682 w
.WriteHeader(tt
.serverStatus
)
1685 req
, err
:= NewRequest(tt
.method
, ts
.URL
, nil)
1687 t
.Errorf("#%d: NewRequest: %v", i
, err
)
1691 c
.CheckRedirect
= func(req
*Request
, via
[]*Request
) error
{
1692 if got
, want
:= req
.Method
, tt
.wantMethod
; got
!= want
{
1693 return fmt
.Errorf("#%d: got next method %q; want %q", i
, got
, want
)
1695 handlerc
<- func(rw ResponseWriter
, req
*Request
) {
1696 // TODO: Check that the body is valid when we do 307 and 308 support
1701 res
, err
:= c
.Do(req
)
1703 t
.Errorf("#%d: Response: %v", i
, err
)
1711 // issue18239Body is an io.ReadCloser for TestTransportBodyReadError.
1712 // Its Read returns readErr and increments *readCalls atomically.
1713 // Its Close returns nil and increments *closeCalls atomically.
1714 type issue18239Body
struct {
1720 func (b issue18239Body
) Read([]byte) (int, error
) {
1721 atomic
.AddInt32(b
.readCalls
, 1)
1725 func (b issue18239Body
) Close() error
{
1726 atomic
.AddInt32(b
.closeCalls
, 1)
1730 // Issue 18239: make sure the Transport doesn't retry requests with bodies
1731 // if Request.GetBody is not defined.
1732 func TestTransportBodyReadError(t
*testing
.T
) {
1735 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
1736 if r
.URL
.Path
== "/ping" {
1739 buf
:= make([]byte, 1)
1740 n
, err
:= r
.Body
.Read(buf
)
1741 w
.Header().Set("X-Body-Read", fmt
.Sprintf("%v, %v", n
, err
))
1745 tr
:= c
.Transport
.(*Transport
)
1747 // Do one initial successful request to create an idle TCP connection
1748 // for the subsequent request to reuse. (The Transport only retries
1749 // requests on reused connections.)
1750 res
, err
:= c
.Get(ts
.URL
+ "/ping")
1756 var readCallsAtomic
int32
1757 var closeCallsAtomic
int32 // atomic
1758 someErr
:= errors
.New("some body read error")
1759 body
:= issue18239Body
{&readCallsAtomic
, &closeCallsAtomic
, someErr
}
1761 req
, err
:= NewRequest("POST", ts
.URL
, body
)
1766 _
, err
= tr
.RoundTrip(req
)
1768 t
.Errorf("Got error: %v; want Request.Body read error: %v", err
, someErr
)
1771 // And verify that our Body wasn't used multiple times, which
1772 // would indicate retries. (as it buggily was during part of
1773 // Go 1.8's dev cycle)
1774 readCalls
:= atomic
.LoadInt32(&readCallsAtomic
)
1775 closeCalls
:= atomic
.LoadInt32(&closeCallsAtomic
)
1777 t
.Errorf("read calls = %d; want 1", readCalls
)
1779 if closeCalls
!= 1 {
1780 t
.Errorf("close calls = %d; want 1", closeCalls
)