| 1 |
747 |
jeremybenn |
// Copyright 2011 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.
|
| 4 |
|
|
|
| 5 |
|
|
// Implementation of Server
|
| 6 |
|
|
|
| 7 |
|
|
package httptest
|
| 8 |
|
|
|
| 9 |
|
|
import (
|
| 10 |
|
|
"crypto/tls"
|
| 11 |
|
|
"flag"
|
| 12 |
|
|
"fmt"
|
| 13 |
|
|
"net"
|
| 14 |
|
|
"net/http"
|
| 15 |
|
|
"os"
|
| 16 |
|
|
)
|
| 17 |
|
|
|
| 18 |
|
|
// A Server is an HTTP server listening on a system-chosen port on the
|
| 19 |
|
|
// local loopback interface, for use in end-to-end HTTP tests.
|
| 20 |
|
|
type Server struct {
|
| 21 |
|
|
URL string // base URL of form http://ipaddr:port with no trailing slash
|
| 22 |
|
|
Listener net.Listener
|
| 23 |
|
|
TLS *tls.Config // nil if not using using TLS
|
| 24 |
|
|
|
| 25 |
|
|
// Config may be changed after calling NewUnstartedServer and
|
| 26 |
|
|
// before Start or StartTLS.
|
| 27 |
|
|
Config *http.Server
|
| 28 |
|
|
}
|
| 29 |
|
|
|
| 30 |
|
|
// historyListener keeps track of all connections that it's ever
|
| 31 |
|
|
// accepted.
|
| 32 |
|
|
type historyListener struct {
|
| 33 |
|
|
net.Listener
|
| 34 |
|
|
history []net.Conn
|
| 35 |
|
|
}
|
| 36 |
|
|
|
| 37 |
|
|
func (hs *historyListener) Accept() (c net.Conn, err error) {
|
| 38 |
|
|
c, err = hs.Listener.Accept()
|
| 39 |
|
|
if err == nil {
|
| 40 |
|
|
hs.history = append(hs.history, c)
|
| 41 |
|
|
}
|
| 42 |
|
|
return
|
| 43 |
|
|
}
|
| 44 |
|
|
|
| 45 |
|
|
func newLocalListener() net.Listener {
|
| 46 |
|
|
if *serve != "" {
|
| 47 |
|
|
l, err := net.Listen("tcp", *serve)
|
| 48 |
|
|
if err != nil {
|
| 49 |
|
|
panic(fmt.Sprintf("httptest: failed to listen on %v: %v", *serve, err))
|
| 50 |
|
|
}
|
| 51 |
|
|
return l
|
| 52 |
|
|
}
|
| 53 |
|
|
l, err := net.Listen("tcp", "127.0.0.1:0")
|
| 54 |
|
|
if err != nil {
|
| 55 |
|
|
if l, err = net.Listen("tcp6", "[::1]:0"); err != nil {
|
| 56 |
|
|
panic(fmt.Sprintf("httptest: failed to listen on a port: %v", err))
|
| 57 |
|
|
}
|
| 58 |
|
|
}
|
| 59 |
|
|
return l
|
| 60 |
|
|
}
|
| 61 |
|
|
|
| 62 |
|
|
// When debugging a particular http server-based test,
|
| 63 |
|
|
// this flag lets you run
|
| 64 |
|
|
// gotest -run=BrokenTest -httptest.serve=127.0.0.1:8000
|
| 65 |
|
|
// to start the broken server so you can interact with it manually.
|
| 66 |
|
|
var serve = flag.String("httptest.serve", "", "if non-empty, httptest.NewServer serves on this address and blocks")
|
| 67 |
|
|
|
| 68 |
|
|
// NewServer starts and returns a new Server.
|
| 69 |
|
|
// The caller should call Close when finished, to shut it down.
|
| 70 |
|
|
func NewServer(handler http.Handler) *Server {
|
| 71 |
|
|
ts := NewUnstartedServer(handler)
|
| 72 |
|
|
ts.Start()
|
| 73 |
|
|
return ts
|
| 74 |
|
|
}
|
| 75 |
|
|
|
| 76 |
|
|
// NewUnstartedServer returns a new Server but doesn't start it.
|
| 77 |
|
|
//
|
| 78 |
|
|
// After changing its configuration, the caller should call Start or
|
| 79 |
|
|
// StartTLS.
|
| 80 |
|
|
//
|
| 81 |
|
|
// The caller should call Close when finished, to shut it down.
|
| 82 |
|
|
func NewUnstartedServer(handler http.Handler) *Server {
|
| 83 |
|
|
return &Server{
|
| 84 |
|
|
Listener: newLocalListener(),
|
| 85 |
|
|
Config: &http.Server{Handler: handler},
|
| 86 |
|
|
}
|
| 87 |
|
|
}
|
| 88 |
|
|
|
| 89 |
|
|
// Start starts a server from NewUnstartedServer.
|
| 90 |
|
|
func (s *Server) Start() {
|
| 91 |
|
|
if s.URL != "" {
|
| 92 |
|
|
panic("Server already started")
|
| 93 |
|
|
}
|
| 94 |
|
|
s.Listener = &historyListener{s.Listener, make([]net.Conn, 0)}
|
| 95 |
|
|
s.URL = "http://" + s.Listener.Addr().String()
|
| 96 |
|
|
go s.Config.Serve(s.Listener)
|
| 97 |
|
|
if *serve != "" {
|
| 98 |
|
|
fmt.Println(os.Stderr, "httptest: serving on", s.URL)
|
| 99 |
|
|
select {}
|
| 100 |
|
|
}
|
| 101 |
|
|
}
|
| 102 |
|
|
|
| 103 |
|
|
// StartTLS starts TLS on a server from NewUnstartedServer.
|
| 104 |
|
|
func (s *Server) StartTLS() {
|
| 105 |
|
|
if s.URL != "" {
|
| 106 |
|
|
panic("Server already started")
|
| 107 |
|
|
}
|
| 108 |
|
|
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
| 109 |
|
|
if err != nil {
|
| 110 |
|
|
panic(fmt.Sprintf("httptest: NewTLSServer: %v", err))
|
| 111 |
|
|
}
|
| 112 |
|
|
|
| 113 |
|
|
s.TLS = &tls.Config{
|
| 114 |
|
|
NextProtos: []string{"http/1.1"},
|
| 115 |
|
|
Certificates: []tls.Certificate{cert},
|
| 116 |
|
|
}
|
| 117 |
|
|
tlsListener := tls.NewListener(s.Listener, s.TLS)
|
| 118 |
|
|
|
| 119 |
|
|
s.Listener = &historyListener{tlsListener, make([]net.Conn, 0)}
|
| 120 |
|
|
s.URL = "https://" + s.Listener.Addr().String()
|
| 121 |
|
|
go s.Config.Serve(s.Listener)
|
| 122 |
|
|
}
|
| 123 |
|
|
|
| 124 |
|
|
// NewTLSServer starts and returns a new Server using TLS.
|
| 125 |
|
|
// The caller should call Close when finished, to shut it down.
|
| 126 |
|
|
func NewTLSServer(handler http.Handler) *Server {
|
| 127 |
|
|
ts := NewUnstartedServer(handler)
|
| 128 |
|
|
ts.StartTLS()
|
| 129 |
|
|
return ts
|
| 130 |
|
|
}
|
| 131 |
|
|
|
| 132 |
|
|
// Close shuts down the server.
|
| 133 |
|
|
func (s *Server) Close() {
|
| 134 |
|
|
s.Listener.Close()
|
| 135 |
|
|
}
|
| 136 |
|
|
|
| 137 |
|
|
// CloseClientConnections closes any currently open HTTP connections
|
| 138 |
|
|
// to the test Server.
|
| 139 |
|
|
func (s *Server) CloseClientConnections() {
|
| 140 |
|
|
hl, ok := s.Listener.(*historyListener)
|
| 141 |
|
|
if !ok {
|
| 142 |
|
|
return
|
| 143 |
|
|
}
|
| 144 |
|
|
for _, conn := range hl.history {
|
| 145 |
|
|
conn.Close()
|
| 146 |
|
|
}
|
| 147 |
|
|
}
|
| 148 |
|
|
|
| 149 |
|
|
// localhostCert is a PEM-encoded TLS cert with SAN DNS names
|
| 150 |
|
|
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
|
| 151 |
|
|
// of ASN.1 time).
|
| 152 |
|
|
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
| 153 |
|
|
MIIBOTCB5qADAgECAgEAMAsGCSqGSIb3DQEBBTAAMB4XDTcwMDEwMTAwMDAwMFoX
|
| 154 |
|
|
DTQ5MTIzMTIzNTk1OVowADBaMAsGCSqGSIb3DQEBAQNLADBIAkEAsuA5mAFMj6Q7
|
| 155 |
|
|
qoBzcvKzIq4kzuT5epSp2AkcQfyBHm7K13Ws7u+0b5Vb9gqTf5cAiIKcrtrXVqkL
|
| 156 |
|
|
8i1UQF6AzwIDAQABo08wTTAOBgNVHQ8BAf8EBAMCACQwDQYDVR0OBAYEBAECAwQw
|
| 157 |
|
|
DwYDVR0jBAgwBoAEAQIDBDAbBgNVHREEFDASggkxMjcuMC4wLjGCBVs6OjFdMAsG
|
| 158 |
|
|
CSqGSIb3DQEBBQNBAJH30zjLWRztrWpOCgJL8RQWLaKzhK79pVhAx6q/3NrF16C7
|
| 159 |
|
|
+l1BRZstTwIGdoGId8BRpErK1TXkniFb95ZMynM=
|
| 160 |
|
|
-----END CERTIFICATE-----
|
| 161 |
|
|
`)
|
| 162 |
|
|
|
| 163 |
|
|
// localhostKey is the private key for localhostCert.
|
| 164 |
|
|
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
| 165 |
|
|
MIIBPQIBAAJBALLgOZgBTI+kO6qAc3LysyKuJM7k+XqUqdgJHEH8gR5uytd1rO7v
|
| 166 |
|
|
tG+VW/YKk3+XAIiCnK7a11apC/ItVEBegM8CAwEAAQJBAI5sxq7naeR9ahyqRkJi
|
| 167 |
|
|
SIv2iMxLuPEHaezf5CYOPWjSjBPyVhyRevkhtqEjF/WkgL7C2nWpYHsUcBDBQVF0
|
| 168 |
|
|
3KECIQDtEGB2ulnkZAahl3WuJziXGLB+p8Wgx7wzSM6bHu1c6QIhAMEp++CaS+SJ
|
| 169 |
|
|
/TrU0zwY/fW4SvQeb49BPZUF3oqR8Xz3AiEA1rAJHBzBgdOQKdE3ksMUPcnvNJSN
|
| 170 |
|
|
poCcELmz2clVXtkCIQCLytuLV38XHToTipR4yMl6O+6arzAjZ56uq7m7ZRV0TwIh
|
| 171 |
|
|
AM65XAOw8Dsg9Kq78aYXiOEDc5DL0sbFUu/SlmRcCg93
|
| 172 |
|
|
-----END RSA PRIVATE KEY-----
|
| 173 |
|
|
`)
|