145 lines
4.0 KiB
Go
145 lines
4.0 KiB
Go
// Command testserver implements a test case.
|
|
package main
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"encoding/json"
|
|
"flag"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/daaku/go.grace/gracehttp"
|
|
)
|
|
|
|
type response struct {
|
|
Sleep time.Duration
|
|
Pid int
|
|
Error string `json:,omitempty`
|
|
}
|
|
|
|
func wait(wg *sync.WaitGroup, url string) {
|
|
defer wg.Done()
|
|
for {
|
|
_, err := http.Get(url)
|
|
if err == nil {
|
|
return
|
|
} else {
|
|
e2 := json.NewEncoder(os.Stderr).Encode(&response{
|
|
Error: err.Error(),
|
|
Pid: os.Getpid(),
|
|
})
|
|
if e2 != nil {
|
|
log.Fatalf("Error writing error json: %s", e2)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func httpsServer(addr string) *http.Server {
|
|
cert, err := tls.X509KeyPair(localhostCert, localhostKey)
|
|
if err != nil {
|
|
log.Fatal("error loading cert: %v", err)
|
|
}
|
|
return &http.Server{
|
|
Addr: addr,
|
|
Handler: newHandler(),
|
|
TLSConfig: &tls.Config{
|
|
NextProtos: []string{"http/1.1"},
|
|
Certificates: []tls.Certificate{cert},
|
|
},
|
|
}
|
|
}
|
|
|
|
func main() {
|
|
var httpAddr, httpsAddr string
|
|
flag.StringVar(&httpAddr, "http", ":48560", "http address to bind to")
|
|
flag.StringVar(&httpsAddr, "https", ":48561", "https address to bind to")
|
|
flag.Parse()
|
|
|
|
// we have self signed certs
|
|
http.DefaultTransport = &http.Transport{
|
|
DisableKeepAlives: true,
|
|
TLSClientConfig: &tls.Config{
|
|
InsecureSkipVerify: true,
|
|
},
|
|
}
|
|
|
|
err := flag.Set("gracehttp.log", "false")
|
|
if err != nil {
|
|
log.Fatalf("Error setting gracehttp.log: %s", err)
|
|
}
|
|
|
|
// print json to stderr once we can successfully connect to all three
|
|
// addresses. the ensures we only print the line once we're ready to serve.
|
|
go func() {
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
go wait(&wg, fmt.Sprintf("http://%s/sleep/?duration=0", httpAddr))
|
|
go wait(&wg, fmt.Sprintf("https://%s/sleep/?duration=0", httpsAddr))
|
|
wg.Wait()
|
|
|
|
err = json.NewEncoder(os.Stderr).Encode(&response{Pid: os.Getpid()})
|
|
if err != nil {
|
|
log.Fatalf("Error writing startup json: %s", err)
|
|
}
|
|
}()
|
|
|
|
err = gracehttp.Serve(
|
|
&http.Server{Addr: httpAddr, Handler: newHandler()},
|
|
httpsServer(httpsAddr),
|
|
)
|
|
if err != nil {
|
|
log.Fatalf("Error in gracehttp.Serve: %s", err)
|
|
}
|
|
}
|
|
|
|
func newHandler() http.Handler {
|
|
mux := http.NewServeMux()
|
|
mux.HandleFunc("/sleep/", func(w http.ResponseWriter, r *http.Request) {
|
|
duration, err := time.ParseDuration(r.FormValue("duration"))
|
|
if err != nil {
|
|
http.Error(w, err.Error(), 400)
|
|
}
|
|
time.Sleep(duration)
|
|
err = json.NewEncoder(w).Encode(&response{
|
|
Sleep: duration,
|
|
Pid: os.Getpid(),
|
|
})
|
|
if err != nil {
|
|
log.Fatalf("Error encoding json: %s", err)
|
|
}
|
|
})
|
|
return mux
|
|
}
|
|
|
|
// localhostCert is a PEM-encoded TLS cert with SAN IPs
|
|
// "127.0.0.1" and "[::1]", expiring at the last second of 2049 (the end
|
|
// of ASN.1 time).
|
|
// generated from src/pkg/crypto/tls:
|
|
// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
|
var localhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
|
MIIBdzCCASOgAwIBAgIBADALBgkqhkiG9w0BAQUwEjEQMA4GA1UEChMHQWNtZSBD
|
|
bzAeFw03MDAxMDEwMDAwMDBaFw00OTEyMzEyMzU5NTlaMBIxEDAOBgNVBAoTB0Fj
|
|
bWUgQ28wWjALBgkqhkiG9w0BAQEDSwAwSAJBALyCfqwwip8BvTKgVKGdmjZTU8DD
|
|
ndR+WALmFPIRqn89bOU3s30olKiqYEju/SFoEvMyFRT/TWEhXHDaufThqaMCAwEA
|
|
AaNoMGYwDgYDVR0PAQH/BAQDAgCkMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1Ud
|
|
EwEB/wQFMAMBAf8wLgYDVR0RBCcwJYILZXhhbXBsZS5jb22HBH8AAAGHEAAAAAAA
|
|
AAAAAAAAAAAAAAEwCwYJKoZIhvcNAQEFA0EAr/09uy108p51rheIOSnz4zgduyTl
|
|
M+4AmRo8/U1twEZLgfAGG/GZjREv2y4mCEUIM3HebCAqlA5jpRg76Rf8jw==
|
|
-----END CERTIFICATE-----`)
|
|
|
|
// localhostKey is the private key for localhostCert.
|
|
var localhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
|
MIIBOQIBAAJBALyCfqwwip8BvTKgVKGdmjZTU8DDndR+WALmFPIRqn89bOU3s30o
|
|
lKiqYEju/SFoEvMyFRT/TWEhXHDaufThqaMCAwEAAQJAPXuWUxTV8XyAt8VhNQER
|
|
LgzJcUKb9JVsoS1nwXgPksXnPDKnL9ax8VERrdNr+nZbj2Q9cDSXBUovfdtehcdP
|
|
qQIhAO48ZsPylbTrmtjDEKiHT2Ik04rLotZYS2U873J6I7WlAiEAypDjYxXyafv/
|
|
Yo1pm9onwcetQKMW8CS3AjuV9Axzj6cCIEx2Il19fEMG4zny0WPlmbrcKvD/DpJQ
|
|
4FHrzsYlIVTpAiAas7S1uAvneqd0l02HlN9OxQKKlbUNXNme+rnOnOGS2wIgS0jW
|
|
zl1jvrOSJeP1PpAHohWz6LOhEr8uvltWkN6x3vE=
|
|
-----END RSA PRIVATE KEY-----`)
|