Skip to content

Instantly share code, notes, and snippets.

@rthellend
Created January 5, 2025 00:33
Show Gist options
  • Save rthellend/e77264034eb761ccf32abd274792775a to your computer and use it in GitHub Desktop.
Save rthellend/e77264034eb761ccf32abd274792775a to your computer and use it in GitHub Desktop.
go issue 71128
/*
Use chrome to open https://hostname:8888/
$ go run .
2025/01/04 16:19:27 HTTP/2.0 GET /
2025/01/04 16:19:27 HTTP/2.0 CONNECT /websocket
2025/01/04 16:19:27 ERR websocket: the client is not using the websocket protocol: 'upgrade' token not found in 'Connection' header
2025/01/04 16:19:27 HTTP/2.0 GET /favicon.ico
$ GODEBUG=http2xconnect=0 go run .
2025/01/04 16:22:24 HTTP/2.0 GET /
2025/01/04 16:22:24 HTTP/1.1 GET /websocket
2025/01/04 16:22:24 HTTP/2.0 GET /favicon.ico
*/
package main
import (
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/tls"
"crypto/x509"
"crypto/x509/pkix"
"fmt"
"log"
"net/http"
"time"
"github.com/gorilla/websocket"
)
func main() {
upgrader := &websocket.Upgrader{
ReadBufferSize: 2048,
WriteBufferSize: 2048,
}
mux := http.NewServeMux()
mux.HandleFunc("/websocket", func(w http.ResponseWriter, req *http.Request) {
log.Printf("%s %s %s", req.Proto, req.Method, req.RequestURI)
conn, err := upgrader.Upgrade(w, req, nil)
if err != nil {
log.Printf("ERR %v", err)
return
}
defer conn.Close()
conn.WriteMessage(websocket.BinaryMessage, []byte("Hello!"))
})
mux.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
log.Printf("%s %s %s", req.Proto, req.Method, req.RequestURI)
w.Header().Set("content-type", "text/html")
w.Write([]byte(`
<html>
<body>
<div id="message"></div>
<script>
let ws = new WebSocket('/websocket');
ws.onmessage = m => m.data.text().then(t => document.getElementById('message').textContent = t);
ws.onerror = () => document.getElementById('message').textContent = 'WebSocket error';
</script>
</body>
</html>
`))
})
cert, err := newCert("foo")
if err != nil {
log.Fatalf("newCert: %v", err)
}
l, err := tls.Listen("tcp", ":8888", &tls.Config{
NextProtos: []string{"h2", "http/1.1"},
Certificates: []tls.Certificate{cert},
})
if err != nil {
log.Fatalf("Listen: %v", err)
}
s := http.Server{
Addr: ":8888",
Handler: mux,
}
s.Serve(l)
}
func newCert(names ...string) (tls.Certificate, error) {
key, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
return tls.Certificate{}, fmt.Errorf("ecdsa.GenerateKey: %w", err)
}
now := time.Now()
templ := &x509.Certificate{
Issuer: pkix.Name{CommonName: names[0]},
Subject: pkix.Name{CommonName: names[0]},
NotBefore: now,
NotAfter: now.Add(3650 * 24 * time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature,
BasicConstraintsValid: true,
IsCA: true,
DNSNames: names,
}
b, err := x509.CreateCertificate(rand.Reader, templ, templ, key.Public(), key)
if err != nil {
return tls.Certificate{}, fmt.Errorf("x509.CreateCertificate: %w", err)
}
cert, err := x509.ParseCertificate(b)
if err != nil {
return tls.Certificate{}, fmt.Errorf("x509.ParseCertificate: %w", err)
}
return tls.Certificate{
Certificate: [][]byte{b},
PrivateKey: key,
Leaf: cert,
}, nil
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment