Update to current Go library.
[official-gcc.git] / libgo / go / http / serve_test.go
blobb0e26e533596b423d0f7ffb61fa2ef6970c62967
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
7 package http_test
9 import (
10 "bufio"
11 "bytes"
12 "fmt"
13 . "http"
14 "http/httptest"
15 "io/ioutil"
16 "os"
17 "net"
18 "reflect"
19 "strings"
20 "testing"
21 "time"
24 type dummyAddr string
25 type oneConnListener struct {
26 conn net.Conn
29 func (l *oneConnListener) Accept() (c net.Conn, err os.Error) {
30 c = l.conn
31 if c == nil {
32 err = os.EOF
33 return
35 err = nil
36 l.conn = nil
37 return
40 func (l *oneConnListener) Close() os.Error {
41 return nil
44 func (l *oneConnListener) Addr() net.Addr {
45 return dummyAddr("test-address")
48 func (a dummyAddr) Network() string {
49 return string(a)
52 func (a dummyAddr) String() string {
53 return string(a)
56 type testConn struct {
57 readBuf bytes.Buffer
58 writeBuf bytes.Buffer
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 {
70 return nil
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 {
82 return nil
85 func (c *testConn) SetReadTimeout(nsec int64) os.Error {
86 return nil
89 func (c *testConn) SetWriteTimeout(nsec int64) os.Error {
90 return nil
93 func TestConsumingBodyOnNextConn(t *testing.T) {
94 conn := new(testConn)
95 for i := 0; i < 2; i++ {
96 conn.readBuf.Write([]byte(
97 "POST / HTTP/1.1\r\n" +
98 "Host: test\r\n" +
99 "Content-Length: 11\r\n" +
100 "\r\n" +
101 "foo=1&bar=1"))
104 reqNum := 0
105 ch := make(chan *Request)
106 servech := make(chan os.Error)
107 listener := &oneConnListener{conn}
108 handler := func(res ResponseWriter, req *Request) {
109 reqNum++
110 t.Logf("Got request #%d: %v", reqNum, req)
111 ch <- req
114 go func() {
115 servech <- Serve(listener, HandlerFunc(handler))
118 var req *Request
119 t.Log("Waiting for first request.")
120 req = <-ch
121 if req == nil {
122 t.Fatal("Got nil first request.")
124 if req.Method != "POST" {
125 t.Errorf("For request #1's method, got %q; expected %q",
126 req.Method, "POST")
129 t.Log("Waiting for second request.")
130 req = <-ch
131 if req == nil {
132 t.Fatal("Got nil first request.")
134 if req.Method != "POST" {
135 t.Errorf("For request #2's method, got %q; expected %q",
136 req.Method, "POST")
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 {
152 pattern string
153 msg string
155 {"/", "Default"},
156 {"/someDir/", "someDir"},
157 {"someHost.com/someDir/", "someHost.com/someDir"},
160 var vtests = []struct {
161 url string
162 expected string
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)
176 defer ts.Close()
178 conn, err := net.Dial("tcp", ts.Listener.Addr().String())
179 if err != nil {
180 t.Fatal(err)
182 defer conn.Close()
183 cc := NewClientConn(conn, nil)
184 for _, vt := range vtests {
185 var r *Response
186 var req Request
187 if req.URL, err = ParseURL(vt.url); err != nil {
188 t.Errorf("cannot parse url: %v", err)
189 continue
191 if err := cc.Write(&req); err != nil {
192 t.Errorf("writing request: %v", err)
193 continue
195 r, err := cc.Read(&req)
196 if err != nil {
197 t.Errorf("reading response: %v", err)
198 continue
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")))
212 if err != nil {
213 t.Errorf("%s", err)
215 mux := NewServeMux()
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)
222 return
225 if code, expected := resp.Code, StatusMovedPermanently; code != expected {
226 t.Errorf("Expected response code of StatusMovedPermanently; got %d", code)
227 return
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})
235 if err != nil {
236 t.Fatalf("listen error: %v", err)
238 addr, _ := l.Addr().(*net.TCPAddr)
240 reqNum := 0
241 handler := HandlerFunc(func(res ResponseWriter, req *Request) {
242 reqNum++
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}
248 go server.Serve(l)
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)
256 if err != nil {
257 t.Fatalf("http Get #1: %v", err)
259 got, _ := ioutil.ReadAll(r.Body)
260 expected := "req=1"
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))
269 if err != nil {
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")
285 r, _, err = Get(url)
286 if err != nil {
287 t.Fatalf("http Get #2: %v", err)
289 got, _ = ioutil.ReadAll(r.Body)
290 expected = "req=2"
291 if string(got) != expected {
292 t.Errorf("Get #2 got %q, want %q", string(got), expected)
295 l.Close()
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"))
303 switch {
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"))
312 default:
313 rw.Write([]byte("foo"))
317 ts := httptest.NewServer(handler)
318 defer ts.Close()
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
323 // responses.
324 for _, te := range []string{"", "identity"} {
325 url := ts.URL + "/?te=" + te
326 res, _, err := Get(url)
327 if err != nil {
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)
340 res.Body.Close()
343 // Verify that ErrContentLength is returned
344 url := ts.URL + "/?overwrite=1"
345 _, _, err := Get(url)
346 if err != nil {
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())
352 if err != nil {
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"))
356 if err != nil {
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.")
364 defer timer.Stop()
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")
378 defer s.Close()
380 conn, err := net.Dial("tcp", s.Listener.Addr().String())
381 if err != nil {
382 t.Fatal("dial error:", err)
384 defer conn.Close()
386 _, err = fmt.Fprint(conn, "GET / HTTP/1.0\r\n\r\n")
387 if err != nil {
388 t.Fatal("print error:", err)
391 r := bufio.NewReader(conn)
392 _, err = ReadResponse(r, "GET")
393 if err != nil {
394 t.Fatal("ReadResponse error:", err)
397 success := make(chan bool)
398 go func() {
399 select {
400 case <-time.After(5e9):
401 t.Fatal("body not closed after 5s")
402 case <-success:
406 _, err = ioutil.ReadAll(r)
407 if err != nil {
408 t.Fatal("read error:", err)
411 success <- true
414 func TestSetsRemoteAddr(t *testing.T) {
415 ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
416 fmt.Fprintf(w, "%s", r.RemoteAddr)
418 defer ts.Close()
420 res, _, err := Get(ts.URL)
421 if err != nil {
422 t.Fatalf("Get error: %v", err)
424 body, err := ioutil.ReadAll(res.Body)
425 if err != nil {
426 t.Fatalf("ReadAll error: %v", err)
428 ip := string(body)
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.")
439 defer ts.Close()
441 res, _, err := Get(ts.URL)
442 if err != nil {
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
458 // output.
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)
467 defer ts.Close()
468 res, _, err := Get(ts.URL)
469 if err != nil {
470 t.Error(err)
472 if len(res.TransferEncoding) > 0 {
473 t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
475 body, err := ioutil.ReadAll(res.Body)
476 if err != nil {
477 t.Error(err)
479 if len(body) > 0 {
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)
494 defer ts.Close()
495 res, err := Head(ts.URL)
496 if err != nil {
497 t.Error(err)
499 if len(res.TransferEncoding) > 0 {
500 t.Errorf("expected no TransferEncoding; got %v", res.TransferEncoding)
502 body, err := ioutil.ReadAll(res.Body)
503 if err != nil {
504 t.Error(err)
506 if len(body) > 0 {
507 t.Errorf("got unexpected body %q", string(body))