1 // Copyright 2010 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.
5 // End-to-end serving tests
25 type oneConnListener
struct {
29 func (l
*oneConnListener
) Accept() (c net
.Conn
, err os
.Error
) {
40 func (l
*oneConnListener
) Close() os
.Error
{
44 func (l
*oneConnListener
) Addr() net
.Addr
{
45 return dummyAddr("test-address")
48 func (a dummyAddr
) Network() string {
52 func (a dummyAddr
) String() string {
56 type testConn
struct {
61 func (c
*testConn
) Read(b
[]byte) (int, os
.Error
) {
62 return c
.readBuf
.Read(b
)
65 func (c
*testConn
) Write(b
[]byte) (int, os
.Error
) {
66 return c
.writeBuf
.Write(b
)
69 func (c
*testConn
) Close() os
.Error
{
73 func (c
*testConn
) LocalAddr() net
.Addr
{
74 return dummyAddr("local-addr")
77 func (c
*testConn
) RemoteAddr() net
.Addr
{
78 return dummyAddr("remote-addr")
81 func (c
*testConn
) SetTimeout(nsec
int64) os
.Error
{
85 func (c
*testConn
) SetReadTimeout(nsec
int64) os
.Error
{
89 func (c
*testConn
) SetWriteTimeout(nsec
int64) os
.Error
{
93 func TestConsumingBodyOnNextConn(t
*testing
.T
) {
95 for i
:= 0; i
< 2; i
++ {
96 conn
.readBuf
.Write([]byte(
97 "POST / HTTP/1.1\r\n" +
99 "Content-Length: 11\r\n" +
105 ch
:= make(chan *Request
)
106 servech
:= make(chan os
.Error
)
107 listener
:= &oneConnListener
{conn
}
108 handler
:= func(res ResponseWriter
, req
*Request
) {
110 t
.Logf("Got request #%d: %v", reqNum
, req
)
115 servech
<- Serve(listener
, HandlerFunc(handler
))
119 t
.Log("Waiting for first request.")
122 t
.Fatal("Got nil first request.")
124 if req
.Method
!= "POST" {
125 t
.Errorf("For request #1's method, got %q; expected %q",
129 t
.Log("Waiting for second request.")
132 t
.Fatal("Got nil first request.")
134 if req
.Method
!= "POST" {
135 t
.Errorf("For request #2's method, got %q; expected %q",
139 t
.Log("Waiting for EOF.")
140 if serveerr
:= <-servech
; serveerr
!= os
.EOF
{
141 t
.Errorf("Serve returned %q; expected EOF", serveerr
)
145 type stringHandler
string
147 func (s stringHandler
) ServeHTTP(w ResponseWriter
, r
*Request
) {
148 w
.Header().Set("Result", string(s
))
151 var handlers
= []struct {
156 {"/someDir/", "someDir"},
157 {"someHost.com/someDir/", "someHost.com/someDir"},
160 var vtests
= []struct {
164 {"http://localhost/someDir/apage", "someDir"},
165 {"http://localhost/otherDir/apage", "Default"},
166 {"http://someHost.com/someDir/apage", "someHost.com/someDir"},
167 {"http://otherHost.com/someDir/apage", "someDir"},
168 {"http://otherHost.com/aDir/apage", "Default"},
171 func TestHostHandlers(t
*testing
.T
) {
172 for _
, h
:= range handlers
{
173 Handle(h
.pattern
, stringHandler(h
.msg
))
175 ts
:= httptest
.NewServer(nil)
178 conn
, err
:= net
.Dial("tcp", ts
.Listener
.Addr().String())
183 cc
:= NewClientConn(conn
, nil)
184 for _
, vt
:= range vtests
{
187 if req
.URL
, err
= ParseURL(vt
.url
); err
!= nil {
188 t
.Errorf("cannot parse url: %v", err
)
191 if err
:= cc
.Write(&req
); err
!= nil {
192 t
.Errorf("writing request: %v", err
)
195 r
, err
:= cc
.Read(&req
)
197 t
.Errorf("reading response: %v", err
)
200 s
:= r
.Header
.Get("Result")
201 if s
!= vt
.expected
{
202 t
.Errorf("Get(%q) = %q, want %q", vt
.url
, s
, vt
.expected
)
207 // Tests for http://code.google.com/p/go/issues/detail?id=900
208 func TestMuxRedirectLeadingSlashes(t
*testing
.T
) {
209 paths
:= []string{"//foo.txt", "///foo.txt", "/../../foo.txt"}
210 for _
, path
:= range paths
{
211 req
, err
:= ReadRequest(bufio
.NewReader(bytes
.NewBufferString("GET " + path
+ " HTTP/1.1\r\nHost: test\r\n\r\n")))
216 resp
:= httptest
.NewRecorder()
218 mux
.ServeHTTP(resp
, req
)
220 if loc
, expected
:= resp
.Header().Get("Location"), "/foo.txt"; loc
!= expected
{
221 t
.Errorf("Expected Location header set to %q; got %q", expected
, loc
)
225 if code
, expected
:= resp
.Code
, StatusMovedPermanently
; code
!= expected
{
226 t
.Errorf("Expected response code of StatusMovedPermanently; got %d", code
)
232 func TestServerTimeouts(t
*testing
.T
) {
233 // TODO(bradfitz): convert this to use httptest.Server
234 l
, err
:= net
.ListenTCP("tcp", &net
.TCPAddr
{Port
: 0})
236 t
.Fatalf("listen error: %v", err
)
238 addr
, _
:= l
.Addr().(*net
.TCPAddr
)
241 handler
:= HandlerFunc(func(res ResponseWriter
, req
*Request
) {
243 fmt
.Fprintf(res
, "req=%d", reqNum
)
246 const second
= 1000000000 /* nanos */
247 server
:= &Server
{Handler
: handler
, ReadTimeout
: 0.25 * second
, WriteTimeout
: 0.25 * second
}
250 url
:= fmt
.Sprintf("http://localhost:%d/", addr
.Port
)
252 // Hit the HTTP server successfully.
253 tr
:= &Transport
{DisableKeepAlives
: true} // they interfere with this test
254 c
:= &Client
{Transport
: tr
}
255 r
, _
, err
:= c
.Get(url
)
257 t
.Fatalf("http Get #1: %v", err
)
259 got
, _
:= ioutil
.ReadAll(r
.Body
)
261 if string(got
) != expected
{
262 t
.Errorf("Unexpected response for request #1; got %q; expected %q",
263 string(got
), expected
)
266 // Slow client that should timeout.
267 t1
:= time
.Nanoseconds()
268 conn
, err
:= net
.Dial("tcp", fmt
.Sprintf("localhost:%d", addr
.Port
))
270 t
.Fatalf("Dial: %v", err
)
272 buf
:= make([]byte, 1)
273 n
, err
:= conn
.Read(buf
)
274 latency
:= time
.Nanoseconds() - t1
275 if n
!= 0 || err
!= os
.EOF
{
276 t
.Errorf("Read = %v, %v, wanted %v, %v", n
, err
, 0, os
.EOF
)
278 if latency
< second
*0.20 /* fudge from 0.25 above */ {
279 t
.Errorf("got EOF after %d ns, want >= %d", latency
, second
*0.20)
282 // Hit the HTTP server successfully again, verifying that the
283 // previous slow connection didn't run our handler. (that we
284 // get "req=2", not "req=3")
287 t
.Fatalf("http Get #2: %v", err
)
289 got
, _
= ioutil
.ReadAll(r
.Body
)
291 if string(got
) != expected
{
292 t
.Errorf("Get #2 got %q, want %q", string(got
), expected
)
298 // TestIdentityResponse verifies that a handler can unset
299 func TestIdentityResponse(t
*testing
.T
) {
300 handler
:= HandlerFunc(func(rw ResponseWriter
, req
*Request
) {
301 rw
.Header().Set("Content-Length", "3")
302 rw
.Header().Set("Transfer-Encoding", req
.FormValue("te"))
304 case req
.FormValue("overwrite") == "1":
305 _
, err
:= rw
.Write([]byte("foo TOO LONG"))
306 if err
!= ErrContentLength
{
307 t
.Errorf("expected ErrContentLength; got %v", err
)
309 case req
.FormValue("underwrite") == "1":
310 rw
.Header().Set("Content-Length", "500")
311 rw
.Write([]byte("too short"))
313 rw
.Write([]byte("foo"))
317 ts
:= httptest
.NewServer(handler
)
320 // Note: this relies on the assumption (which is true) that
321 // Get sends HTTP/1.1 or greater requests. Otherwise the
322 // server wouldn't have the choice to send back chunked
324 for _
, te
:= range []string{"", "identity"} {
325 url
:= ts
.URL
+ "/?te=" + te
326 res
, _
, err
:= Get(url
)
328 t
.Fatalf("error with Get of %s: %v", url
, err
)
330 if cl
, expected
:= res
.ContentLength
, int64(3); cl
!= expected
{
331 t
.Errorf("for %s expected res.ContentLength of %d; got %d", url
, expected
, cl
)
333 if cl
, expected
:= res
.Header
.Get("Content-Length"), "3"; cl
!= expected
{
334 t
.Errorf("for %s expected Content-Length header of %q; got %q", url
, expected
, cl
)
336 if tl
, expected
:= len(res
.TransferEncoding
), 0; tl
!= expected
{
337 t
.Errorf("for %s expected len(res.TransferEncoding) of %d; got %d (%v)",
338 url
, expected
, tl
, res
.TransferEncoding
)
343 // Verify that ErrContentLength is returned
344 url
:= ts
.URL
+ "/?overwrite=1"
345 _
, _
, err
:= Get(url
)
347 t
.Fatalf("error with Get of %s: %v", url
, err
)
349 // Verify that the connection is closed when the declared Content-Length
350 // is larger than what the handler wrote.
351 conn
, err
:= net
.Dial("tcp", ts
.Listener
.Addr().String())
353 t
.Fatalf("error dialing: %v", err
)
355 _
, err
= conn
.Write([]byte("GET /?underwrite=1 HTTP/1.1\r\nHost: foo\r\n\r\n"))
357 t
.Fatalf("error writing: %v", err
)
359 // The next ReadAll will hang for a failing test, so use a Timer instead
360 // to fail more traditionally
361 timer
:= time
.AfterFunc(2e9
, func() {
362 t
.Fatalf("Timeout expired in ReadAll.")
365 got
, _
:= ioutil
.ReadAll(conn
)
366 expectedSuffix
:= "\r\n\r\ntoo short"
367 if !strings
.HasSuffix(string(got
), expectedSuffix
) {
368 t
.Fatalf("Expected output to end with %q; got response body %q",
369 expectedSuffix
, string(got
))
373 // TestServeHTTP10Close verifies that HTTP/1.0 requests won't be kept alive.
374 func TestServeHTTP10Close(t
*testing
.T
) {
375 s
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
376 ServeFile(w
, r
, "testdata/file")
380 conn
, err
:= net
.Dial("tcp", s
.Listener
.Addr().String())
382 t
.Fatal("dial error:", err
)
386 _
, err
= fmt
.Fprint(conn
, "GET / HTTP/1.0\r\n\r\n")
388 t
.Fatal("print error:", err
)
391 r
:= bufio
.NewReader(conn
)
392 _
, err
= ReadResponse(r
, "GET")
394 t
.Fatal("ReadResponse error:", err
)
397 success
:= make(chan bool)
400 case <-time
.After(5e9
):
401 t
.Fatal("body not closed after 5s")
406 _
, err
= ioutil
.ReadAll(r
)
408 t
.Fatal("read error:", err
)
414 func TestSetsRemoteAddr(t
*testing
.T
) {
415 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
416 fmt
.Fprintf(w
, "%s", r
.RemoteAddr
)
420 res
, _
, err
:= Get(ts
.URL
)
422 t
.Fatalf("Get error: %v", err
)
424 body
, err
:= ioutil
.ReadAll(res
.Body
)
426 t
.Fatalf("ReadAll error: %v", err
)
429 if !strings
.HasPrefix(ip
, "127.0.0.1:") && !strings
.HasPrefix(ip
, "[::1]:") {
430 t
.Fatalf("Expected local addr; got %q", ip
)
434 func TestChunkedResponseHeaders(t
*testing
.T
) {
435 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
436 w
.Header().Set("Content-Length", "intentional gibberish") // we check that this is deleted
437 fmt
.Fprintf(w
, "I am a chunked response.")
441 res
, _
, err
:= Get(ts
.URL
)
443 t
.Fatalf("Get error: %v", err
)
445 if g
, e
:= res
.ContentLength
, int64(-1); g
!= e
{
446 t
.Errorf("expected ContentLength of %d; got %d", e
, g
)
448 if g
, e
:= res
.TransferEncoding
, []string{"chunked"}; !reflect
.DeepEqual(g
, e
) {
449 t
.Errorf("expected TransferEncoding of %v; got %v", e
, g
)
451 if _
, haveCL
:= res
.Header
["Content-Length"]; haveCL
{
452 t
.Errorf("Unexpected Content-Length")
456 // Test304Responses verifies that 304s don't declare that they're
457 // chunking in their response headers and aren't allowed to produce
459 func Test304Responses(t
*testing
.T
) {
460 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
461 w
.WriteHeader(StatusNotModified
)
462 _
, err
:= w
.Write([]byte("illegal body"))
463 if err
!= ErrBodyNotAllowed
{
464 t
.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err
)
468 res
, _
, err
:= Get(ts
.URL
)
472 if len(res
.TransferEncoding
) > 0 {
473 t
.Errorf("expected no TransferEncoding; got %v", res
.TransferEncoding
)
475 body
, err
:= ioutil
.ReadAll(res
.Body
)
480 t
.Errorf("got unexpected body %q", string(body
))
484 // TestHeadResponses verifies that responses to HEAD requests don't
485 // declare that they're chunking in their response headers and aren't
486 // allowed to produce output.
487 func TestHeadResponses(t
*testing
.T
) {
488 ts
:= httptest
.NewServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
489 _
, err
:= w
.Write([]byte("Ignored body"))
490 if err
!= ErrBodyNotAllowed
{
491 t
.Errorf("on Write, expected ErrBodyNotAllowed, got %v", err
)
495 res
, err
:= Head(ts
.URL
)
499 if len(res
.TransferEncoding
) > 0 {
500 t
.Errorf("expected no TransferEncoding; got %v", res
.TransferEncoding
)
502 body
, err
:= ioutil
.ReadAll(res
.Body
)
507 t
.Errorf("got unexpected body %q", string(body
))
511 func TestTLSServer(t
*testing
.T
) {
512 ts
:= httptest
.NewTLSServer(HandlerFunc(func(w ResponseWriter
, r
*Request
) {
513 fmt
.Fprintf(w
, "tls=%v", r
.TLS
!= nil)
516 if !strings
.HasPrefix(ts
.URL
, "https://") {
517 t
.Fatalf("expected test TLS server to start with https://, got %q", ts
.URL
)
519 res
, _
, err
:= Get(ts
.URL
)
524 t
.Fatalf("got nil Response")
527 t
.Fatalf("got nil Response.Body")
529 body
, err
:= ioutil
.ReadAll(res
.Body
)
533 if e
, g
:= "tls=true", string(body
); e
!= g
{
534 t
.Errorf("expected body %q; got %q", e
, g
)