Skip to content

Commit 74a3348

Browse files
committed
x/wasihttp: add wasihttp package
This commit ports the wasihttp package from the [wasi-http-go](https://github.com/ydnar/wasi-http-go) repository to here under the `x/wasihttp` directory. The wasihttp package provides a WASI HTTP server and client implementation using Go net/http package. The ./x/wasihttp/internal directory is regenerated using `make go-bindings` command from the wasihttp Makefile. Examples can be found in the `x/wasihttp/examples` directory and can be run under the ./x/wasihttp working directory. This new package has its own CHANGELOG.md, README.md, and RELEASE.md files to document the changes, usage, and release notes. Signed-off-by: Jiaxiao Zhou <[email protected]>
1 parent cfe612d commit 74a3348

File tree

149 files changed

+12079
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

149 files changed

+12079
-0
lines changed

x/wasihttp/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Changelog
2+
3+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4+
5+
## [Unreleased]
6+
7+
### Added
8+
- Initial import of the WASI HTTP package from the standalone repository
9+
10+
### Changed
11+
- Package import path is now `go.bytecodealliance.org/x/wasihttp`

x/wasihttp/README.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
# `go.bytecodealliance.org/x/wasihttp`
2+
3+
Package `go.bytecodealliance.org/x/wasihttp` implements [`wasi:http/proxy`](https://github.com/WebAssembly/wasi-http/blob/v0.2.0/proxy.md) for Go using standard [`net/http`](https://pkg.go.dev/net/http) interfaces.
4+
5+
This package allows Go applications to use the familiar `net/http` API when building WebAssembly modules that use the WASI HTTP standard.
6+
7+
## Prerequisites
8+
9+
To use this package, you'll need:
10+
11+
- [TinyGo](https://tinygo.org/) 0.34.0 or later.
12+
- [Wasmtime](https://wasmtime.dev/) 26.0.0 or later.
13+
14+
## Usage
15+
16+
### Server
17+
18+
Create a standard Go HTTP server using the familiar `net/http` API:
19+
20+
```go
21+
package main
22+
23+
import (
24+
"net/http"
25+
_ "go.bytecodealliance.org/x/wasihttp" // enable wasi-http
26+
)
27+
28+
func init() {
29+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
30+
w.Header().Add("X-Go", "Gopher")
31+
w.Write([]byte("Hello world!\n"))
32+
})
33+
}
34+
35+
func main() {}
36+
```
37+
38+
Compile with:
39+
40+
```bash
41+
tinygo build -target=wasip2-http.json -o server.wasm ./main.go
42+
```
43+
44+
## Examples
45+
46+
For more examples, see the `examples` directory.

x/wasihttp/RELEASE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Release Process
2+
3+
This document describes how to release a new version of the `wasihttp` package.
4+
5+
## Release Steps
6+
7+
1. Update the [CHANGELOG.md](CHANGELOG.md) with the changes since the last release.
8+
2. Ensure all tests pass and examples work correctly.
9+
10+
## Creating a Release
11+
12+
Create a new git tag for the release:
13+
14+
```bash
15+
git tag x/wasihttp/v0.1.0
16+
git push origin x/wasihttp/v0.1.0
17+
```
18+
19+
## Version Numbering
20+
21+
The `wasihttp` package follows [semantic versioning](https://semver.org/).

x/wasihttp/docs.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Package wasihttp implements [`wasi:http/proxy`](https://github.com/WebAssembly/wasi-http/blob/v0.2.0/proxy.md) for Go using standard [`net/http`](https://pkg.go.dev/net/http) interfaces
2+
//
3+
// It provides an implementation of the wasi:http/proxy interface that allows Go applications
4+
// to use the standard net/http library for both client and server operations within a WebAssembly
5+
// module. This allows Go developers to use familiar HTTP APIs when building WebAssembly modules
6+
// that need to make or handle HTTP requests.
7+
//
8+
// To use this package in your Go application, simply import it:
9+
//
10+
// import _ "go.bytecodealliance.org/x/wasihttp"
11+
package wasihttp

x/wasihttp/examples/basic/basic.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// This example implements a basic web server.
2+
//
3+
// To run: `tinygo run -target=wasip2-http.json ./examples/basic`
4+
// Test /: `curl -v 'http://0.0.0.0:8080/'`
5+
// Test /error: `curl -v 'http://0.0.0.0:8080/error'`
6+
7+
package main
8+
9+
import (
10+
"net/http"
11+
12+
_ "go.bytecodealliance.org/x/wasihttp"
13+
)
14+
15+
func init() {
16+
// TODO: use "GET /" when TinyGo supports net/http from Go 1.22+
17+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
18+
w.Header().Add("X-Go", "Gopher")
19+
w.Write([]byte("Hello world!\n"))
20+
})
21+
22+
http.HandleFunc("/error", func(w http.ResponseWriter, r *http.Request) {
23+
// do nothing, force default response handling
24+
})
25+
}
26+
27+
func main() {}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// This example implements a web server with a counter running in a goroutine.
2+
// This demonstrates instance reuse by the host.
3+
//
4+
// To run: `tinygo run -target=wasip2-http.json ./examples/counter`
5+
// Test /: `curl -v 'http://0.0.0.0:8080/'`
6+
7+
package main
8+
9+
import (
10+
"fmt"
11+
"net/http"
12+
13+
_ "go.bytecodealliance.org/x/wasihttp"
14+
)
15+
16+
func init() {
17+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
18+
n := <-c
19+
fmt.Fprintf(w, "%d", n)
20+
})
21+
22+
go func() {
23+
var n int
24+
for {
25+
c <- n
26+
n++
27+
}
28+
}()
29+
}
30+
31+
var c = make(chan int, 1)
32+
33+
func main() {}

x/wasihttp/examples/proxy/proxy.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// This example implements a reverse proxy that sends requests to postman-echo.com.
2+
//
3+
// To run: `tinygo run -target=wasip2-http.json ./examples/proxy`
4+
// Test GET: `curl -v 'http://0.0.0.0:8080/get'`
5+
// Test POST: `curl -v -d hello 'http://0.0.0.0:8080/post'`
6+
7+
package main
8+
9+
import (
10+
"context"
11+
"fmt"
12+
"io"
13+
"log"
14+
"net/http"
15+
"time"
16+
17+
_ "go.bytecodealliance.org/x/wasihttp"
18+
)
19+
20+
func init() {
21+
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
22+
start := time.Now()
23+
24+
ctx, cancel := context.WithCancel(r.Context())
25+
defer cancel()
26+
27+
r2 := r.Clone(ctx)
28+
r2.Host = "postman-echo.com"
29+
r2.URL.Host = "postman-echo.com"
30+
r2.URL.Scheme = "https"
31+
32+
defer func() {
33+
dur := time.Since(start)
34+
log.Printf("proxied %s in %s\n", r2.URL.String(), dur.String())
35+
}()
36+
37+
res, err := http.DefaultClient.Do(r2)
38+
if err != nil {
39+
w.WriteHeader(http.StatusInternalServerError)
40+
fmt.Fprintf(w, "error: %v", err)
41+
log.Printf("error: %v", err)
42+
return
43+
}
44+
45+
for k, v := range res.Header {
46+
for _, vv := range v {
47+
w.Header().Add(k, vv)
48+
}
49+
}
50+
51+
w.WriteHeader(res.StatusCode)
52+
if res.Body != nil {
53+
io.Copy(w, res.Body)
54+
res.Body.Close()
55+
}
56+
})
57+
}
58+
59+
func main() {}
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
// This example is taken from https://github.com/dev-wasm/dev-wasm-go/blob/main/http/main.go
2+
// demonstrates how to use the wasihttp package to make HTTP requests using the `http.Client` interface.
3+
//
4+
// To run: `tinygo build -target=wasip2-roundtrip.json -o roundtrip.wasm ./examples/roundtrip`
5+
// Test: `wasmtime run -Shttp -Sinherit-network -Sinherit-env roundtrip.wasm`
6+
package main
7+
8+
import (
9+
"bytes"
10+
"fmt"
11+
"io"
12+
"net/http"
13+
14+
wasihttp "go.bytecodealliance.org/x/wasihttp"
15+
)
16+
17+
func printResponse(r *http.Response) error {
18+
fmt.Printf("Status: %d\n", r.StatusCode)
19+
for k, v := range r.Header {
20+
fmt.Printf("%s: %s\n", k, v[0])
21+
}
22+
body, err := io.ReadAll(r.Body)
23+
if err != nil {
24+
return err
25+
}
26+
fmt.Printf("Body: \n%s\n", body)
27+
return nil
28+
}
29+
30+
func main() {
31+
client := &http.Client{
32+
Transport: &wasihttp.Transport{},
33+
}
34+
req, err := http.NewRequest("GET", "https://postman-echo.com/get", nil)
35+
if err != nil {
36+
panic(err.Error())
37+
}
38+
if req == nil {
39+
panic("Nil request!")
40+
}
41+
res, err := client.Do(req)
42+
if err != nil {
43+
panic(err.Error())
44+
}
45+
defer res.Body.Close()
46+
47+
err = printResponse(res)
48+
if err != nil {
49+
panic(err.Error())
50+
}
51+
52+
res, err = client.Post("https://postman-echo.com/post", "application/json", bytes.NewReader([]byte("{\"foo\": \"bar\"}")))
53+
if err != nil {
54+
panic(err.Error())
55+
}
56+
defer res.Body.Close()
57+
58+
err = printResponse(res)
59+
if err != nil {
60+
panic(err.Error())
61+
}
62+
63+
req, err = http.NewRequest("PUT", "http://postman-echo.com/put", bytes.NewReader([]byte("{\"baz\": \"blah\"}")))
64+
if err != nil {
65+
panic(err.Error())
66+
}
67+
if req == nil {
68+
panic("Nil request!")
69+
}
70+
res, err = client.Do(req)
71+
if err != nil {
72+
panic(err.Error())
73+
}
74+
defer res.Body.Close()
75+
76+
err = printResponse(res)
77+
if err != nil {
78+
panic(err.Error())
79+
}
80+
}

x/wasihttp/internal/go/http/proxy/proxy.wit.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// This file exists for testing this package without WebAssembly,
2+
// allowing empty function bodies with a //go:wasmimport directive.
3+
// See https://pkg.go.dev/cmd/compile for more information.

0 commit comments

Comments
 (0)