| // Copyright 2010 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| // End-to-end serving tests |
| |
| package http |
| |
| import ( |
| "bufio" |
| "bytes" |
| "io" |
| "os" |
| "net" |
| "testing" |
| ) |
| |
| type dummyAddr string |
| type oneConnListener struct { |
| conn net.Conn |
| } |
| |
| func (l *oneConnListener) Accept() (c net.Conn, err os.Error) { |
| c = l.conn |
| if c == nil { |
| err = os.EOF |
| return |
| } |
| err = nil |
| l.conn = nil |
| return |
| } |
| |
| func (l *oneConnListener) Close() os.Error { |
| return nil |
| } |
| |
| func (l *oneConnListener) Addr() net.Addr { |
| return dummyAddr("test-address") |
| } |
| |
| func (a dummyAddr) Network() string { |
| return string(a) |
| } |
| |
| func (a dummyAddr) String() string { |
| return string(a) |
| } |
| |
| type testConn struct { |
| readBuf bytes.Buffer |
| writeBuf bytes.Buffer |
| } |
| |
| func (c *testConn) Read(b []byte) (int, os.Error) { |
| return c.readBuf.Read(b) |
| } |
| |
| func (c *testConn) Write(b []byte) (int, os.Error) { |
| return c.writeBuf.Write(b) |
| } |
| |
| func (c *testConn) Close() os.Error { |
| return nil |
| } |
| |
| func (c *testConn) LocalAddr() net.Addr { |
| return dummyAddr("local-addr") |
| } |
| |
| func (c *testConn) RemoteAddr() net.Addr { |
| return dummyAddr("remote-addr") |
| } |
| |
| func (c *testConn) SetTimeout(nsec int64) os.Error { |
| return nil |
| } |
| |
| func (c *testConn) SetReadTimeout(nsec int64) os.Error { |
| return nil |
| } |
| |
| func (c *testConn) SetWriteTimeout(nsec int64) os.Error { |
| return nil |
| } |
| |
| func TestConsumingBodyOnNextConn(t *testing.T) { |
| conn := new(testConn) |
| for i := 0; i < 2; i++ { |
| conn.readBuf.Write([]byte( |
| "POST / HTTP/1.1\r\n" + |
| "Host: test\r\n" + |
| "Content-Length: 11\r\n" + |
| "\r\n" + |
| "foo=1&bar=1")) |
| } |
| |
| reqNum := 0 |
| ch := make(chan *Request) |
| servech := make(chan os.Error) |
| listener := &oneConnListener{conn} |
| handler := func(res ResponseWriter, req *Request) { |
| reqNum++ |
| t.Logf("Got request #%d: %v", reqNum, req) |
| ch <- req |
| } |
| |
| go func() { |
| servech <- Serve(listener, HandlerFunc(handler)) |
| }() |
| |
| var req *Request |
| t.Log("Waiting for first request.") |
| req = <-ch |
| if req == nil { |
| t.Fatal("Got nil first request.") |
| } |
| if req.Method != "POST" { |
| t.Errorf("For request #1's method, got %q; expected %q", |
| req.Method, "POST") |
| } |
| |
| t.Log("Waiting for second request.") |
| req = <-ch |
| if req == nil { |
| t.Fatal("Got nil first request.") |
| } |
| if req.Method != "POST" { |
| t.Errorf("For request #2's method, got %q; expected %q", |
| req.Method, "POST") |
| } |
| |
| t.Log("Waiting for EOF.") |
| if serveerr := <-servech; serveerr != os.EOF { |
| t.Errorf("Serve returned %q; expected EOF", serveerr) |
| } |
| } |
| |
| type responseWriterMethodCall struct { |
| method string |
| headerKey, headerValue string // if method == "SetHeader" |
| bytesWritten []byte // if method == "Write" |
| responseCode int // if method == "WriteHeader" |
| } |
| |
| type recordingResponseWriter struct { |
| log []*responseWriterMethodCall |
| } |
| |
| func (rw *recordingResponseWriter) RemoteAddr() string { |
| return "1.2.3.4" |
| } |
| |
| func (rw *recordingResponseWriter) UsingTLS() bool { |
| return false |
| } |
| |
| func (rw *recordingResponseWriter) SetHeader(k, v string) { |
| rw.log = append(rw.log, &responseWriterMethodCall{method: "SetHeader", headerKey: k, headerValue: v}) |
| } |
| |
| func (rw *recordingResponseWriter) Write(buf []byte) (int, os.Error) { |
| rw.log = append(rw.log, &responseWriterMethodCall{method: "Write", bytesWritten: buf}) |
| return len(buf), nil |
| } |
| |
| func (rw *recordingResponseWriter) WriteHeader(code int) { |
| rw.log = append(rw.log, &responseWriterMethodCall{method: "WriteHeader", responseCode: code}) |
| } |
| |
| func (rw *recordingResponseWriter) Flush() { |
| rw.log = append(rw.log, &responseWriterMethodCall{method: "Flush"}) |
| } |
| |
| func (rw *recordingResponseWriter) Hijack() (io.ReadWriteCloser, *bufio.ReadWriter, os.Error) { |
| panic("Not supported") |
| } |
| |
| // Tests for http://code.google.com/p/go/issues/detail?id=900 |
| func TestMuxRedirectLeadingSlashes(t *testing.T) { |
| paths := []string{"//foo.txt", "///foo.txt", "/../../foo.txt"} |
| for _, path := range paths { |
| req, err := ReadRequest(bufio.NewReader(bytes.NewBufferString("GET " + path + " HTTP/1.1\r\nHost: test\r\n\r\n"))) |
| if err != nil { |
| t.Errorf("%s", err) |
| } |
| mux := NewServeMux() |
| resp := new(recordingResponseWriter) |
| resp.log = make([]*responseWriterMethodCall, 0) |
| |
| mux.ServeHTTP(resp, req) |
| |
| dumpLog := func() { |
| t.Logf("For path %q:", path) |
| for _, call := range resp.log { |
| t.Logf("Got call: %s, header=%s, value=%s, buf=%q, code=%d", call.method, |
| call.headerKey, call.headerValue, call.bytesWritten, call.responseCode) |
| } |
| } |
| |
| if len(resp.log) != 2 { |
| dumpLog() |
| t.Errorf("expected 2 calls to response writer; got %d", len(resp.log)) |
| return |
| } |
| |
| if resp.log[0].method != "SetHeader" || |
| resp.log[0].headerKey != "Location" || resp.log[0].headerValue != "/foo.txt" { |
| dumpLog() |
| t.Errorf("Expected SetHeader of Location to /foo.txt") |
| return |
| } |
| |
| if resp.log[1].method != "WriteHeader" || resp.log[1].responseCode != StatusMovedPermanently { |
| dumpLog() |
| t.Errorf("Expected WriteHeader of StatusMovedPermanently") |
| return |
| } |
| } |
| } |