adriancable / webtransport-go

Lightweight but fully-capable WebTransport server for Go
MIT License
116 stars 12 forks source link

webtransport-go

This package provides a lightweight WebTransport-over-HTTP/3 server implementation in Go.

What is WebTransport?

WebTransport (https://www.w3.org/TR/webtransport/) is a 21st century replacement for WebSockets. It's currently supported by Chrome, with support in other browsers coming shortly. It has several benefits over WebSockets:

Neither WebTransport nor HTTP/3 are standardized yet. We adhere to: draft-ietf-quic-http-34 and draft-ietf-webtrans-http3-02.

Documentation

GoDoc has full documentation on webtransport-go's public API.

Complete Go server and browser-based client example

Take a look at the webtransport-go-example repo for a complete server (and browser client) example.

Minimal "getting started" example

You'll need to get a certificate for your server. Please read the comments at the top of Google's WebTransport server example in Python for detailed instructions.

First, set up WebTransport server parameters:

server := &webtransport.Server{
    ListenAddr:     ":4433",
    TLSCert:        webtransport.CertFile{Path: "cert.pem"},
    TLSKey:         webtransport.CertFile{Path: "cert.key"},
}

Then, set up an http.Handler to accept a session, wait for an incoming bidirectional stream from the client, then (in this example) receive data and echo it back:

http.HandleFunc("/counter", func(rw http.ResponseWriter, r *http.Request) {
    session := r.Body.(*webtransport.Session)
    session.AcceptSession()
    defer session.CloseSession()

    // Wait for incoming bidi stream
    s, err := session.AcceptStream()
    if err != nil {
        return
    }

    for {
        buf := make([]byte, 1024)
        n, err := s.Read(buf)
        if err != nil {
            break
        }
        fmt.Printf("Received from bidi stream %v: %s\n", s.StreamID(), buf[:n])
        sendMsg := bytes.ToUpper(buf[:n])
        fmt.Printf("Sending to bidi stream %v: %s\n", s.StreamID(), sendMsg)
        s.Write(sendMsg)
    }
}

Finally, start the server:

ctx, cancel := context.WithCancel(context.Background())
server.Run(ctx)

Here is a simple Chrome browser client to talk to this server. You can open a new browser tab and paste it into the Chrome DevTools console:

let transport = new WebTransport("https://localhost:4433/counter");
await transport.ready;
let stream = await transport.createBidirectionalStream();
let encoder = new TextEncoder();
let decoder = new TextDecoder();
let writer = stream.writable.getWriter();
let reader = stream.readable.getReader();
await writer.write(encoder.encode("Hello, world!"))
console.log(decoder.decode((await reader.read()).value));
transport.close();

Authors and acknowledgment

This package was written by me, drawing on several sources of inspiration:

Instead, webtransport-go implements the latest draft standards for all the supported protocols, is very lightweight, and doesn't depend on any non-standard Go package forks or WIP modules.

License

Provided under the MIT license.