summaryrefslogtreecommitdiff
path: root/src/pkg/http/httptest
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/http/httptest')
-rw-r--r--src/pkg/http/httptest/recorder.go44
-rw-r--r--src/pkg/http/httptest/server.go106
2 files changed, 112 insertions, 38 deletions
diff --git a/src/pkg/http/httptest/recorder.go b/src/pkg/http/httptest/recorder.go
index ec7bde8aa..0dd19a617 100644
--- a/src/pkg/http/httptest/recorder.go
+++ b/src/pkg/http/httptest/recorder.go
@@ -14,20 +14,17 @@ import (
// ResponseRecorder is an implementation of http.ResponseWriter that
// records its mutations for later inspection in tests.
type ResponseRecorder struct {
- Code int // the HTTP response code from WriteHeader
- Header http.Header // if non-nil, the headers to populate
- Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
- Flushed bool
-
- FakeRemoteAddr string // the fake RemoteAddr to return, or "" for DefaultRemoteAddr
- FakeUsingTLS bool // whether to return true from the UsingTLS method
+ Code int // the HTTP response code from WriteHeader
+ HeaderMap http.Header // the HTTP response headers
+ Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
+ Flushed bool
}
// NewRecorder returns an initialized ResponseRecorder.
func NewRecorder() *ResponseRecorder {
return &ResponseRecorder{
- Header: http.Header(make(map[string][]string)),
- Body: new(bytes.Buffer),
+ HeaderMap: make(http.Header),
+ Body: new(bytes.Buffer),
}
}
@@ -35,29 +32,9 @@ func NewRecorder() *ResponseRecorder {
// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
const DefaultRemoteAddr = "1.2.3.4"
-// RemoteAddr returns the value of rw.FakeRemoteAddr, if set, else
-// returns DefaultRemoteAddr.
-func (rw *ResponseRecorder) RemoteAddr() string {
- if rw.FakeRemoteAddr != "" {
- return rw.FakeRemoteAddr
- }
- return DefaultRemoteAddr
-}
-
-// UsingTLS returns the fake value in rw.FakeUsingTLS
-func (rw *ResponseRecorder) UsingTLS() bool {
- return rw.FakeUsingTLS
-}
-
-// SetHeader populates rw.Header, if non-nil.
-func (rw *ResponseRecorder) SetHeader(k, v string) {
- if rw.Header != nil {
- if v == "" {
- rw.Header.Del(k)
- } else {
- rw.Header.Set(k, v)
- }
- }
+// Header returns the response headers.
+func (rw *ResponseRecorder) Header() http.Header {
+ return rw.HeaderMap
}
// Write always succeeds and writes to rw.Body, if not nil.
@@ -65,6 +42,9 @@ func (rw *ResponseRecorder) Write(buf []byte) (int, os.Error) {
if rw.Body != nil {
rw.Body.Write(buf)
}
+ if rw.Code == 0 {
+ rw.Code = http.StatusOK
+ }
return len(buf), nil
}
diff --git a/src/pkg/http/httptest/server.go b/src/pkg/http/httptest/server.go
index 86c9eb435..8e385d045 100644
--- a/src/pkg/http/httptest/server.go
+++ b/src/pkg/http/httptest/server.go
@@ -7,9 +7,13 @@
package httptest
import (
+ "crypto/rand"
+ "crypto/tls"
"fmt"
"http"
"net"
+ "os"
+ "time"
)
// A Server is an HTTP server listening on a system-chosen port on the
@@ -17,22 +21,69 @@ import (
type Server struct {
URL string // base URL of form http://ipaddr:port with no trailing slash
Listener net.Listener
+ TLS *tls.Config // nil if not using using TLS
}
-// NewServer starts and returns a new Server.
-// The caller should call Close when finished, to shut it down.
-func NewServer(handler http.Handler) *Server {
- ts := new(Server)
+// historyListener keeps track of all connections that it's ever
+// accepted.
+type historyListener struct {
+ net.Listener
+ history []net.Conn
+}
+
+func (hs *historyListener) Accept() (c net.Conn, err os.Error) {
+ c, err = hs.Listener.Accept()
+ if err == nil {
+ hs.history = append(hs.history, c)
+ }
+ return
+}
+
+func newLocalListener() net.Listener {
l, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err))
}
}
- ts.Listener = l
+ return l
+}
+
+// NewServer starts and returns a new Server.
+// The caller should call Close when finished, to shut it down.
+func NewServer(handler http.Handler) *Server {
+ ts := new(Server)
+ l := newLocalListener()
+ ts.Listener = &historyListener{l, make([]net.Conn, 0)}
ts.URL = "http://" + l.Addr().String()
server := &http.Server{Handler: handler}
- go server.Serve(l)
+ go server.Serve(ts.Listener)
+ return ts
+}
+
+// NewTLSServer starts and returns a new Server using TLS.
+// The caller should call Close when finished, to shut it down.
+func NewTLSServer(handler http.Handler) *Server {
+ l := newLocalListener()
+ ts := new(Server)
+
+ cert, err := tls.X509KeyPair(localhostCert, localhostKey)
+ if err != nil {
+ panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
+ }
+
+ ts.TLS = &tls.Config{
+ Rand: rand.Reader,
+ Time: time.Seconds,
+ NextProtos: []string{"http/1.1"},
+ Certificates: []tls.Certificate{cert},
+ }
+ tlsListener := tls.NewListener(l, ts.TLS)
+
+ ts.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
+ ts.URL = "https://" + l.Addr().String()
+ server := &http.Server{Handler: handler}
+ go server.Serve(ts.Listener)
return ts
}
@@ -40,3 +91,46 @@ func NewServer(handler http.Handler) *Server {
func (s *Server) Close() {
s.Listener.Close()
}
+
+// CloseClientConnections closes any currently open HTTP connections
+// to the test Server.
+func (s *Server) CloseClientConnections() {
+ hl, ok := s.Listener.(*historyListener)
+ if !ok {
+ return
+ }
+ for _, conn := range hl.history {
+ conn.Close()
+ }
+}
+
+// localhostCert is a PEM-encoded TLS cert with SAN DNS names
+// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
+// of ASN.1 time).
+var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
+MIIBwTCCASugAwIBAgIBADALBgkqhkiG9w0BAQUwADAeFw0xMTAzMzEyMDI1MDda
+Fw00OTEyMzEyMzU5NTlaMAAwggCdMAsGCSqGSIb3DQEBAQOCAIwAMIIAhwKCAIB6
+oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZLKq2sM3gRaimsktIw
+nNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0SjdZ7vTPnFDPNsHGe
+KBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBA6NPME0wDgYDVR0PAQH/
+BAQDAgCgMA0GA1UdDgQGBAQBAgMEMA8GA1UdIwQIMAaABAECAwQwGwYDVR0RBBQw
+EoIJMTI3LjAuMC4xggVbOjoxXTALBgkqhkiG9w0BAQUDggCBAHC3gbdvc44vs+wD
+g2kONiENnx8WKc0UTGg/TOXS3gaRb+CUIQtHWja65l8rAfclEovjHgZ7gx8brO0W
+JuC6p3MUAKsgOssIrrRIx2rpnfcmFVMzguCmrMNVmKUAalw18Yp0F72xYAIitVQl
+kJrLdIhBajcJRYu/YGltHQRaXuVt
+-----END CERTIFICATE-----
+`)
+
+// localhostKey is the private key for localhostCert.
+var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
+MIIBkgIBAQKCAIB6oy4iT42G6qk+GGn5VL5JlnJT6ZG5cqaMNFaNGlIxNb6CPUZL
+Kq2sM3gRaimsktIwnNAcNwQGHpe1tZo+J/Pl04JTt71Y/TTAxy7OX27aZf1Rpt0S
+jdZ7vTPnFDPNsHGeKBKvPt55l2+YKjkZmV7eRevsVbpkNvNGB+T5d4Ge/wIBAwKC
+AIBRwh7Bil5Z8cYpZZv7jdQxDvbim7Z7ocRdeDmzZuF2I9RW04QyHHPIIlALnBvI
+YeF1veASz1gEFGUjzmbUGqKYSbCoTzXoev+F4bmbRxcX9sOmtslqvhMSHRSzA5NH
+aDVI3Hn4wvBVD8gePu8ACWqvPGbCiql11OKCMfjlPn2uuwJAx/24/F5DjXZ6hQQ7
+HxScOxKrpx5WnA9r1wZTltOTZkhRRzuLc21WJeE3M15QUdWi3zZxCKRFoth65HEs
+jy9YHQJAnPueRI44tz79b5QqVbeaOMUr7ZCb1Kp0uo6G+ANPLdlfliAupwij2eIz
+mHRJOWk0jBtXfRft1McH2H51CpXAyw==
+-----END RSA PRIVATE KEY-----
+`)