2011-03-05 14:51:35 -07:00
|
|
|
// 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.
|
|
|
|
|
2011-03-05 16:43:26 -07:00
|
|
|
// Implementation of Server
|
2011-03-05 14:51:35 -07:00
|
|
|
|
|
|
|
package httptest
|
|
|
|
|
|
|
|
import (
|
2011-04-04 09:32:59 -06:00
|
|
|
"crypto/rand"
|
|
|
|
"crypto/tls"
|
2011-03-05 14:51:35 -07:00
|
|
|
"fmt"
|
|
|
|
"http"
|
|
|
|
"net"
|
2011-04-04 09:32:59 -06:00
|
|
|
"os"
|
|
|
|
"time"
|
2011-03-05 14:51:35 -07:00
|
|
|
)
|
|
|
|
|
|
|
|
// 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
|
2011-04-04 09:32:59 -06:00
|
|
|
TLS *tls.Config // nil if not using using TLS
|
2011-03-05 14:51:35 -07:00
|
|
|
}
|
|
|
|
|
2011-03-23 11:38:18 -06:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2011-04-04 09:32:59 -06:00
|
|
|
func newLocalListener() net.Listener {
|
2011-03-05 14:51:35 -07:00
|
|
|
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))
|
|
|
|
}
|
|
|
|
}
|
2011-04-04 09:32:59 -06:00
|
|
|
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()
|
2011-03-23 11:38:18 -06:00
|
|
|
ts.Listener = &historyListener{l, make([]net.Conn, 0)}
|
2011-03-05 14:51:35 -07:00
|
|
|
ts.URL = "http://" + l.Addr().String()
|
|
|
|
server := &http.Server{Handler: handler}
|
2011-03-23 11:38:18 -06:00
|
|
|
go server.Serve(ts.Listener)
|
2011-03-05 14:51:35 -07:00
|
|
|
return ts
|
|
|
|
}
|
|
|
|
|
2011-04-04 09:32:59 -06:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2011-03-05 16:43:26 -07:00
|
|
|
// Close shuts down the server.
|
2011-03-05 14:51:35 -07:00
|
|
|
func (s *Server) Close() {
|
|
|
|
s.Listener.Close()
|
|
|
|
}
|
2011-03-23 11:38:18 -06:00
|
|
|
|
|
|
|
// 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()
|
|
|
|
}
|
|
|
|
}
|
2011-04-04 09:32:59 -06:00
|
|
|
|
|
|
|
// 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-----
|
|
|
|
`)
|