package server import ( "context" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/pem" "io" "math/big" "net" "net/http" "os" "path/filepath" "strings" "testing" "time" ) // TestHTTPSAndPlainOnOnePort serves a certificate file: the same port // answers HTTPS, and plain HTTP from loopback. func TestHTTPSAndPlainOnOnePort(t *testing.T) { dir := t.TempDir() key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) tmpl := &x509.Certificate{SerialNumber: big.NewInt(1), Subject: pkix.Name{CommonName: "dhcp.test"}, DNSNames: []string{"dhcp.test"}, NotBefore: time.Now().Add(-time.Hour), NotAfter: time.Now().Add(time.Hour)} der, _ := x509.CreateCertificate(rand.Reader, tmpl, tmpl, &key.PublicKey, key) kd, _ := x509.MarshalPKCS8PrivateKey(key) os.WriteFile(filepath.Join(dir, "c.pem"), pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: der}), 0o600) os.WriteFile(filepath.Join(dir, "k.pem"), pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: kd}), 0o600) ln, _ := net.Listen("tcp", "127.0.0.1:0") addr := ln.Addr().String() ln.Close() e := newEnv(t) e.srv.cfg.Listen, e.srv.cfg.TLSCertFile, e.srv.cfg.TLSKeyFile = []string{addr}, filepath.Join(dir, "c.pem"), filepath.Join(dir, "k.pem") ctx, cancel := context.WithCancel(context.Background()) defer cancel() ready := make(chan struct{}) go e.srv.Serve(ctx, func() { close(ready) }) <-ready pool := x509.NewCertPool() pool.AddCert(func() *x509.Certificate { c, _ := x509.ParseCertificate(der); return c }()) hc := &http.Client{Timeout: 5 * time.Second, Transport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: pool, ServerName: "dhcp.test"}}} for _, url := range []string{"https://" + addr + "/healthz", "http://" + addr + "/healthz"} { resp, err := hc.Get(url) if err != nil { t.Fatalf("%s: %v", url, err) } b, _ := io.ReadAll(resp.Body) resp.Body.Close() if resp.StatusCode != 200 || !strings.Contains(string(b), `"ok":true`) { t.Errorf("%s: %d %s", url, resp.StatusCode, b) } } }