// Copyright 2011 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. // Implementation of Server 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 // local loopback interface, for use in end-to-end HTTP tests. 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 } // 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)) } } 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(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 } // Close shuts down the 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----- `)