Documentation ¶
Overview ¶
Example (Auth) ¶
package main import ( "context" "fmt" "log" "net/http" "net/http/httptest" _ "embed" wasm "github.com/httpwasm/http-wasm-host-go/handler/nethttp" "github.com/httpwasm/http-wasm-host-go/internal/test" ) var ( responseBody = "{\"hello\": \"world\"}" serveJson = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.Header.Set("Content-Type", "application/json") w.Write([]byte(responseBody)) }) ) func main() { ctx := context.Background() // Configure and compile the WebAssembly guest binary. In this case, it is // an auth interceptor. mw, err := wasm.NewMiddleware(ctx, test.BinExampleAuth) if err != nil { log.Panicln(err) } defer mw.Close(ctx) // Create the real request handler. next := serveJson // Wrap this with an interceptor implemented in WebAssembly. wrapped := mw.NewHandler(ctx, next) // Start the server with the wrapped handler. ts := httptest.NewServer(wrapped) defer ts.Close() // Invoke some requests, only one of which should pass headers := []http.Header{ {"NotAuthorization": {"1"}}, {"Authorization": {""}}, {"Authorization": {"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="}}, {"Authorization": {"0"}}, } for _, header := range headers { req, err := http.NewRequest(http.MethodGet, ts.URL, nil) if err != nil { log.Panicln(err) } req.Header = header resp, err := ts.Client().Do(req) if err != nil { log.Panicln(err) } resp.Body.Close() switch resp.StatusCode { case http.StatusOK: fmt.Println("OK") case http.StatusUnauthorized: fmt.Println("Unauthorized") default: log.Panicln("unexpected status code", resp.StatusCode) } if auth, ok := resp.Header["Www-Authenticate"]; ok { fmt.Println("Www-Authenticate:", auth[0]) } } }
Output: Unauthorized Www-Authenticate: Basic realm="test" Unauthorized OK Unauthorized
Example (Log) ¶
package main import ( "context" "log" "net/http" "net/http/httptest" "github.com/httpwasm/http-wasm-host-go/api" "github.com/httpwasm/http-wasm-host-go/handler" _ "embed" wasm "github.com/httpwasm/http-wasm-host-go/handler/nethttp" "github.com/httpwasm/http-wasm-host-go/internal/test" ) var ( responseBody = "{\"hello\": \"world\"}" serveJson = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.Header.Set("Content-Type", "application/json") w.Write([]byte(responseBody)) }) ) func main() { ctx := context.Background() // Configure and compile the WebAssembly guest binary. In this case, it is // a logging interceptor. mw, err := wasm.NewMiddleware(ctx, test.BinExampleLog, handler.Logger(api.ConsoleLogger{})) if err != nil { log.Panicln(err) } defer mw.Close(ctx) // Create the real request handler. next := serveJson // Wrap this with an interceptor implemented in WebAssembly. wrapped := mw.NewHandler(ctx, next) // Start the server with the wrapped handler. ts := httptest.NewServer(wrapped) defer ts.Close() // Make a client request. resp, err := ts.Client().Get(ts.URL) if err != nil { log.Panicln(err) } defer resp.Body.Close() }
Output: hello world
Example (Redact) ¶
package main import ( "context" "fmt" "io" "log" "net/http" "net/http/httptest" "strings" "github.com/httpwasm/http-wasm-host-go/handler" _ "embed" wasm "github.com/httpwasm/http-wasm-host-go/handler/nethttp" "github.com/httpwasm/http-wasm-host-go/internal/test" ) func main() { ctx := context.Background() // Configure and compile the WebAssembly guest binary. In this case, it is // an example response redact. secret := "open sesame" mw, err := wasm.NewMiddleware(ctx, test.BinExampleRedact, handler.GuestConfig([]byte(secret))) if err != nil { log.Panicln(err) } defer mw.Close(ctx) var body string serveBody := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { content, _ := io.ReadAll(r.Body) fmt.Println(string(content)) r.Header.Set("Content-Type", "text/plain") w.Write([]byte(body)) // nolint }) // Wrap the real handler with an interceptor implemented in WebAssembly. wrapped := mw.NewHandler(ctx, serveBody) // Start the server with the wrapped handler. ts := httptest.NewServer(wrapped) defer ts.Close() bodies := []string{ secret, "hello world", fmt.Sprintf("hello %s world", secret), } for _, b := range bodies { body = b resp, err := ts.Client().Post(ts.URL, "text/plain", strings.NewReader(body)) if err != nil { log.Panicln(err) } defer resp.Body.Close() content, _ := io.ReadAll(resp.Body) fmt.Println(string(content)) } }
Output: ########### ########### hello world hello world hello ########### world hello ########### world
Example (Router) ¶
package main import ( "context" "fmt" "io" "log" "net/http" "net/http/httptest" _ "embed" wasm "github.com/httpwasm/http-wasm-host-go/handler/nethttp" "github.com/httpwasm/http-wasm-host-go/internal/test" ) var ( responseBody = "{\"hello\": \"world\"}" servePath = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { r.Header.Set("Content-Type", "text/plain") w.Write([]byte(r.URL.Path)) }) ) func main() { ctx := context.Background() // Configure and compile the WebAssembly guest binary. In this case, it is // an example request router. mw, err := wasm.NewMiddleware(ctx, test.BinExampleRouter) if err != nil { log.Panicln(err) } defer mw.Close(ctx) // Wrap the real handler with an interceptor implemented in WebAssembly. wrapped := mw.NewHandler(ctx, servePath) // Start the server with the wrapped handler. ts := httptest.NewServer(wrapped) defer ts.Close() // Invoke some requests, only one of which should pass paths := []string{ "", "nothosst", "host/a", } for _, p := range paths { url := fmt.Sprintf("%s/%s", ts.URL, p) resp, err := ts.Client().Get(url) if err != nil { log.Panicln(err) } defer resp.Body.Close() content, _ := io.ReadAll(resp.Body) fmt.Println(string(content)) } }
Output: hello world hello world /a
Example (Wasi) ¶
package main import ( "context" "log" "net/http" "net/http/httptest" "os" "strings" "github.com/tetratelabs/wazero" "github.com/httpwasm/http-wasm-host-go/handler" _ "embed" wasm "github.com/httpwasm/http-wasm-host-go/handler/nethttp" "github.com/httpwasm/http-wasm-host-go/internal/test" ) var ( requestBody = "{\"hello\": \"panda\"}" responseBody = "{\"hello\": \"world\"}" ) func main() { ctx := context.Background() moduleConfig := wazero.NewModuleConfig().WithStdout(os.Stdout) // Configure and compile the WebAssembly guest binary. In this case, it // prints the request and response to the STDOUT via WASI. mw, err := wasm.NewMiddleware(ctx, test.BinExampleWASI, handler.ModuleConfig(moduleConfig)) if err != nil { log.Panicln(err) } defer mw.Close(ctx) // Create the real request handler. next := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Content-Type", "application/json") w.Header().Add("Set-Cookie", "a=b") // example of multiple headers w.Header().Add("Set-Cookie", "c=d") w.Header().Set("Date", "Tue, 15 Nov 1994 08:12:31 GMT") // Use chunked encoding so we can set a test trailer w.Header().Set("Transfer-Encoding", "chunked") w.Header().Set("Trailer", "grpc-status") w.Header().Set(http.TrailerPrefix+"grpc-status", "1") w.Write([]byte(`{"hello": "world"}`)) // nolint }) // Wrap this with an interceptor implemented in WebAssembly. wrapped := mw.NewHandler(ctx, next) // Start the server with the wrapped handler. ts := httptest.NewServer(wrapped) defer ts.Close() // Make a client request which should print to the console req, err := http.NewRequest("POST", ts.URL, strings.NewReader(requestBody)) if err != nil { log.Panicln(err) } req.Header.Set("Content-Type", "application/json") req.Host = "localhost" resp, err := ts.Client().Do(req) if err != nil { log.Panicln(err) } defer resp.Body.Close() }
Output: POST / HTTP/1.1 accept-encoding: gzip content-length: 18 content-type: application/json host: localhost user-agent: Go-http-client/1.1 {"hello": "panda"} HTTP/1.1 200 content-type: application/json date: Tue, 15 Nov 1994 08:12:31 GMT set-cookie: a=b set-cookie: c=d trailer: grpc-status transfer-encoding: chunked {"hello": "world"} grpc-status: 1
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
Click to show internal directories.
Click to hide internal directories.