maybe fixed

This commit is contained in:
Lorenzo Venerandi 2024-12-16 20:34:52 +01:00
parent cdc80d0b53
commit 8cd67e00a2
24 changed files with 1651 additions and 242 deletions

View File

@ -48,5 +48,4 @@ RUN mkdir /app
WORKDIR /app WORKDIR /app
# Install go dependencies, build the wasm module, push it to the registry # Install go dependencies, build the wasm module, push it to the registry
#CMD ["sh", "-c", "go mod download && go mod verify && go mod tidy && wash build && wash push $REGISTRY build/*_s.wasm"]
CMD ["sh", "-c", "go env -w GOFLAGS=-buildvcs=false && go mod download && go mod verify && wash build && wash push $REGISTRY build/*.wasm"] CMD ["sh", "-c", "go env -w GOFLAGS=-buildvcs=false && go mod download && go mod verify && wash build && wash push $REGISTRY build/*.wasm"]

View File

@ -1,8 +1,4 @@
# HTTP Hello World # Prerequisites
This is a simple TinyGo Wasm example that responds with a "Hello World" message for each request.
## Prerequisites
- `go` 1.23 - `go` 1.23
- `tinygo` 0.33 - `tinygo` 0.33
@ -20,6 +16,24 @@ wash build
wash push gitea.rebus.ninja/lore/go-nats-client:1.x.x build/go_nats_client_s.wasm wash push gitea.rebus.ninja/lore/go-nats-client:1.x.x build/go_nats_client_s.wasm
``` ```
## Build and push to the registry using the dockerfile
### Build the cointainer
```bash
docker build -t wash-image-build .
```
### Build the component and push to the registry
First setup your credentials
```bash
export REG_USER=user && export REG_PASS=pass
```
Build and push
```bash
docker run --rm -e REGISTRY=gitea.rebus.ninja/lore/wasm-nats-producer-client:1.0.x -e WASH_REG_USER=$REG_USER -e WASH_REG_PASSWORD=$REG_PASS -v "$(pwd):/app" wash-image-build
```
## Running with wasmtime ## Running with wasmtime
You must have wasmtime 25.0.0 for this to work. Make sure to follow the build step above first. You must have wasmtime 25.0.0 for this to work. Make sure to follow the build step above first.

View File

@ -0,0 +1,3 @@
// This file exists for testing this package without WebAssembly,
// allowing empty function bodies with a //go:wasmimport directive.
// See https://pkg.go.dev/cmd/compile for more information.

View File

@ -0,0 +1,22 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package incominghandler
// Exports represents the caller-defined exports from "wasi:http/incoming-handler@0.2.0".
var Exports struct {
// Handle represents the caller-defined, exported function "handle".
//
// This function is invoked with an incoming HTTP Request, and a resource
// `response-outparam` which provides the capability to reply with an HTTP
// Response. The response is sent by calling the `response-outparam.set`
// method, which allows execution to continue after the response has been
// sent. This enables both streaming to the response body, and performing other
// work.
//
// The implementor of this function must write a response to the
// `response-outparam` before returning, or else the caller will respond
// with an error on its behalf.
//
// handle: func(request: incoming-request, response-out: response-outparam)
Handle func(request IncomingRequest, responseOut ResponseOutparam)
}

View File

@ -0,0 +1,21 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
// Package incominghandler represents the exported interface "wasi:http/incoming-handler@0.2.0".
//
// This interface defines a handler of incoming HTTP Requests. It should
// be exported by components which can respond to HTTP Requests.
package incominghandler
import (
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasi/http/types"
)
// IncomingRequest represents the exported type alias "wasi:http/incoming-handler@0.2.0#incoming-request".
//
// See [types.IncomingRequest] for more information.
type IncomingRequest = types.IncomingRequest
// ResponseOutparam represents the exported type alias "wasi:http/incoming-handler@0.2.0#response-outparam".
//
// See [types.ResponseOutparam] for more information.
type ResponseOutparam = types.ResponseOutparam

View File

@ -0,0 +1,18 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package incominghandler
import (
"github.com/bytecodealliance/wasm-tools-go/cm"
)
// This file contains wasmimport and wasmexport declarations for "wasi:http@0.2.0".
//go:wasmexport wasi:http/incoming-handler@0.2.0#handle
//export wasi:http/incoming-handler@0.2.0#handle
func wasmexport_Handle(request0 uint32, responseOut0 uint32) {
request := cm.Reinterpret[IncomingRequest]((uint32)(request0))
responseOut := cm.Reinterpret[ResponseOutparam]((uint32)(responseOut0))
Exports.Handle(request, responseOut)
return
}

View File

@ -1,6 +1,9 @@
// Code generated by wit-bindgen-go. DO NOT EDIT. // Code generated by wit-bindgen-go. DO NOT EDIT.
// Package outgoinghandler represents the imported interface "wasi:http/outgoing-handler@0.2.0". // Package outgoinghandler represents the imported interface "wasi:http/outgoing-handler@0.2.0".
//
// This interface defines a handler of outgoing HTTP Requests. It should be
// imported by components which wish to make HTTP Requests.
package outgoinghandler package outgoinghandler
import ( import (
@ -30,6 +33,17 @@ type ErrorCode = types.ErrorCode
// Handle represents the imported function "handle". // Handle represents the imported function "handle".
// //
// This function is invoked with an outgoing HTTP Request, and it returns
// a resource `future-incoming-response` which represents an HTTP Response
// which may arrive in the future.
//
// The `options` argument accepts optional parameters for the HTTP
// protocol's transport layer.
//
// This function may return an error if the `outgoing-request` is invalid
// or not allowed to be made. Otherwise, protocol errors are reported
// through the `future-incoming-response`.
//
// handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response, // handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response,
// error-code> // error-code>
// //

View File

@ -1,6 +1,10 @@
// Code generated by wit-bindgen-go. DO NOT EDIT. // Code generated by wit-bindgen-go. DO NOT EDIT.
// Package types represents the imported interface "wasi:http/types@0.2.0". // Package types represents the imported interface "wasi:http/types@0.2.0".
//
// This interface defines all of the types and methods for implementing
// HTTP Requests and Responses, both incoming and outgoing, as well as
// their headers, trailers, and bodies.
package types package types
import ( import (
@ -38,6 +42,8 @@ type Pollable = poll.Pollable
// Method represents the variant "wasi:http/types@0.2.0#method". // Method represents the variant "wasi:http/types@0.2.0#method".
// //
// This type corresponds to HTTP standard Methods.
//
// variant method { // variant method {
// get, // get,
// head, // head,
@ -181,6 +187,8 @@ func (v Method) String() string {
// Scheme represents the variant "wasi:http/types@0.2.0#scheme". // Scheme represents the variant "wasi:http/types@0.2.0#scheme".
// //
// This type corresponds to HTTP standard Related Schemes.
//
// variant scheme { // variant scheme {
// HTTP, // HTTP,
// HTTPS, // HTTPS,
@ -233,6 +241,8 @@ func (v Scheme) String() string {
// DNSErrorPayload represents the record "wasi:http/types@0.2.0#DNS-error-payload". // DNSErrorPayload represents the record "wasi:http/types@0.2.0#DNS-error-payload".
// //
// Defines the case payload type for `DNS-error` above:
//
// record DNS-error-payload { // record DNS-error-payload {
// rcode: option<string>, // rcode: option<string>,
// info-code: option<u16>, // info-code: option<u16>,
@ -245,6 +255,8 @@ type DNSErrorPayload struct {
// TLSAlertReceivedPayload represents the record "wasi:http/types@0.2.0#TLS-alert-received-payload". // TLSAlertReceivedPayload represents the record "wasi:http/types@0.2.0#TLS-alert-received-payload".
// //
// Defines the case payload type for `TLS-alert-received` above:
//
// record TLS-alert-received-payload { // record TLS-alert-received-payload {
// alert-id: option<u8>, // alert-id: option<u8>,
// alert-message: option<string>, // alert-message: option<string>,
@ -257,6 +269,8 @@ type TLSAlertReceivedPayload struct {
// FieldSizePayload represents the record "wasi:http/types@0.2.0#field-size-payload". // FieldSizePayload represents the record "wasi:http/types@0.2.0#field-size-payload".
// //
// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
//
// record field-size-payload { // record field-size-payload {
// field-name: option<string>, // field-name: option<string>,
// field-size: option<u32>, // field-size: option<u32>,
@ -269,6 +283,9 @@ type FieldSizePayload struct {
// ErrorCode represents the variant "wasi:http/types@0.2.0#error-code". // ErrorCode represents the variant "wasi:http/types@0.2.0#error-code".
// //
// These cases are inspired by the IANA HTTP Proxy Error Types:
// https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types
//
// variant error-code { // variant error-code {
// DNS-timeout, // DNS-timeout,
// DNS-error(DNS-error-payload), // DNS-error(DNS-error-payload),
@ -717,6 +734,12 @@ func (self *ErrorCode) ConfigurationError() bool {
} }
// ErrorCodeInternalError returns a [ErrorCode] of case "internal-error". // ErrorCodeInternalError returns a [ErrorCode] of case "internal-error".
//
// This is a catch-all error for anything that doesn't fit cleanly into a
// more specific case. It also includes an optional string for an
// unstructured description of the error. Users should not depend on the
// string for diagnosing errors, as it's not required to be consistent
// between implementations.
func ErrorCodeInternalError(data cm.Option[string]) ErrorCode { func ErrorCodeInternalError(data cm.Option[string]) ErrorCode {
return cm.New[ErrorCode](38, data) return cm.New[ErrorCode](38, data)
} }
@ -775,6 +798,9 @@ func (v ErrorCode) String() string {
// HeaderError represents the variant "wasi:http/types@0.2.0#header-error". // HeaderError represents the variant "wasi:http/types@0.2.0#header-error".
// //
// This type enumerates the different kinds of errors that may occur when
// setting or appending to a `fields` resource.
//
// variant header-error { // variant header-error {
// invalid-syntax, // invalid-syntax,
// forbidden, // forbidden,
@ -783,8 +809,17 @@ func (v ErrorCode) String() string {
type HeaderError uint8 type HeaderError uint8
const ( const (
// This error indicates that a `field-key` or `field-value` was
// syntactically invalid when used with an operation that sets headers in a
// `fields`.
HeaderErrorInvalidSyntax HeaderError = iota HeaderErrorInvalidSyntax HeaderError = iota
// This error indicates that a forbidden `field-key` was used when trying
// to set a header in a `fields`.
HeaderErrorForbidden HeaderErrorForbidden
// This error indicates that the operation on the `fields` was not
// permitted because the fields are immutable.
HeaderErrorImmutable HeaderErrorImmutable
) )
@ -801,16 +836,33 @@ func (e HeaderError) String() string {
// FieldKey represents the string "wasi:http/types@0.2.0#field-key". // FieldKey represents the string "wasi:http/types@0.2.0#field-key".
// //
// Field keys are always strings.
//
// type field-key = string // type field-key = string
type FieldKey string type FieldKey string
// FieldValue represents the list "wasi:http/types@0.2.0#field-value". // FieldValue represents the list "wasi:http/types@0.2.0#field-value".
// //
// Field values should always be ASCII strings. However, in
// reality, HTTP implementations often have to interpret malformed values,
// so they are provided as a list of bytes.
//
// type field-value = list<u8> // type field-value = list<u8>
type FieldValue cm.List[uint8] type FieldValue cm.List[uint8]
// Fields represents the imported resource "wasi:http/types@0.2.0#fields". // Fields represents the imported resource "wasi:http/types@0.2.0#fields".
// //
// This following block defines the `fields` resource which corresponds to
// HTTP standard Fields. Fields are a common representation used for both
// Headers and Trailers.
//
// A `fields` may be mutable or immutable. A `fields` created using the
// constructor, `from-list`, or `clone` will be mutable, but a `fields`
// resource given by other means (including, but not limited to,
// `incoming-request.headers`, `outgoing-request.headers`) might be be
// immutable. In an immutable fields, the `set`, `append`, and `delete`
// operations will fail with `header-error.immutable`.
//
// resource fields // resource fields
type Fields cm.Resource type Fields cm.Resource
@ -827,6 +879,10 @@ func (self Fields) ResourceDrop() {
// NewFields represents the imported constructor for resource "fields". // NewFields represents the imported constructor for resource "fields".
// //
// Construct an empty HTTP Fields.
//
// The resulting `fields` is mutable.
//
// constructor() // constructor()
// //
//go:nosplit //go:nosplit
@ -838,6 +894,22 @@ func NewFields() (result Fields) {
// FieldsFromList represents the imported static function "from-list". // FieldsFromList represents the imported static function "from-list".
// //
// Construct an HTTP Fields.
//
// The resulting `fields` is mutable.
//
// The list represents each key-value pair in the Fields. Keys
// which have multiple values are represented by multiple entries in this
// list with the same key.
//
// The tuple is a pair of the field key, represented as a string, and
// Value, represented as a list of bytes. In a valid Fields, all keys
// and values are valid UTF-8 strings. However, values are not always
// well-formed, so they are represented as a raw list of bytes.
//
// An error result will be returned if any header or value was
// syntactically invalid, or if a header was forbidden.
//
// from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields, // from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields,
// header-error> // header-error>
// //
@ -850,6 +922,11 @@ func FieldsFromList(entries cm.List[cm.Tuple[FieldKey, FieldValue]]) (result cm.
// Append represents the imported method "append". // Append represents the imported method "append".
// //
// Append a value for a key. Does not change or delete any existing
// values for that key.
//
// Fails with `header-error.immutable` if the `fields` are immutable.
//
// append: func(name: field-key, value: field-value) -> result<_, header-error> // append: func(name: field-key, value: field-value) -> result<_, header-error>
// //
//go:nosplit //go:nosplit
@ -863,6 +940,10 @@ func (self Fields) Append(name FieldKey, value FieldValue) (result cm.Result[Hea
// Clone represents the imported method "clone". // Clone represents the imported method "clone".
// //
// Make a deep copy of the Fields. Equivelant in behavior to calling the
// `fields` constructor on the return value of `entries`. The resulting
// `fields` is mutable.
//
// clone: func() -> fields // clone: func() -> fields
// //
//go:nosplit //go:nosplit
@ -875,6 +956,11 @@ func (self Fields) Clone() (result Fields) {
// Delete represents the imported method "delete". // Delete represents the imported method "delete".
// //
// Delete all values for a key. Does nothing if no values for the key
// exist.
//
// Fails with `header-error.immutable` if the `fields` are immutable.
//
// delete: func(name: field-key) -> result<_, header-error> // delete: func(name: field-key) -> result<_, header-error>
// //
//go:nosplit //go:nosplit
@ -887,6 +973,13 @@ func (self Fields) Delete(name FieldKey) (result cm.Result[HeaderError, struct{}
// Entries represents the imported method "entries". // Entries represents the imported method "entries".
// //
// Retrieve the full set of keys and values in the Fields. Like the
// constructor, the list represents each key-value pair.
//
// The outer list represents each key-value pair in the Fields. Keys
// which have multiple values are represented by multiple entries in this
// list with the same key.
//
// entries: func() -> list<tuple<field-key, field-value>> // entries: func() -> list<tuple<field-key, field-value>>
// //
//go:nosplit //go:nosplit
@ -898,6 +991,11 @@ func (self Fields) Entries() (result cm.List[cm.Tuple[FieldKey, FieldValue]]) {
// Get represents the imported method "get". // Get represents the imported method "get".
// //
// Get all of the values corresponding to a key. If the key is not present
// in this `fields`, an empty list is returned. However, if the key is
// present but empty, this is represented by a list with one or more
// empty field-values present.
//
// get: func(name: field-key) -> list<field-value> // get: func(name: field-key) -> list<field-value>
// //
//go:nosplit //go:nosplit
@ -910,6 +1008,9 @@ func (self Fields) Get(name FieldKey) (result cm.List[FieldValue]) {
// Has represents the imported method "has". // Has represents the imported method "has".
// //
// Returns `true` when the key is present in this `fields`. If the key is
// syntactically invalid, `false` is returned.
//
// has: func(name: field-key) -> bool // has: func(name: field-key) -> bool
// //
//go:nosplit //go:nosplit
@ -923,6 +1024,11 @@ func (self Fields) Has(name FieldKey) (result bool) {
// Set represents the imported method "set". // Set represents the imported method "set".
// //
// Set all of the values for a key. Clears any existing values for that
// key, if they have been set.
//
// Fails with `header-error.immutable` if the `fields` are immutable.
//
// set: func(name: field-key, value: list<field-value>) -> result<_, header-error> // set: func(name: field-key, value: list<field-value>) -> result<_, header-error>
// //
//go:nosplit //go:nosplit
@ -946,6 +1052,8 @@ type Trailers = Fields
// IncomingRequest represents the imported resource "wasi:http/types@0.2.0#incoming-request". // IncomingRequest represents the imported resource "wasi:http/types@0.2.0#incoming-request".
// //
// Represents an incoming HTTP Request.
//
// resource incoming-request // resource incoming-request
type IncomingRequest cm.Resource type IncomingRequest cm.Resource
@ -962,6 +1070,8 @@ func (self IncomingRequest) ResourceDrop() {
// Authority represents the imported method "authority". // Authority represents the imported method "authority".
// //
// Returns the authority from the request, if it was present.
//
// authority: func() -> option<string> // authority: func() -> option<string>
// //
//go:nosplit //go:nosplit
@ -973,6 +1083,9 @@ func (self IncomingRequest) Authority() (result cm.Option[string]) {
// Consume represents the imported method "consume". // Consume represents the imported method "consume".
// //
// Gives the `incoming-body` associated with this request. Will only
// return success at most once, and subsequent calls will return error.
//
// consume: func() -> result<incoming-body> // consume: func() -> result<incoming-body>
// //
//go:nosplit //go:nosplit
@ -984,6 +1097,15 @@ func (self IncomingRequest) Consume() (result cm.Result[IncomingBody, IncomingBo
// Headers represents the imported method "headers". // Headers represents the imported method "headers".
// //
// Get the `headers` associated with the request.
//
// The returned `headers` resource is immutable: `set`, `append`, and
// `delete` operations will fail with `header-error.immutable`.
//
// The `headers` returned are a child resource: it must be dropped before
// the parent `incoming-request` is dropped. Dropping this
// `incoming-request` before all children are dropped will trap.
//
// headers: func() -> headers // headers: func() -> headers
// //
//go:nosplit //go:nosplit
@ -996,6 +1118,8 @@ func (self IncomingRequest) Headers() (result Headers) {
// Method represents the imported method "method". // Method represents the imported method "method".
// //
// Returns the method of the incoming request.
//
// method: func() -> method // method: func() -> method
// //
//go:nosplit //go:nosplit
@ -1007,6 +1131,8 @@ func (self IncomingRequest) Method() (result Method) {
// PathWithQuery represents the imported method "path-with-query". // PathWithQuery represents the imported method "path-with-query".
// //
// Returns the path with query parameters from the request, as a string.
//
// path-with-query: func() -> option<string> // path-with-query: func() -> option<string>
// //
//go:nosplit //go:nosplit
@ -1018,6 +1144,8 @@ func (self IncomingRequest) PathWithQuery() (result cm.Option[string]) {
// Scheme represents the imported method "scheme". // Scheme represents the imported method "scheme".
// //
// Returns the protocol scheme from the request.
//
// scheme: func() -> option<scheme> // scheme: func() -> option<scheme>
// //
//go:nosplit //go:nosplit
@ -1029,6 +1157,8 @@ func (self IncomingRequest) Scheme() (result cm.Option[Scheme]) {
// OutgoingRequest represents the imported resource "wasi:http/types@0.2.0#outgoing-request". // OutgoingRequest represents the imported resource "wasi:http/types@0.2.0#outgoing-request".
// //
// Represents an outgoing HTTP Request.
//
// resource outgoing-request // resource outgoing-request
type OutgoingRequest cm.Resource type OutgoingRequest cm.Resource
@ -1045,6 +1175,17 @@ func (self OutgoingRequest) ResourceDrop() {
// NewOutgoingRequest represents the imported constructor for resource "outgoing-request". // NewOutgoingRequest represents the imported constructor for resource "outgoing-request".
// //
// Construct a new `outgoing-request` with a default `method` of `GET`, and
// `none` values for `path-with-query`, `scheme`, and `authority`.
//
// * `headers` is the HTTP Headers for the Request.
//
// It is possible to construct, or manipulate with the accessor functions
// below, an `outgoing-request` with an invalid combination of `scheme`
// and `authority`, or `headers` which are not permitted to be sent.
// It is the obligation of the `outgoing-handler.handle` implementation
// to reject invalid constructions of `outgoing-request`.
//
// constructor(headers: headers) // constructor(headers: headers)
// //
//go:nosplit //go:nosplit
@ -1057,6 +1198,10 @@ func NewOutgoingRequest(headers Headers) (result OutgoingRequest) {
// Authority represents the imported method "authority". // Authority represents the imported method "authority".
// //
// Get the HTTP Authority for the Request. A value of `none` may be used
// with Related Schemes which do not require an Authority. The HTTP and
// HTTPS schemes always require an authority.
//
// authority: func() -> option<string> // authority: func() -> option<string>
// //
//go:nosplit //go:nosplit
@ -1068,6 +1213,13 @@ func (self OutgoingRequest) Authority() (result cm.Option[string]) {
// Body represents the imported method "body". // Body represents the imported method "body".
// //
// Returns the resource corresponding to the outgoing Body for this
// Request.
//
// Returns success on the first call: the `outgoing-body` resource for
// this `outgoing-request` can be retrieved at most once. Subsequent
// calls will return error.
//
// body: func() -> result<outgoing-body> // body: func() -> result<outgoing-body>
// //
//go:nosplit //go:nosplit
@ -1079,6 +1231,15 @@ func (self OutgoingRequest) Body() (result cm.Result[OutgoingBody, OutgoingBody,
// Headers represents the imported method "headers". // Headers represents the imported method "headers".
// //
// Get the headers associated with the Request.
//
// The returned `headers` resource is immutable: `set`, `append`, and
// `delete` operations will fail with `header-error.immutable`.
//
// This headers resource is a child: it must be dropped before the parent
// `outgoing-request` is dropped, or its ownership is transfered to
// another component by e.g. `outgoing-handler.handle`.
//
// headers: func() -> headers // headers: func() -> headers
// //
//go:nosplit //go:nosplit
@ -1091,6 +1252,8 @@ func (self OutgoingRequest) Headers() (result Headers) {
// Method represents the imported method "method". // Method represents the imported method "method".
// //
// Get the Method for the Request.
//
// method: func() -> method // method: func() -> method
// //
//go:nosplit //go:nosplit
@ -1102,6 +1265,9 @@ func (self OutgoingRequest) Method() (result Method) {
// PathWithQuery represents the imported method "path-with-query". // PathWithQuery represents the imported method "path-with-query".
// //
// Get the combination of the HTTP Path and Query for the Request.
// When `none`, this represents an empty Path and empty Query.
//
// path-with-query: func() -> option<string> // path-with-query: func() -> option<string>
// //
//go:nosplit //go:nosplit
@ -1113,6 +1279,9 @@ func (self OutgoingRequest) PathWithQuery() (result cm.Option[string]) {
// Scheme represents the imported method "scheme". // Scheme represents the imported method "scheme".
// //
// Get the HTTP Related Scheme for the Request. When `none`, the
// implementation may choose an appropriate default scheme.
//
// scheme: func() -> option<scheme> // scheme: func() -> option<scheme>
// //
//go:nosplit //go:nosplit
@ -1124,6 +1293,11 @@ func (self OutgoingRequest) Scheme() (result cm.Option[Scheme]) {
// SetAuthority represents the imported method "set-authority". // SetAuthority represents the imported method "set-authority".
// //
// Set the HTTP Authority for the Request. A value of `none` may be used
// with Related Schemes which do not require an Authority. The HTTP and
// HTTPS schemes always require an authority. Fails if the string given is
// not a syntactically valid uri authority.
//
// set-authority: func(authority: option<string>) -> result // set-authority: func(authority: option<string>) -> result
// //
//go:nosplit //go:nosplit
@ -1137,6 +1311,9 @@ func (self OutgoingRequest) SetAuthority(authority cm.Option[string]) (result cm
// SetMethod represents the imported method "set-method". // SetMethod represents the imported method "set-method".
// //
// Set the Method for the Request. Fails if the string present in a
// `method.other` argument is not a syntactically valid method.
//
// set-method: func(method: method) -> result // set-method: func(method: method) -> result
// //
//go:nosplit //go:nosplit
@ -1150,6 +1327,10 @@ func (self OutgoingRequest) SetMethod(method Method) (result cm.BoolResult) {
// SetPathWithQuery represents the imported method "set-path-with-query". // SetPathWithQuery represents the imported method "set-path-with-query".
// //
// Set the combination of the HTTP Path and Query for the Request.
// When `none`, this represents an empty Path and empty Query. Fails is the
// string given is not a syntactically valid path and query uri component.
//
// set-path-with-query: func(path-with-query: option<string>) -> result // set-path-with-query: func(path-with-query: option<string>) -> result
// //
//go:nosplit //go:nosplit
@ -1163,6 +1344,10 @@ func (self OutgoingRequest) SetPathWithQuery(pathWithQuery cm.Option[string]) (r
// SetScheme represents the imported method "set-scheme". // SetScheme represents the imported method "set-scheme".
// //
// Set the HTTP Related Scheme for the Request. When `none`, the
// implementation may choose an appropriate default scheme. Fails if the
// string given is not a syntactically valid uri scheme.
//
// set-scheme: func(scheme: option<scheme>) -> result // set-scheme: func(scheme: option<scheme>) -> result
// //
//go:nosplit //go:nosplit
@ -1176,6 +1361,13 @@ func (self OutgoingRequest) SetScheme(scheme cm.Option[Scheme]) (result cm.BoolR
// RequestOptions represents the imported resource "wasi:http/types@0.2.0#request-options". // RequestOptions represents the imported resource "wasi:http/types@0.2.0#request-options".
// //
// Parameters for making an HTTP Request. Each of these parameters is
// currently an optional timeout applicable to the transport layer of the
// HTTP protocol.
//
// These timeouts are separate from any the user may use to bound a
// blocking call to `wasi:io/poll.poll`.
//
// resource request-options // resource request-options
type RequestOptions cm.Resource type RequestOptions cm.Resource
@ -1192,6 +1384,8 @@ func (self RequestOptions) ResourceDrop() {
// NewRequestOptions represents the imported constructor for resource "request-options". // NewRequestOptions represents the imported constructor for resource "request-options".
// //
// Construct a default `request-options` value.
//
// constructor() // constructor()
// //
//go:nosplit //go:nosplit
@ -1203,6 +1397,9 @@ func NewRequestOptions() (result RequestOptions) {
// BetweenBytesTimeout represents the imported method "between-bytes-timeout". // BetweenBytesTimeout represents the imported method "between-bytes-timeout".
// //
// The timeout for receiving subsequent chunks of bytes in the Response
// body stream.
//
// between-bytes-timeout: func() -> option<duration> // between-bytes-timeout: func() -> option<duration>
// //
//go:nosplit //go:nosplit
@ -1214,6 +1411,8 @@ func (self RequestOptions) BetweenBytesTimeout() (result cm.Option[Duration]) {
// ConnectTimeout represents the imported method "connect-timeout". // ConnectTimeout represents the imported method "connect-timeout".
// //
// The timeout for the initial connect to the HTTP Server.
//
// connect-timeout: func() -> option<duration> // connect-timeout: func() -> option<duration>
// //
//go:nosplit //go:nosplit
@ -1225,6 +1424,8 @@ func (self RequestOptions) ConnectTimeout() (result cm.Option[Duration]) {
// FirstByteTimeout represents the imported method "first-byte-timeout". // FirstByteTimeout represents the imported method "first-byte-timeout".
// //
// The timeout for receiving the first byte of the Response body.
//
// first-byte-timeout: func() -> option<duration> // first-byte-timeout: func() -> option<duration>
// //
//go:nosplit //go:nosplit
@ -1236,6 +1437,10 @@ func (self RequestOptions) FirstByteTimeout() (result cm.Option[Duration]) {
// SetBetweenBytesTimeout represents the imported method "set-between-bytes-timeout". // SetBetweenBytesTimeout represents the imported method "set-between-bytes-timeout".
// //
// Set the timeout for receiving subsequent chunks of bytes in the Response
// body stream. An error return value indicates that this timeout is not
// supported.
//
// set-between-bytes-timeout: func(duration: option<duration>) -> result // set-between-bytes-timeout: func(duration: option<duration>) -> result
// //
//go:nosplit //go:nosplit
@ -1249,6 +1454,9 @@ func (self RequestOptions) SetBetweenBytesTimeout(duration cm.Option[Duration])
// SetConnectTimeout represents the imported method "set-connect-timeout". // SetConnectTimeout represents the imported method "set-connect-timeout".
// //
// Set the timeout for the initial connect to the HTTP Server. An error
// return value indicates that this timeout is not supported.
//
// set-connect-timeout: func(duration: option<duration>) -> result // set-connect-timeout: func(duration: option<duration>) -> result
// //
//go:nosplit //go:nosplit
@ -1262,6 +1470,9 @@ func (self RequestOptions) SetConnectTimeout(duration cm.Option[Duration]) (resu
// SetFirstByteTimeout represents the imported method "set-first-byte-timeout". // SetFirstByteTimeout represents the imported method "set-first-byte-timeout".
// //
// Set the timeout for receiving the first byte of the Response body. An
// error return value indicates that this timeout is not supported.
//
// set-first-byte-timeout: func(duration: option<duration>) -> result // set-first-byte-timeout: func(duration: option<duration>) -> result
// //
//go:nosplit //go:nosplit
@ -1275,6 +1486,12 @@ func (self RequestOptions) SetFirstByteTimeout(duration cm.Option[Duration]) (re
// ResponseOutparam represents the imported resource "wasi:http/types@0.2.0#response-outparam". // ResponseOutparam represents the imported resource "wasi:http/types@0.2.0#response-outparam".
// //
// Represents the ability to send an HTTP Response.
//
// This resource is used by the `wasi:http/incoming-handler` interface to
// allow a Response to be sent corresponding to the Request provided as the
// other argument to `incoming-handler.handle`.
//
// resource response-outparam // resource response-outparam
type ResponseOutparam cm.Resource type ResponseOutparam cm.Resource
@ -1291,6 +1508,16 @@ func (self ResponseOutparam) ResourceDrop() {
// ResponseOutparamSet represents the imported static function "set". // ResponseOutparamSet represents the imported static function "set".
// //
// Set the value of the `response-outparam` to either send a response,
// or indicate an error.
//
// This method consumes the `response-outparam` to ensure that it is
// called at most once. If it is never called, the implementation
// will respond with an error.
//
// The user may provide an `error` to `response` to allow the
// implementation determine how to respond with an HTTP error response.
//
// set: static func(param: response-outparam, response: result<outgoing-response, // set: static func(param: response-outparam, response: result<outgoing-response,
// error-code>) // error-code>)
// //
@ -1304,11 +1531,15 @@ func ResponseOutparamSet(param ResponseOutparam, response cm.Result[ErrorCodeSha
// StatusCode represents the u16 "wasi:http/types@0.2.0#status-code". // StatusCode represents the u16 "wasi:http/types@0.2.0#status-code".
// //
// This type corresponds to the HTTP standard Status Code.
//
// type status-code = u16 // type status-code = u16
type StatusCode uint16 type StatusCode uint16
// IncomingResponse represents the imported resource "wasi:http/types@0.2.0#incoming-response". // IncomingResponse represents the imported resource "wasi:http/types@0.2.0#incoming-response".
// //
// Represents an incoming HTTP Response.
//
// resource incoming-response // resource incoming-response
type IncomingResponse cm.Resource type IncomingResponse cm.Resource
@ -1325,6 +1556,9 @@ func (self IncomingResponse) ResourceDrop() {
// Consume represents the imported method "consume". // Consume represents the imported method "consume".
// //
// Returns the incoming body. May be called at most once. Returns error
// if called additional times.
//
// consume: func() -> result<incoming-body> // consume: func() -> result<incoming-body>
// //
//go:nosplit //go:nosplit
@ -1336,6 +1570,14 @@ func (self IncomingResponse) Consume() (result cm.Result[IncomingBody, IncomingB
// Headers represents the imported method "headers". // Headers represents the imported method "headers".
// //
// Returns the headers from the incoming response.
//
// The returned `headers` resource is immutable: `set`, `append`, and
// `delete` operations will fail with `header-error.immutable`.
//
// This headers resource is a child: it must be dropped before the parent
// `incoming-response` is dropped.
//
// headers: func() -> headers // headers: func() -> headers
// //
//go:nosplit //go:nosplit
@ -1348,6 +1590,8 @@ func (self IncomingResponse) Headers() (result Headers) {
// Status represents the imported method "status". // Status represents the imported method "status".
// //
// Returns the status code from the incoming response.
//
// status: func() -> status-code // status: func() -> status-code
// //
//go:nosplit //go:nosplit
@ -1360,6 +1604,15 @@ func (self IncomingResponse) Status() (result StatusCode) {
// IncomingBody represents the imported resource "wasi:http/types@0.2.0#incoming-body". // IncomingBody represents the imported resource "wasi:http/types@0.2.0#incoming-body".
// //
// Represents an incoming HTTP Request or Response's Body.
//
// A body has both its contents - a stream of bytes - and a (possibly
// empty) set of trailers, indicating that the full contents of the
// body have been received. This resource represents the contents as
// an `input-stream` and the delivery of trailers as a `future-trailers`,
// and ensures that the user of this interface may only be consuming either
// the body contents or waiting on trailers at any given time.
//
// resource incoming-body // resource incoming-body
type IncomingBody cm.Resource type IncomingBody cm.Resource
@ -1376,6 +1629,9 @@ func (self IncomingBody) ResourceDrop() {
// IncomingBodyFinish represents the imported static function "finish". // IncomingBodyFinish represents the imported static function "finish".
// //
// Takes ownership of `incoming-body`, and returns a `future-trailers`.
// This function will trap if the `input-stream` child is still alive.
//
// finish: static func(this: incoming-body) -> future-trailers // finish: static func(this: incoming-body) -> future-trailers
// //
//go:nosplit //go:nosplit
@ -1388,6 +1644,22 @@ func IncomingBodyFinish(this IncomingBody) (result FutureTrailers) {
// Stream represents the imported method "stream". // Stream represents the imported method "stream".
// //
// Returns the contents of the body, as a stream of bytes.
//
// Returns success on first call: the stream representing the contents
// can be retrieved at most once. Subsequent calls will return error.
//
// The returned `input-stream` resource is a child: it must be dropped
// before the parent `incoming-body` is dropped, or consumed by
// `incoming-body.finish`.
//
// This invariant ensures that the implementation can determine whether
// the user is consuming the contents of the body, waiting on the
// `future-trailers` to be ready, or neither. This allows for network
// backpressure is to be applied when the user is consuming the body,
// and for that backpressure to not inhibit delivery of the trailers if
// the user does not read the entire body.
//
// %stream: func() -> result<input-stream> // %stream: func() -> result<input-stream>
// //
//go:nosplit //go:nosplit
@ -1399,6 +1671,12 @@ func (self IncomingBody) Stream() (result cm.Result[InputStream, InputStream, st
// FutureTrailers represents the imported resource "wasi:http/types@0.2.0#future-trailers". // FutureTrailers represents the imported resource "wasi:http/types@0.2.0#future-trailers".
// //
// Represents a future which may eventaully return trailers, or an error.
//
// In the case that the incoming HTTP Request or Response did not have any
// trailers, this future will resolve to the empty set of trailers once the
// complete Request or Response body has been received.
//
// resource future-trailers // resource future-trailers
type FutureTrailers cm.Resource type FutureTrailers cm.Resource
@ -1415,6 +1693,26 @@ func (self FutureTrailers) ResourceDrop() {
// Get represents the imported method "get". // Get represents the imported method "get".
// //
// Returns the contents of the trailers, or an error which occured,
// once the future is ready.
//
// The outer `option` represents future readiness. Users can wait on this
// `option` to become `some` using the `subscribe` method.
//
// The outer `result` is used to retrieve the trailers or error at most
// once. It will be success on the first call in which the outer option
// is `some`, and error on subsequent calls.
//
// The inner `result` represents that either the HTTP Request or Response
// body, as well as any trailers, were received successfully, or that an
// error occured receiving them. The optional `trailers` indicates whether
// or not trailers were present in the body.
//
// When some `trailers` are returned by this method, the `trailers`
// resource is immutable, and a child. Use of the `set`, `append`, or
// `delete` methods will return an error, and the resource must be
// dropped before the parent `future-trailers` is dropped.
//
// get: func() -> option<result<result<option<trailers>, error-code>>> // get: func() -> option<result<result<option<trailers>, error-code>>>
// //
//go:nosplit //go:nosplit
@ -1426,6 +1724,10 @@ func (self FutureTrailers) Get() (result cm.Option[cm.Result[cm.Result[ErrorCode
// Subscribe represents the imported method "subscribe". // Subscribe represents the imported method "subscribe".
// //
// Returns a pollable which becomes ready when either the trailers have
// been received, or an error has occured. When this pollable is ready,
// the `get` method will return `some`.
//
// subscribe: func() -> pollable // subscribe: func() -> pollable
// //
//go:nosplit //go:nosplit
@ -1438,6 +1740,8 @@ func (self FutureTrailers) Subscribe() (result Pollable) {
// OutgoingResponse represents the imported resource "wasi:http/types@0.2.0#outgoing-response". // OutgoingResponse represents the imported resource "wasi:http/types@0.2.0#outgoing-response".
// //
// Represents an outgoing HTTP Response.
//
// resource outgoing-response // resource outgoing-response
type OutgoingResponse cm.Resource type OutgoingResponse cm.Resource
@ -1454,6 +1758,12 @@ func (self OutgoingResponse) ResourceDrop() {
// NewOutgoingResponse represents the imported constructor for resource "outgoing-response". // NewOutgoingResponse represents the imported constructor for resource "outgoing-response".
// //
// Construct an `outgoing-response`, with a default `status-code` of `200`.
// If a different `status-code` is needed, it must be set via the
// `set-status-code` method.
//
// * `headers` is the HTTP Headers for the Response.
//
// constructor(headers: headers) // constructor(headers: headers)
// //
//go:nosplit //go:nosplit
@ -1466,6 +1776,12 @@ func NewOutgoingResponse(headers Headers) (result OutgoingResponse) {
// Body represents the imported method "body". // Body represents the imported method "body".
// //
// Returns the resource corresponding to the outgoing Body for this Response.
//
// Returns success on the first call: the `outgoing-body` resource for
// this `outgoing-response` can be retrieved at most once. Subsequent
// calls will return error.
//
// body: func() -> result<outgoing-body> // body: func() -> result<outgoing-body>
// //
//go:nosplit //go:nosplit
@ -1477,6 +1793,15 @@ func (self OutgoingResponse) Body() (result cm.Result[OutgoingBody, OutgoingBody
// Headers represents the imported method "headers". // Headers represents the imported method "headers".
// //
// Get the headers associated with the Request.
//
// The returned `headers` resource is immutable: `set`, `append`, and
// `delete` operations will fail with `header-error.immutable`.
//
// This headers resource is a child: it must be dropped before the parent
// `outgoing-request` is dropped, or its ownership is transfered to
// another component by e.g. `outgoing-handler.handle`.
//
// headers: func() -> headers // headers: func() -> headers
// //
//go:nosplit //go:nosplit
@ -1489,6 +1814,9 @@ func (self OutgoingResponse) Headers() (result Headers) {
// SetStatusCode represents the imported method "set-status-code". // SetStatusCode represents the imported method "set-status-code".
// //
// Set the HTTP Status Code for the Response. Fails if the status-code
// given is not a valid http status code.
//
// set-status-code: func(status-code: status-code) -> result // set-status-code: func(status-code: status-code) -> result
// //
//go:nosplit //go:nosplit
@ -1502,6 +1830,8 @@ func (self OutgoingResponse) SetStatusCode(statusCode StatusCode) (result cm.Boo
// StatusCode represents the imported method "status-code". // StatusCode represents the imported method "status-code".
// //
// Get the HTTP Status Code for the Response.
//
// status-code: func() -> status-code // status-code: func() -> status-code
// //
//go:nosplit //go:nosplit
@ -1514,6 +1844,23 @@ func (self OutgoingResponse) StatusCode() (result StatusCode) {
// OutgoingBody represents the imported resource "wasi:http/types@0.2.0#outgoing-body". // OutgoingBody represents the imported resource "wasi:http/types@0.2.0#outgoing-body".
// //
// Represents an outgoing HTTP Request or Response's Body.
//
// A body has both its contents - a stream of bytes - and a (possibly
// empty) set of trailers, inducating the full contents of the body
// have been sent. This resource represents the contents as an
// `output-stream` child resource, and the completion of the body (with
// optional trailers) with a static function that consumes the
// `outgoing-body` resource, and ensures that the user of this interface
// may not write to the body contents after the body has been finished.
//
// If the user code drops this resource, as opposed to calling the static
// method `finish`, the implementation should treat the body as incomplete,
// and that an error has occured. The implementation should propogate this
// error to the HTTP protocol by whatever means it has available,
// including: corrupting the body on the wire, aborting the associated
// Request, or sending a late status code for the Response.
//
// resource outgoing-body // resource outgoing-body
type OutgoingBody cm.Resource type OutgoingBody cm.Resource
@ -1530,6 +1877,16 @@ func (self OutgoingBody) ResourceDrop() {
// OutgoingBodyFinish represents the imported static function "finish". // OutgoingBodyFinish represents the imported static function "finish".
// //
// Finalize an outgoing body, optionally providing trailers. This must be
// called to signal that the response is complete. If the `outgoing-body`
// is dropped without calling `outgoing-body.finalize`, the implementation
// should treat the body as corrupted.
//
// Fails if the body's `outgoing-request` or `outgoing-response` was
// constructed with a Content-Length header, and the contents written
// to the body (via `write`) does not match the value given in the
// Content-Length.
//
// finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_, // finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_,
// error-code> // error-code>
// //
@ -1543,6 +1900,16 @@ func OutgoingBodyFinish(this OutgoingBody, trailers cm.Option[Trailers]) (result
// Write represents the imported method "write". // Write represents the imported method "write".
// //
// Returns a stream for writing the body contents.
//
// The returned `output-stream` is a child resource: it must be dropped
// before the parent `outgoing-body` resource is dropped (or finished),
// otherwise the `outgoing-body` drop or `finish` will trap.
//
// Returns success on the first call: the `output-stream` resource for
// this `outgoing-body` may be retrieved at most once. Subsequent calls
// will return error.
//
// write: func() -> result<output-stream> // write: func() -> result<output-stream>
// //
//go:nosplit //go:nosplit
@ -1554,6 +1921,12 @@ func (self OutgoingBody) Write() (result cm.Result[OutputStream, OutputStream, s
// FutureIncomingResponse represents the imported resource "wasi:http/types@0.2.0#future-incoming-response". // FutureIncomingResponse represents the imported resource "wasi:http/types@0.2.0#future-incoming-response".
// //
// Represents a future which may eventaully return an incoming HTTP
// Response, or an error.
//
// This resource is returned by the `wasi:http/outgoing-handler` interface to
// provide the HTTP Response corresponding to the sent Request.
//
// resource future-incoming-response // resource future-incoming-response
type FutureIncomingResponse cm.Resource type FutureIncomingResponse cm.Resource
@ -1570,6 +1943,21 @@ func (self FutureIncomingResponse) ResourceDrop() {
// Get represents the imported method "get". // Get represents the imported method "get".
// //
// Returns the incoming HTTP Response, or an error, once one is ready.
//
// The outer `option` represents future readiness. Users can wait on this
// `option` to become `some` using the `subscribe` method.
//
// The outer `result` is used to retrieve the response or error at most
// once. It will be success on the first call in which the outer option
// is `some`, and error on subsequent calls.
//
// The inner `result` represents that either the incoming HTTP Response
// status and headers have recieved successfully, or that an error
// occured. Errors may also occur while consuming the response body,
// but those will be reported by the `incoming-body` and its
// `output-stream` child.
//
// get: func() -> option<result<result<incoming-response, error-code>>> // get: func() -> option<result<result<incoming-response, error-code>>>
// //
//go:nosplit //go:nosplit
@ -1581,6 +1969,10 @@ func (self FutureIncomingResponse) Get() (result cm.Option[cm.Result[cm.Result[E
// Subscribe represents the imported method "subscribe". // Subscribe represents the imported method "subscribe".
// //
// Returns a pollable which becomes ready when either the Response has
// been received, or an error has occured. When this pollable is ready,
// the `get` method will return `some`.
//
// subscribe: func() -> pollable // subscribe: func() -> pollable
// //
//go:nosplit //go:nosplit
@ -1593,6 +1985,18 @@ func (self FutureIncomingResponse) Subscribe() (result Pollable) {
// HTTPErrorCode represents the imported function "http-error-code". // HTTPErrorCode represents the imported function "http-error-code".
// //
// Attempts to extract a http-related `error` from the wasi:io `error`
// provided.
//
// Stream operations which return
// `wasi:io/stream/stream-error::last-operation-failed` have a payload of
// type `wasi:io/error/error` with more information about the operation
// that failed. This payload can be passed through to this function to see
// if there's http-related information about the error to return.
//
// Note that this function is fallible because not all io-errors are
// http-related errors.
//
// http-error-code: func(err: borrow<io-error>) -> option<error-code> // http-error-code: func(err: borrow<io-error>) -> option<error-code>
// //
//go:nosplit //go:nosplit

View File

@ -38,77 +38,8 @@ package wasmcloud:hello {
import wasi:random/random@0.2.0; import wasi:random/random@0.2.0;
import wasi:random/insecure@0.2.0; import wasi:random/insecure@0.2.0;
import wasi:random/insecure-seed@0.2.0; import wasi:random/insecure-seed@0.2.0;
} export wasi:http/incoming-handler@0.2.0;
} export wasmcloud:messaging/handler@0.2.0;
package wasi:cli@0.2.0 {
interface environment {
get-environment: func() -> list<tuple<string, string>>;
get-arguments: func() -> list<string>;
initial-cwd: func() -> option<string>;
}
interface exit {
exit: func(status: result);
}
interface stdin {
use wasi:io/streams@0.2.0.{input-stream};
get-stdin: func() -> input-stream;
}
interface stdout {
use wasi:io/streams@0.2.0.{output-stream};
get-stdout: func() -> output-stream;
}
interface stderr {
use wasi:io/streams@0.2.0.{output-stream};
get-stderr: func() -> output-stream;
}
interface terminal-input {
resource terminal-input;
}
interface terminal-output {
resource terminal-output;
}
interface terminal-stdin {
use terminal-input.{terminal-input};
get-terminal-stdin: func() -> option<terminal-input>;
}
interface terminal-stdout {
use terminal-output.{terminal-output};
get-terminal-stdout: func() -> option<terminal-output>;
}
interface terminal-stderr {
use terminal-output.{terminal-output};
get-terminal-stderr: func() -> option<terminal-output>;
}
}
package wasi:clocks@0.2.0 {
interface monotonic-clock {
use wasi:io/poll@0.2.0.{pollable};
type instant = u64;
type duration = u64;
now: func() -> instant;
resolution: func() -> duration;
subscribe-instant: func(when: instant) -> pollable;
subscribe-duration: func(when: duration) -> pollable;
}
interface wall-clock {
record datetime {
seconds: u64,
nanoseconds: u32,
}
now: func() -> datetime;
resolution: func() -> datetime;
} }
} }
@ -282,12 +213,17 @@ package wasi:filesystem@0.2.0 {
} }
package wasi:http@0.2.0 { package wasi:http@0.2.0 {
/// This interface defines all of the types and methods for implementing
/// HTTP Requests and Responses, both incoming and outgoing, as well as
/// their headers, trailers, and bodies.
interface types { interface types {
use wasi:clocks/monotonic-clock@0.2.0.{duration}; use wasi:clocks/monotonic-clock@0.2.0.{duration};
use wasi:io/streams@0.2.0.{input-stream}; use wasi:io/streams@0.2.0.{input-stream};
use wasi:io/streams@0.2.0.{output-stream}; use wasi:io/streams@0.2.0.{output-stream};
use wasi:io/error@0.2.0.{error as io-error}; use wasi:io/error@0.2.0.{error as io-error};
use wasi:io/poll@0.2.0.{pollable}; use wasi:io/poll@0.2.0.{pollable};
/// This type corresponds to HTTP standard Methods.
variant method { variant method {
get, get,
head, head,
@ -300,19 +236,30 @@ package wasi:http@0.2.0 {
patch, patch,
other(string), other(string),
} }
/// This type corresponds to HTTP standard Related Schemes.
variant scheme { HTTP, HTTPS, other(string) } variant scheme { HTTP, HTTPS, other(string) }
/// Defines the case payload type for `DNS-error` above:
record DNS-error-payload { record DNS-error-payload {
rcode: option<string>, rcode: option<string>,
info-code: option<u16>, info-code: option<u16>,
} }
/// Defines the case payload type for `TLS-alert-received` above:
record TLS-alert-received-payload { record TLS-alert-received-payload {
alert-id: option<u8>, alert-id: option<u8>,
alert-message: option<string>, alert-message: option<string>,
} }
/// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
record field-size-payload { record field-size-payload {
field-name: option<string>, field-name: option<string>,
field-size: option<u32>, field-size: option<u32>,
} }
/// These cases are inspired by the IANA HTTP Proxy Error Types:
/// https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types
variant error-code { variant error-code {
DNS-timeout, DNS-timeout,
DNS-error(DNS-error-payload), DNS-error(DNS-error-payload),
@ -352,102 +299,568 @@ package wasi:http@0.2.0 {
HTTP-protocol-error, HTTP-protocol-error,
loop-detected, loop-detected,
configuration-error, configuration-error,
/// This is a catch-all error for anything that doesn't fit cleanly into a
/// more specific case. It also includes an optional string for an
/// unstructured description of the error. Users should not depend on the
/// string for diagnosing errors, as it's not required to be consistent
/// between implementations.
internal-error(option<string>), internal-error(option<string>),
} }
/// This type enumerates the different kinds of errors that may occur when
/// setting or appending to a `fields` resource.
variant header-error { variant header-error {
/// This error indicates that a `field-key` or `field-value` was
/// syntactically invalid when used with an operation that sets headers in a
/// `fields`.
invalid-syntax, invalid-syntax,
/// This error indicates that a forbidden `field-key` was used when trying
/// to set a header in a `fields`.
forbidden, forbidden,
/// This error indicates that the operation on the `fields` was not
/// permitted because the fields are immutable.
immutable, immutable,
} }
/// Field keys are always strings.
type field-key = string; type field-key = string;
/// Field values should always be ASCII strings. However, in
/// reality, HTTP implementations often have to interpret malformed values,
/// so they are provided as a list of bytes.
type field-value = list<u8>; type field-value = list<u8>;
/// This following block defines the `fields` resource which corresponds to
/// HTTP standard Fields. Fields are a common representation used for both
/// Headers and Trailers.
///
/// A `fields` may be mutable or immutable. A `fields` created using the
/// constructor, `from-list`, or `clone` will be mutable, but a `fields`
/// resource given by other means (including, but not limited to,
/// `incoming-request.headers`, `outgoing-request.headers`) might be be
/// immutable. In an immutable fields, the `set`, `append`, and `delete`
/// operations will fail with `header-error.immutable`.
resource fields { resource fields {
/// Construct an empty HTTP Fields.
///
/// The resulting `fields` is mutable.
constructor(); constructor();
/// Append a value for a key. Does not change or delete any existing
/// values for that key.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
append: func(name: field-key, value: field-value) -> result<_, header-error>; append: func(name: field-key, value: field-value) -> result<_, header-error>;
/// Make a deep copy of the Fields. Equivelant in behavior to calling the
/// `fields` constructor on the return value of `entries`. The resulting
/// `fields` is mutable.
clone: func() -> fields; clone: func() -> fields;
/// Delete all values for a key. Does nothing if no values for the key
/// exist.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
delete: func(name: field-key) -> result<_, header-error>; delete: func(name: field-key) -> result<_, header-error>;
/// Retrieve the full set of keys and values in the Fields. Like the
/// constructor, the list represents each key-value pair.
///
/// The outer list represents each key-value pair in the Fields. Keys
/// which have multiple values are represented by multiple entries in this
/// list with the same key.
entries: func() -> list<tuple<field-key, field-value>>; entries: func() -> list<tuple<field-key, field-value>>;
/// Get all of the values corresponding to a key. If the key is not present
/// in this `fields`, an empty list is returned. However, if the key is
/// present but empty, this is represented by a list with one or more
/// empty field-values present.
get: func(name: field-key) -> list<field-value>; get: func(name: field-key) -> list<field-value>;
/// Returns `true` when the key is present in this `fields`. If the key is
/// syntactically invalid, `false` is returned.
has: func(name: field-key) -> bool; has: func(name: field-key) -> bool;
/// Set all of the values for a key. Clears any existing values for that
/// key, if they have been set.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
set: func(name: field-key, value: list<field-value>) -> result<_, header-error>; set: func(name: field-key, value: list<field-value>) -> result<_, header-error>;
/// Construct an HTTP Fields.
///
/// The resulting `fields` is mutable.
///
/// The list represents each key-value pair in the Fields. Keys
/// which have multiple values are represented by multiple entries in this
/// list with the same key.
///
/// The tuple is a pair of the field key, represented as a string, and
/// Value, represented as a list of bytes. In a valid Fields, all keys
/// and values are valid UTF-8 strings. However, values are not always
/// well-formed, so they are represented as a raw list of bytes.
///
/// An error result will be returned if any header or value was
/// syntactically invalid, or if a header was forbidden.
from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields, header-error>; from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields, header-error>;
} }
/// Headers is an alias for Fields.
type headers = fields; type headers = fields;
/// Trailers is an alias for Fields.
type trailers = fields; type trailers = fields;
/// Represents an incoming HTTP Request.
resource incoming-request { resource incoming-request {
/// Returns the authority from the request, if it was present.
authority: func() -> option<string>; authority: func() -> option<string>;
/// Gives the `incoming-body` associated with this request. Will only
/// return success at most once, and subsequent calls will return error.
consume: func() -> result<incoming-body>; consume: func() -> result<incoming-body>;
/// Get the `headers` associated with the request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// The `headers` returned are a child resource: it must be dropped before
/// the parent `incoming-request` is dropped. Dropping this
/// `incoming-request` before all children are dropped will trap.
headers: func() -> headers; headers: func() -> headers;
/// Returns the method of the incoming request.
method: func() -> method; method: func() -> method;
/// Returns the path with query parameters from the request, as a string.
path-with-query: func() -> option<string>; path-with-query: func() -> option<string>;
/// Returns the protocol scheme from the request.
scheme: func() -> option<scheme>; scheme: func() -> option<scheme>;
} }
/// Represents an outgoing HTTP Request.
resource outgoing-request { resource outgoing-request {
/// Construct a new `outgoing-request` with a default `method` of `GET`, and
/// `none` values for `path-with-query`, `scheme`, and `authority`.
///
/// * `headers` is the HTTP Headers for the Request.
///
/// It is possible to construct, or manipulate with the accessor functions
/// below, an `outgoing-request` with an invalid combination of `scheme`
/// and `authority`, or `headers` which are not permitted to be sent.
/// It is the obligation of the `outgoing-handler.handle` implementation
/// to reject invalid constructions of `outgoing-request`.
constructor(headers: headers); constructor(headers: headers);
/// Get the HTTP Authority for the Request. A value of `none` may be used
/// with Related Schemes which do not require an Authority. The HTTP and
/// HTTPS schemes always require an authority.
authority: func() -> option<string>; authority: func() -> option<string>;
/// Returns the resource corresponding to the outgoing Body for this
/// Request.
///
/// Returns success on the first call: the `outgoing-body` resource for
/// this `outgoing-request` can be retrieved at most once. Subsequent
/// calls will return error.
body: func() -> result<outgoing-body>; body: func() -> result<outgoing-body>;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `outgoing-request` is dropped, or its ownership is transfered to
/// another component by e.g. `outgoing-handler.handle`.
headers: func() -> headers; headers: func() -> headers;
/// Get the Method for the Request.
method: func() -> method; method: func() -> method;
/// Get the combination of the HTTP Path and Query for the Request.
/// When `none`, this represents an empty Path and empty Query.
path-with-query: func() -> option<string>; path-with-query: func() -> option<string>;
/// Get the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme.
scheme: func() -> option<scheme>; scheme: func() -> option<scheme>;
/// Set the HTTP Authority for the Request. A value of `none` may be used
/// with Related Schemes which do not require an Authority. The HTTP and
/// HTTPS schemes always require an authority. Fails if the string given is
/// not a syntactically valid uri authority.
set-authority: func(authority: option<string>) -> result; set-authority: func(authority: option<string>) -> result;
/// Set the Method for the Request. Fails if the string present in a
/// `method.other` argument is not a syntactically valid method.
set-method: func(method: method) -> result; set-method: func(method: method) -> result;
/// Set the combination of the HTTP Path and Query for the Request.
/// When `none`, this represents an empty Path and empty Query. Fails is the
/// string given is not a syntactically valid path and query uri component.
set-path-with-query: func(path-with-query: option<string>) -> result; set-path-with-query: func(path-with-query: option<string>) -> result;
/// Set the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme. Fails if the
/// string given is not a syntactically valid uri scheme.
set-scheme: func(scheme: option<scheme>) -> result; set-scheme: func(scheme: option<scheme>) -> result;
} }
/// Parameters for making an HTTP Request. Each of these parameters is
/// currently an optional timeout applicable to the transport layer of the
/// HTTP protocol.
///
/// These timeouts are separate from any the user may use to bound a
/// blocking call to `wasi:io/poll.poll`.
resource request-options { resource request-options {
/// Construct a default `request-options` value.
constructor(); constructor();
/// The timeout for receiving subsequent chunks of bytes in the Response
/// body stream.
between-bytes-timeout: func() -> option<duration>; between-bytes-timeout: func() -> option<duration>;
/// The timeout for the initial connect to the HTTP Server.
connect-timeout: func() -> option<duration>; connect-timeout: func() -> option<duration>;
/// The timeout for receiving the first byte of the Response body.
first-byte-timeout: func() -> option<duration>; first-byte-timeout: func() -> option<duration>;
/// Set the timeout for receiving subsequent chunks of bytes in the Response
/// body stream. An error return value indicates that this timeout is not
/// supported.
set-between-bytes-timeout: func(duration: option<duration>) -> result; set-between-bytes-timeout: func(duration: option<duration>) -> result;
/// Set the timeout for the initial connect to the HTTP Server. An error
/// return value indicates that this timeout is not supported.
set-connect-timeout: func(duration: option<duration>) -> result; set-connect-timeout: func(duration: option<duration>) -> result;
/// Set the timeout for receiving the first byte of the Response body. An
/// error return value indicates that this timeout is not supported.
set-first-byte-timeout: func(duration: option<duration>) -> result; set-first-byte-timeout: func(duration: option<duration>) -> result;
} }
/// Represents the ability to send an HTTP Response.
///
/// This resource is used by the `wasi:http/incoming-handler` interface to
/// allow a Response to be sent corresponding to the Request provided as the
/// other argument to `incoming-handler.handle`.
resource response-outparam { resource response-outparam {
/// Set the value of the `response-outparam` to either send a response,
/// or indicate an error.
///
/// This method consumes the `response-outparam` to ensure that it is
/// called at most once. If it is never called, the implementation
/// will respond with an error.
///
/// The user may provide an `error` to `response` to allow the
/// implementation determine how to respond with an HTTP error response.
set: static func(param: response-outparam, response: result<outgoing-response, error-code>); set: static func(param: response-outparam, response: result<outgoing-response, error-code>);
} }
/// This type corresponds to the HTTP standard Status Code.
type status-code = u16; type status-code = u16;
/// Represents an incoming HTTP Response.
resource incoming-response { resource incoming-response {
/// Returns the incoming body. May be called at most once. Returns error
/// if called additional times.
consume: func() -> result<incoming-body>; consume: func() -> result<incoming-body>;
/// Returns the headers from the incoming response.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `incoming-response` is dropped.
headers: func() -> headers; headers: func() -> headers;
/// Returns the status code from the incoming response.
status: func() -> status-code; status: func() -> status-code;
} }
/// Represents an incoming HTTP Request or Response's Body.
///
/// A body has both its contents - a stream of bytes - and a (possibly
/// empty) set of trailers, indicating that the full contents of the
/// body have been received. This resource represents the contents as
/// an `input-stream` and the delivery of trailers as a `future-trailers`,
/// and ensures that the user of this interface may only be consuming either
/// the body contents or waiting on trailers at any given time.
resource incoming-body { resource incoming-body {
/// Returns the contents of the body, as a stream of bytes.
///
/// Returns success on first call: the stream representing the contents
/// can be retrieved at most once. Subsequent calls will return error.
///
/// The returned `input-stream` resource is a child: it must be dropped
/// before the parent `incoming-body` is dropped, or consumed by
/// `incoming-body.finish`.
///
/// This invariant ensures that the implementation can determine whether
/// the user is consuming the contents of the body, waiting on the
/// `future-trailers` to be ready, or neither. This allows for network
/// backpressure is to be applied when the user is consuming the body,
/// and for that backpressure to not inhibit delivery of the trailers if
/// the user does not read the entire body.
%stream: func() -> result<input-stream>; %stream: func() -> result<input-stream>;
/// Takes ownership of `incoming-body`, and returns a `future-trailers`.
/// This function will trap if the `input-stream` child is still alive.
finish: static func(this: incoming-body) -> future-trailers; finish: static func(this: incoming-body) -> future-trailers;
} }
/// Represents a future which may eventaully return trailers, or an error.
///
/// In the case that the incoming HTTP Request or Response did not have any
/// trailers, this future will resolve to the empty set of trailers once the
/// complete Request or Response body has been received.
resource future-trailers { resource future-trailers {
/// Returns the contents of the trailers, or an error which occured,
/// once the future is ready.
///
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The outer `result` is used to retrieve the trailers or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the HTTP Request or Response
/// body, as well as any trailers, were received successfully, or that an
/// error occured receiving them. The optional `trailers` indicates whether
/// or not trailers were present in the body.
///
/// When some `trailers` are returned by this method, the `trailers`
/// resource is immutable, and a child. Use of the `set`, `append`, or
/// `delete` methods will return an error, and the resource must be
/// dropped before the parent `future-trailers` is dropped.
get: func() -> option<result<result<option<trailers>, error-code>>>; get: func() -> option<result<result<option<trailers>, error-code>>>;
/// Returns a pollable which becomes ready when either the trailers have
/// been received, or an error has occured. When this pollable is ready,
/// the `get` method will return `some`.
subscribe: func() -> pollable; subscribe: func() -> pollable;
} }
/// Represents an outgoing HTTP Response.
resource outgoing-response { resource outgoing-response {
/// Construct an `outgoing-response`, with a default `status-code` of `200`.
/// If a different `status-code` is needed, it must be set via the
/// `set-status-code` method.
///
/// * `headers` is the HTTP Headers for the Response.
constructor(headers: headers); constructor(headers: headers);
/// Returns the resource corresponding to the outgoing Body for this Response.
///
/// Returns success on the first call: the `outgoing-body` resource for
/// this `outgoing-response` can be retrieved at most once. Subsequent
/// calls will return error.
body: func() -> result<outgoing-body>; body: func() -> result<outgoing-body>;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `outgoing-request` is dropped, or its ownership is transfered to
/// another component by e.g. `outgoing-handler.handle`.
headers: func() -> headers; headers: func() -> headers;
/// Set the HTTP Status Code for the Response. Fails if the status-code
/// given is not a valid http status code.
set-status-code: func(status-code: status-code) -> result; set-status-code: func(status-code: status-code) -> result;
/// Get the HTTP Status Code for the Response.
status-code: func() -> status-code; status-code: func() -> status-code;
} }
/// Represents an outgoing HTTP Request or Response's Body.
///
/// A body has both its contents - a stream of bytes - and a (possibly
/// empty) set of trailers, inducating the full contents of the body
/// have been sent. This resource represents the contents as an
/// `output-stream` child resource, and the completion of the body (with
/// optional trailers) with a static function that consumes the
/// `outgoing-body` resource, and ensures that the user of this interface
/// may not write to the body contents after the body has been finished.
///
/// If the user code drops this resource, as opposed to calling the static
/// method `finish`, the implementation should treat the body as incomplete,
/// and that an error has occured. The implementation should propogate this
/// error to the HTTP protocol by whatever means it has available,
/// including: corrupting the body on the wire, aborting the associated
/// Request, or sending a late status code for the Response.
resource outgoing-body { resource outgoing-body {
/// Returns a stream for writing the body contents.
///
/// The returned `output-stream` is a child resource: it must be dropped
/// before the parent `outgoing-body` resource is dropped (or finished),
/// otherwise the `outgoing-body` drop or `finish` will trap.
///
/// Returns success on the first call: the `output-stream` resource for
/// this `outgoing-body` may be retrieved at most once. Subsequent calls
/// will return error.
write: func() -> result<output-stream>; write: func() -> result<output-stream>;
/// Finalize an outgoing body, optionally providing trailers. This must be
/// called to signal that the response is complete. If the `outgoing-body`
/// is dropped without calling `outgoing-body.finalize`, the implementation
/// should treat the body as corrupted.
///
/// Fails if the body's `outgoing-request` or `outgoing-response` was
/// constructed with a Content-Length header, and the contents written
/// to the body (via `write`) does not match the value given in the
/// Content-Length.
finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_, error-code>; finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_, error-code>;
} }
/// Represents a future which may eventaully return an incoming HTTP
/// Response, or an error.
///
/// This resource is returned by the `wasi:http/outgoing-handler` interface to
/// provide the HTTP Response corresponding to the sent Request.
resource future-incoming-response { resource future-incoming-response {
/// Returns the incoming HTTP Response, or an error, once one is ready.
///
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The outer `result` is used to retrieve the response or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the incoming HTTP Response
/// status and headers have recieved successfully, or that an error
/// occured. Errors may also occur while consuming the response body,
/// but those will be reported by the `incoming-body` and its
/// `output-stream` child.
get: func() -> option<result<result<incoming-response, error-code>>>; get: func() -> option<result<result<incoming-response, error-code>>>;
/// Returns a pollable which becomes ready when either the Response has
/// been received, or an error has occured. When this pollable is ready,
/// the `get` method will return `some`.
subscribe: func() -> pollable; subscribe: func() -> pollable;
} }
/// Attempts to extract a http-related `error` from the wasi:io `error`
/// provided.
///
/// Stream operations which return
/// `wasi:io/stream/stream-error::last-operation-failed` have a payload of
/// type `wasi:io/error/error` with more information about the operation
/// that failed. This payload can be passed through to this function to see
/// if there's http-related information about the error to return.
///
/// Note that this function is fallible because not all io-errors are
/// http-related errors.
http-error-code: func(err: borrow<io-error>) -> option<error-code>; http-error-code: func(err: borrow<io-error>) -> option<error-code>;
} }
/// This interface defines a handler of incoming HTTP Requests. It should
/// be exported by components which can respond to HTTP Requests.
interface incoming-handler {
use types.{incoming-request};
use types.{response-outparam};
/// This function is invoked with an incoming HTTP Request, and a resource
/// `response-outparam` which provides the capability to reply with an HTTP
/// Response. The response is sent by calling the `response-outparam.set`
/// method, which allows execution to continue after the response has been
/// sent. This enables both streaming to the response body, and performing other
/// work.
///
/// The implementor of this function must write a response to the
/// `response-outparam` before returning, or else the caller will respond
/// with an error on its behalf.
handle: func(request: incoming-request, response-out: response-outparam);
}
/// This interface defines a handler of outgoing HTTP Requests. It should be
/// imported by components which wish to make HTTP Requests.
interface outgoing-handler { interface outgoing-handler {
use types.{outgoing-request}; use types.{outgoing-request};
use types.{request-options}; use types.{request-options};
use types.{future-incoming-response}; use types.{future-incoming-response};
use types.{error-code}; use types.{error-code};
/// This function is invoked with an outgoing HTTP Request, and it returns
/// a resource `future-incoming-response` which represents an HTTP Response
/// which may arrive in the future.
///
/// The `options` argument accepts optional parameters for the HTTP
/// protocol's transport layer.
///
/// This function may return an error if the `outgoing-request` is invalid
/// or not allowed to be made. Otherwise, protocol errors are reported
/// through the `future-incoming-response`.
handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response, error-code>; handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response, error-code>;
} }
} }
package wasi:cli@0.2.0 {
interface stdout {
use wasi:io/streams@0.2.0.{output-stream};
get-stdout: func() -> output-stream;
}
interface stderr {
use wasi:io/streams@0.2.0.{output-stream};
get-stderr: func() -> output-stream;
}
interface stdin {
use wasi:io/streams@0.2.0.{input-stream};
get-stdin: func() -> input-stream;
}
interface environment {
get-environment: func() -> list<tuple<string, string>>;
get-arguments: func() -> list<string>;
initial-cwd: func() -> option<string>;
}
interface exit {
exit: func(status: result);
}
interface terminal-input {
resource terminal-input;
}
interface terminal-output {
resource terminal-output;
}
interface terminal-stdin {
use terminal-input.{terminal-input};
get-terminal-stdin: func() -> option<terminal-input>;
}
interface terminal-stdout {
use terminal-output.{terminal-output};
get-terminal-stdout: func() -> option<terminal-output>;
}
interface terminal-stderr {
use terminal-output.{terminal-output};
get-terminal-stderr: func() -> option<terminal-output>;
}
}
package wasi:io@0.2.0 { package wasi:io@0.2.0 {
interface poll { interface poll {
resource pollable { resource pollable {
@ -706,6 +1119,27 @@ package wasi:sockets@0.2.0 {
} }
} }
package wasi:clocks@0.2.0 {
interface monotonic-clock {
use wasi:io/poll@0.2.0.{pollable};
type instant = u64;
type duration = u64;
now: func() -> instant;
resolution: func() -> duration;
subscribe-instant: func(when: instant) -> pollable;
subscribe-duration: func(when: duration) -> pollable;
}
interface wall-clock {
record datetime {
seconds: u64,
nanoseconds: u32,
}
now: func() -> datetime;
resolution: func() -> datetime;
}
}
package wasmcloud:bus@1.0.0 { package wasmcloud:bus@1.0.0 {
interface lattice { interface lattice {
resource call-target-interface { resource call-target-interface {
@ -726,6 +1160,13 @@ package wasmcloud:messaging@0.2.0 {
} }
} }
interface handler {
use types.{broker-message};
/// Callback handled to invoke a function when a message is received from a subscription
handle-message: func(msg: broker-message) -> result<_, string>;
}
interface consumer { interface consumer {
use types.{broker-message}; use types.{broker-message};

View File

@ -0,0 +1,22 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package handler
import (
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/types"
"github.com/bytecodealliance/wasm-tools-go/cm"
)
func lift_OptionString(f0 uint32, f1 *uint8, f2 uint32) (v cm.Option[string]) {
if f0 == 0 {
return
}
return (cm.Option[string])(cm.Some[string](cm.LiftString[string]((*uint8)(f1), (uint32)(f2))))
}
func lift_BrokerMessage(f0 *uint8, f1 uint32, f2 *uint8, f3 uint32, f4 uint32, f5 *uint8, f6 uint32) (v types.BrokerMessage) {
v.Subject = cm.LiftString[string](f0, f1)
v.Body = cm.LiftList[cm.List[uint8]](f2, f3)
v.ReplyTo = lift_OptionString(f4, f5, f6)
return
}

View File

@ -0,0 +1,3 @@
// This file exists for testing this package without WebAssembly,
// allowing empty function bodies with a //go:wasmimport directive.
// See https://pkg.go.dev/cmd/compile for more information.

View File

@ -0,0 +1,17 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package handler
import (
"github.com/bytecodealliance/wasm-tools-go/cm"
)
// Exports represents the caller-defined exports from "wasmcloud:messaging/handler@0.2.0".
var Exports struct {
// HandleMessage represents the caller-defined, exported function "handle-message".
//
// Callback handled to invoke a function when a message is received from a subscription
//
// handle-message: func(msg: broker-message) -> result<_, string>
HandleMessage func(msg BrokerMessage) (result cm.Result[string, struct{}, string])
}

View File

@ -0,0 +1,18 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
package handler
import (
"github.com/bytecodealliance/wasm-tools-go/cm"
)
// This file contains wasmimport and wasmexport declarations for "wasmcloud:messaging@0.2.0".
//go:wasmexport wasmcloud:messaging/handler@0.2.0#handle-message
//export wasmcloud:messaging/handler@0.2.0#handle-message
func wasmexport_HandleMessage(msg0 *uint8, msg1 uint32, msg2 *uint8, msg3 uint32, msg4 uint32, msg5 *uint8, msg6 uint32) (result *cm.Result[string, struct{}, string]) {
msg := lift_BrokerMessage((*uint8)(msg0), (uint32)(msg1), (*uint8)(msg2), (uint32)(msg3), (uint32)(msg4), (*uint8)(msg5), (uint32)(msg6))
result_ := Exports.HandleMessage(msg)
result = &result_
return
}

View File

@ -0,0 +1,13 @@
// Code generated by wit-bindgen-go. DO NOT EDIT.
// Package handler represents the exported interface "wasmcloud:messaging/handler@0.2.0".
package handler
import (
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/types"
)
// BrokerMessage represents the type alias "wasmcloud:messaging/handler@0.2.0#broker-message".
//
// See [types.BrokerMessage] for more information.
type BrokerMessage = types.BrokerMessage

2
go.mod
View File

@ -17,7 +17,7 @@ require (
github.com/sirupsen/logrus v1.9.3 // indirect github.com/sirupsen/logrus v1.9.3 // indirect
github.com/ulikunitz/xz v0.5.12 // indirect github.com/ulikunitz/xz v0.5.12 // indirect
github.com/urfave/cli/v3 v3.0.0-beta1 // indirect github.com/urfave/cli/v3 v3.0.0-beta1 // indirect
go.bytecodealliance.org v0.4.1 // indirect go.bytecodealliance.org v0.4.0 // indirect
golang.org/x/mod v0.22.0 // indirect golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.10.0 // indirect golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect golang.org/x/sys v0.28.0 // indirect

4
go.sum
View File

@ -31,8 +31,8 @@ github.com/ulikunitz/xz v0.5.12 h1:37Nm15o69RwBkXM0J6A5OlE67RZTfzUxTj8fB3dfcsc=
github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14= github.com/ulikunitz/xz v0.5.12/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg= github.com/urfave/cli/v3 v3.0.0-beta1 h1:6DTaaUarcM0wX7qj5Hcvs+5Dm3dyUTBbEwIWAjcw9Zg=
github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y= github.com/urfave/cli/v3 v3.0.0-beta1/go.mod h1:FnIeEMYu+ko8zP1F9Ypr3xkZMIDqW3DR92yUtY39q1Y=
go.bytecodealliance.org v0.4.1 h1:Y3Nnz+C061i9Hw4qQlSkZTg3IBTsTLC92+sdh4xCADQ= go.bytecodealliance.org v0.4.0 h1:SRwgZIcXR54AmbJg9Y3AMgDlZlvD8dffteBYW+nCD3k=
go.bytecodealliance.org v0.4.1/go.mod h1:jxAxqtTxs+6Q2q6bQnWa/lF+Q+2/LkdbqIgNJYxEmFA= go.bytecodealliance.org v0.4.0/go.mod h1:hkdjfgQ/bFZYUucnm9cn0Q8/SHO3iT0rzskYlkV4Jy0=
go.wasmcloud.dev/component v0.0.5 h1:z9+fq1CJKm/yom33ctd5wfo8TVunm5IaI7EJdY2i9hk= go.wasmcloud.dev/component v0.0.5 h1:z9+fq1CJKm/yom33ctd5wfo8TVunm5IaI7EJdY2i9hk=
go.wasmcloud.dev/component v0.0.5/go.mod h1:PvVHQ7Xp8D9kZnVB3fm8lqWAcC6Yxd7CI/snXZUAG8E= go.wasmcloud.dev/component v0.0.5/go.mod h1:PvVHQ7Xp8D9kZnVB3fm8lqWAcC6Yxd7CI/snXZUAG8E=
go.wasmcloud.dev/wadge v0.7.0 h1:eUt0jODh6xQ5HEof1PFSgDp+evrNs+lD1LYCYeRR2Cg= go.wasmcloud.dev/wadge v0.7.0 h1:eUt0jODh6xQ5HEof1PFSgDp+evrNs+lD1LYCYeRR2Cg=

17
main.go
View File

@ -2,10 +2,25 @@
package main package main
import ( import (
"net/http"
"fmt"
"go.wasmcloud.dev/component/net/wasihttp"
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/handler"
) )
func init() { func init() {
loop() wasihttp.HandleFunc(handleRequest)
handler.Exports.HandleMessage = handleMessage
}
func handleRequest(w http.ResponseWriter, r *http.Request) {
// get body as string
handleHttp(r.FormValue("data"))
// send response
fmt.Fprintf(w, "Message sent!\n")
} }
// Since we don't run this program like a CLI, the `main` function is empty. Instead, // Since we don't run this program like a CLI, the `main` function is empty. Instead,

View File

@ -1,54 +0,0 @@
//go:generate go run go.wasmcloud.dev/wadge/cmd/wadge-bindgen-go
package main
import (
"bytes"
"io"
"log"
"log/slog"
"net/http"
"os"
"testing"
incominghandler "go.wasmcloud.dev/component/gen/wasi/http/incoming-handler"
"go.wasmcloud.dev/wadge"
"go.wasmcloud.dev/wadge/wadgehttp"
)
func init() {
log.SetFlags(0)
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: slog.LevelDebug, ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
if a.Key == slog.TimeKey {
return slog.Attr{}
}
return a
},
})))
}
func TestIncomingHandler(t *testing.T) {
wadge.RunTest(t, func() {
req, err := http.NewRequest("", "/", nil)
if err != nil {
t.Fatalf("failed to create new HTTP request: %s", err)
}
resp, err := wadgehttp.HandleIncomingRequest(incominghandler.Exports.Handle, req)
if err != nil {
t.Fatalf("failed to handle incoming HTTP request: %s", err)
}
if want, got := http.StatusOK, resp.StatusCode; want != got {
t.Fatalf("unexpected status code: want %d, got %d", want, got)
}
buf, err := io.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed to read HTTP response body: %s", err)
}
defer resp.Body.Close()
if want, got := []byte("Hello from Go!\n"), buf; !bytes.Equal(want, got) {
t.Fatalf("unexpected response body: want %q, got %q", want, got)
}
})
}

View File

@ -6,7 +6,6 @@ import (
"gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/types" "gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasmcloud/messaging/types"
logger "gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasi/logging/logging" logger "gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasi/logging/logging"
//config "gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasi/config/runtime" //config "gitea.rebus.ninja/lore/wasm-nats-producer-client/gen/wasi/config/runtime"
"time"
) )
type messagingConsumerAdapter struct { type messagingConsumerAdapter struct {
@ -18,42 +17,49 @@ var messagingConsumer = &messagingConsumerAdapter{
Publish: consumer.Publish, Publish: consumer.Publish,
} }
func loop() cm.Result[string, struct{}, string] { func handleHttp(httpData string) {
// TODO implement the logic to get the destination topic from the config // TODO implement the logic to get the destination topic from the config
// dest_topic := config.GetAll() // dest_topic := config.GetAll()
dest_topic := "test.reply" dest_topic := "streaming"
counter := 0
// TASK // generate random message
for { data := []byte(httpData)
// generate random message // Send reply
data := []byte("Hello, World! " + string(counter)) reply := types.BrokerMessage{
Subject: dest_topic,
Body: cm.ToList(data),
ReplyTo: cm.None[string](),
}
// Send reply res := messagingConsumer.Publish(reply)
reply := types.BrokerMessage{
Subject: dest_topic,
Body: cm.ToList(data),
ReplyTo: cm.None[string](),
}
res := messagingConsumer.Publish(reply)
if res.IsErr() {
logger.Log(logger.LevelError, "MessageHandler", "Failed to send reply, error: " + *res.Err())
return res
}
counter++ if res.IsErr() {
logger.Log(logger.LevelError, "MessageHandler", "Failed to send reply, error: " + *res.Err())
}
if counter == 1000 { }
break
}
// sleep for 1 second func handleMessage(msg types.BrokerMessage) cm.Result[string, struct{}, string] {
time.Sleep(1 * time.Second)
logger.Log(logger.LevelInfo,"MessageHandler", "Received message on subject" + msg.Subject)
// TODO implement the logic to get the destination topic from the config
// dest_topic := config.GetAll()
dest_topic := "streaming"
// Send reply
reply := types.BrokerMessage{
Subject: dest_topic,
Body: msg.Body,
ReplyTo: cm.None[string](),
}
res := messagingConsumer.Publish(reply)
if res.IsErr() {
logger.Log(logger.LevelError, "MessageHandler", "Failed to send reply, error: " + *res.Err())
return res
} }
return cm.OK[cm.Result[string, struct{}, string]](struct{}{}) return cm.OK[cm.Result[string, struct{}, string]](struct{}{})
} }

View File

@ -3,32 +3,36 @@ kind: Application
metadata: metadata:
name: go-data-producer name: go-data-producer
annotations: annotations:
description: 'HTTP hello world demo in Golang (TinyGo), using the WebAssembly Component Model and WebAssembly Interfaces Types (WIT)' description: 'Data producer using NATS topic in Golang (TinyGo), using the WebAssembly Component Model and WebAssembly Interfaces Types (WIT)'
wasmcloud.dev/authors: wasmCloud team wasmcloud.dev/authors: Lorenzo Venerandi
wasmcloud.dev/source-url: https://github.com/wasmCloud/wasmCloud/blob/main/examples/golang/components/http-hello-world/wadm.yaml wasmcloud.dev/source-url: https://gitea.rebus.ninja/lore/wasm-nats-producer-client.git/wadm.yaml
wasmcloud.dev/readme-md-url: https://github.com/wasmCloud/wasmCloud/blob/main/examples/golang/components/http-hello-world/README.md wasmcloud.dev/readme-md-url: https://gitea.rebus.ninja/lore/wasm-nats-producer-client.git/README.md
wasmcloud.dev/homepage: https://github.com/wasmCloud/wasmCloud/tree/main/examples/golang/components/http-hello-world wasmcloud.dev/homepage: https://gitea.rebus.ninja/lore/wasm-nats-producer-client.git
wasmcloud.dev/categories: | wasmcloud.dev/categories: |
http,outgoing-http,http-server,tinygo,golang,example data-producer,nats-client,tinygo,golang
spec: spec:
components: components:
- name: echo - name: go-data-producer
type: component type: component
properties: properties:
# To use the locally compiled code in this folder, use the line below instead after running `wash build`: # To use the locally compiled code in this folder, use the line below instead after running `wash build`:
# image: file://./build/echo_messaging_s.wasm # image: file://./build/echo_messaging_s.wasm
image: gitea.rebus.ninja/lore/go-nats-client:1.0.1 image: gitea.rebus.ninja/lore/wasm-nats-producer-client:1.0.3
id: echo id: producer
config: # config:
- name: nats-topic # - name: nats-topic
properties: # properties:
dest-topic: wasmcloud.echo.reply # dest-topic: wasmcloud.echo.reply
traits: traits:
# Govern the spread/scheduling of the component # Govern the spread/scheduling of the component
- type: spreadscaler - type: spreadscaler
properties: properties:
instances: 1 instances: 1
spread: spread:
- name: cloud
weight: 0
requirements:
host-type: cloud
- name: edge - name: edge
weight: 100 weight: 100
requirements: requirements:
@ -63,9 +67,53 @@ spec:
# #
# Here we link the `nats` provider (the "source"), to the `echo` component (the "target"), # Here we link the `nats` provider (the "source"), to the `echo` component (the "target"),
# so that so the provider can deliver messages to the component (by invoking the wasmcloud:messaging/handler interface) . # so that so the provider can deliver messages to the component (by invoking the wasmcloud:messaging/handler interface) .
- type: link
properties:
target: go-data-producer
namespace: wasmcloud
package: messaging
interfaces: [handler]
source_config:
- name: simple-subscription
properties:
subscriptions: producer
- type: spreadscaler
properties: properties:
instances: 1 instances: 1
spread: spread:
- name: cloud
weight: 0
requirements:
host-type: cloud
- name: edge
weight: 100
requirements:
host-type: edge
- name: httpserver
type: capability
properties:
image: ghcr.io/wasmcloud/http-server:0.23.2
traits:
# Link to Echo, and inform it to listen on port 8000
# on the local machine
- type: link
properties:
target: go-data-producer
namespace: wasmcloud
package: http
interfaces: [incoming-handler]
source_config:
- name: default-http
properties:
address: 0.0.0.0:8000
- type: spreadscaler
properties:
instances: 1
spread:
- name: cloud
weight: 0
requirements:
host-type: cloud
- name: edge - name: edge
weight: 100 weight: 100
requirements: requirements:

View File

@ -11,6 +11,15 @@ requirement = "=0.2.0-draft"
version = "0.2.0-draft" version = "0.2.0-draft"
digest = "sha256:aa2d36d0843999edad80a13bf22f4529277f7b6012429f8a5d1f9499f3793c1a" digest = "sha256:aa2d36d0843999edad80a13bf22f4529277f7b6012429f8a5d1f9499f3793c1a"
[[packages]]
name = "wasi:http"
registry = "wasi.dev"
[[packages.versions]]
requirement = "=0.2.0"
version = "0.2.0"
digest = "sha256:5a568e6e2d60c1ce51220e1833cdd5b88db9f615720edc762a9b4a6f36b383bd"
[[packages]] [[packages]]
name = "wasi:logging" name = "wasi:logging"
registry = "wasi.dev" registry = "wasi.dev"

View File

@ -1,23 +1,5 @@
package wasi:cli@0.2.0; package wasi:cli@0.2.0;
interface environment {
get-environment: func() -> list<tuple<string, string>>;
get-arguments: func() -> list<string>;
initial-cwd: func() -> option<string>;
}
interface exit {
exit: func(status: result);
}
interface stdin {
use wasi:io/streams@0.2.0.{input-stream};
get-stdin: func() -> input-stream;
}
interface stdout { interface stdout {
use wasi:io/streams@0.2.0.{output-stream}; use wasi:io/streams@0.2.0.{output-stream};
@ -30,6 +12,24 @@ interface stderr {
get-stderr: func() -> output-stream; get-stderr: func() -> output-stream;
} }
interface stdin {
use wasi:io/streams@0.2.0.{input-stream};
get-stdin: func() -> input-stream;
}
interface environment {
get-environment: func() -> list<tuple<string, string>>;
get-arguments: func() -> list<string>;
initial-cwd: func() -> option<string>;
}
interface exit {
exit: func(status: result);
}
interface terminal-input { interface terminal-input {
resource terminal-input; resource terminal-input;
} }

View File

@ -1,11 +1,15 @@
package wasi:http@0.2.0; package wasi:http@0.2.0;
/// This interface defines all of the types and methods for implementing
/// HTTP Requests and Responses, both incoming and outgoing, as well as
/// their headers, trailers, and bodies.
interface types { interface types {
use wasi:clocks/monotonic-clock@0.2.0.{duration}; use wasi:clocks/monotonic-clock@0.2.0.{duration};
use wasi:io/streams@0.2.0.{input-stream, output-stream}; use wasi:io/streams@0.2.0.{input-stream, output-stream};
use wasi:io/error@0.2.0.{error as io-error}; use wasi:io/error@0.2.0.{error as io-error};
use wasi:io/poll@0.2.0.{pollable}; use wasi:io/poll@0.2.0.{pollable};
/// This type corresponds to HTTP standard Methods.
variant method { variant method {
get, get,
head, head,
@ -19,27 +23,33 @@ interface types {
other(string), other(string),
} }
/// This type corresponds to HTTP standard Related Schemes.
variant scheme { variant scheme {
HTTP, HTTP,
HTTPS, HTTPS,
other(string), other(string),
} }
/// Defines the case payload type for `DNS-error` above:
record DNS-error-payload { record DNS-error-payload {
rcode: option<string>, rcode: option<string>,
info-code: option<u16>, info-code: option<u16>,
} }
/// Defines the case payload type for `TLS-alert-received` above:
record TLS-alert-received-payload { record TLS-alert-received-payload {
alert-id: option<u8>, alert-id: option<u8>,
alert-message: option<string>, alert-message: option<string>,
} }
/// Defines the case payload type for `HTTP-response-{header,trailer}-size` above:
record field-size-payload { record field-size-payload {
field-name: option<string>, field-name: option<string>,
field-size: option<u32>, field-size: option<u32>,
} }
/// These cases are inspired by the IANA HTTP Proxy Error Types:
/// https://www.iana.org/assignments/http-proxy-status/http-proxy-status.xhtml#table-http-proxy-error-types
variant error-code { variant error-code {
DNS-timeout, DNS-timeout,
DNS-error(DNS-error-payload), DNS-error(DNS-error-payload),
@ -79,120 +89,483 @@ interface types {
HTTP-protocol-error, HTTP-protocol-error,
loop-detected, loop-detected,
configuration-error, configuration-error,
/// This is a catch-all error for anything that doesn't fit cleanly into a
/// more specific case. It also includes an optional string for an
/// unstructured description of the error. Users should not depend on the
/// string for diagnosing errors, as it's not required to be consistent
/// between implementations.
internal-error(option<string>), internal-error(option<string>),
} }
/// This type enumerates the different kinds of errors that may occur when
/// setting or appending to a `fields` resource.
variant header-error { variant header-error {
/// This error indicates that a `field-key` or `field-value` was
/// syntactically invalid when used with an operation that sets headers in a
/// `fields`.
invalid-syntax, invalid-syntax,
/// This error indicates that a forbidden `field-key` was used when trying
/// to set a header in a `fields`.
forbidden, forbidden,
/// This error indicates that the operation on the `fields` was not
/// permitted because the fields are immutable.
immutable, immutable,
} }
/// Field keys are always strings.
type field-key = string; type field-key = string;
/// Field values should always be ASCII strings. However, in
/// reality, HTTP implementations often have to interpret malformed values,
/// so they are provided as a list of bytes.
type field-value = list<u8>; type field-value = list<u8>;
/// This following block defines the `fields` resource which corresponds to
/// HTTP standard Fields. Fields are a common representation used for both
/// Headers and Trailers.
///
/// A `fields` may be mutable or immutable. A `fields` created using the
/// constructor, `from-list`, or `clone` will be mutable, but a `fields`
/// resource given by other means (including, but not limited to,
/// `incoming-request.headers`, `outgoing-request.headers`) might be be
/// immutable. In an immutable fields, the `set`, `append`, and `delete`
/// operations will fail with `header-error.immutable`.
resource fields { resource fields {
/// Construct an empty HTTP Fields.
///
/// The resulting `fields` is mutable.
constructor(); constructor();
/// Construct an HTTP Fields.
///
/// The resulting `fields` is mutable.
///
/// The list represents each key-value pair in the Fields. Keys
/// which have multiple values are represented by multiple entries in this
/// list with the same key.
///
/// The tuple is a pair of the field key, represented as a string, and
/// Value, represented as a list of bytes. In a valid Fields, all keys
/// and values are valid UTF-8 strings. However, values are not always
/// well-formed, so they are represented as a raw list of bytes.
///
/// An error result will be returned if any header or value was
/// syntactically invalid, or if a header was forbidden.
from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields, header-error>; from-list: static func(entries: list<tuple<field-key, field-value>>) -> result<fields, header-error>;
/// Get all of the values corresponding to a key. If the key is not present
/// in this `fields`, an empty list is returned. However, if the key is
/// present but empty, this is represented by a list with one or more
/// empty field-values present.
get: func(name: field-key) -> list<field-value>; get: func(name: field-key) -> list<field-value>;
/// Returns `true` when the key is present in this `fields`. If the key is
/// syntactically invalid, `false` is returned.
has: func(name: field-key) -> bool; has: func(name: field-key) -> bool;
/// Set all of the values for a key. Clears any existing values for that
/// key, if they have been set.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
set: func(name: field-key, value: list<field-value>) -> result<_, header-error>; set: func(name: field-key, value: list<field-value>) -> result<_, header-error>;
/// Delete all values for a key. Does nothing if no values for the key
/// exist.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
delete: func(name: field-key) -> result<_, header-error>; delete: func(name: field-key) -> result<_, header-error>;
/// Append a value for a key. Does not change or delete any existing
/// values for that key.
///
/// Fails with `header-error.immutable` if the `fields` are immutable.
append: func(name: field-key, value: field-value) -> result<_, header-error>; append: func(name: field-key, value: field-value) -> result<_, header-error>;
/// Retrieve the full set of keys and values in the Fields. Like the
/// constructor, the list represents each key-value pair.
///
/// The outer list represents each key-value pair in the Fields. Keys
/// which have multiple values are represented by multiple entries in this
/// list with the same key.
entries: func() -> list<tuple<field-key, field-value>>; entries: func() -> list<tuple<field-key, field-value>>;
/// Make a deep copy of the Fields. Equivelant in behavior to calling the
/// `fields` constructor on the return value of `entries`. The resulting
/// `fields` is mutable.
clone: func() -> fields; clone: func() -> fields;
} }
/// Headers is an alias for Fields.
type headers = fields; type headers = fields;
/// Trailers is an alias for Fields.
type trailers = fields; type trailers = fields;
/// Represents an incoming HTTP Request.
resource incoming-request { resource incoming-request {
/// Returns the method of the incoming request.
method: func() -> method; method: func() -> method;
/// Returns the path with query parameters from the request, as a string.
path-with-query: func() -> option<string>; path-with-query: func() -> option<string>;
/// Returns the protocol scheme from the request.
scheme: func() -> option<scheme>; scheme: func() -> option<scheme>;
/// Returns the authority from the request, if it was present.
authority: func() -> option<string>; authority: func() -> option<string>;
/// Get the `headers` associated with the request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// The `headers` returned are a child resource: it must be dropped before
/// the parent `incoming-request` is dropped. Dropping this
/// `incoming-request` before all children are dropped will trap.
headers: func() -> headers; headers: func() -> headers;
/// Gives the `incoming-body` associated with this request. Will only
/// return success at most once, and subsequent calls will return error.
consume: func() -> result<incoming-body>; consume: func() -> result<incoming-body>;
} }
/// Represents an outgoing HTTP Request.
resource outgoing-request { resource outgoing-request {
/// Construct a new `outgoing-request` with a default `method` of `GET`, and
/// `none` values for `path-with-query`, `scheme`, and `authority`.
///
/// * `headers` is the HTTP Headers for the Request.
///
/// It is possible to construct, or manipulate with the accessor functions
/// below, an `outgoing-request` with an invalid combination of `scheme`
/// and `authority`, or `headers` which are not permitted to be sent.
/// It is the obligation of the `outgoing-handler.handle` implementation
/// to reject invalid constructions of `outgoing-request`.
constructor(headers: headers); constructor(headers: headers);
/// Returns the resource corresponding to the outgoing Body for this
/// Request.
///
/// Returns success on the first call: the `outgoing-body` resource for
/// this `outgoing-request` can be retrieved at most once. Subsequent
/// calls will return error.
body: func() -> result<outgoing-body>; body: func() -> result<outgoing-body>;
/// Get the Method for the Request.
method: func() -> method; method: func() -> method;
/// Set the Method for the Request. Fails if the string present in a
/// `method.other` argument is not a syntactically valid method.
set-method: func(method: method) -> result; set-method: func(method: method) -> result;
/// Get the combination of the HTTP Path and Query for the Request.
/// When `none`, this represents an empty Path and empty Query.
path-with-query: func() -> option<string>; path-with-query: func() -> option<string>;
/// Set the combination of the HTTP Path and Query for the Request.
/// When `none`, this represents an empty Path and empty Query. Fails is the
/// string given is not a syntactically valid path and query uri component.
set-path-with-query: func(path-with-query: option<string>) -> result; set-path-with-query: func(path-with-query: option<string>) -> result;
/// Get the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme.
scheme: func() -> option<scheme>; scheme: func() -> option<scheme>;
/// Set the HTTP Related Scheme for the Request. When `none`, the
/// implementation may choose an appropriate default scheme. Fails if the
/// string given is not a syntactically valid uri scheme.
set-scheme: func(scheme: option<scheme>) -> result; set-scheme: func(scheme: option<scheme>) -> result;
/// Get the HTTP Authority for the Request. A value of `none` may be used
/// with Related Schemes which do not require an Authority. The HTTP and
/// HTTPS schemes always require an authority.
authority: func() -> option<string>; authority: func() -> option<string>;
/// Set the HTTP Authority for the Request. A value of `none` may be used
/// with Related Schemes which do not require an Authority. The HTTP and
/// HTTPS schemes always require an authority. Fails if the string given is
/// not a syntactically valid uri authority.
set-authority: func(authority: option<string>) -> result; set-authority: func(authority: option<string>) -> result;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `outgoing-request` is dropped, or its ownership is transfered to
/// another component by e.g. `outgoing-handler.handle`.
headers: func() -> headers; headers: func() -> headers;
} }
/// Parameters for making an HTTP Request. Each of these parameters is
/// currently an optional timeout applicable to the transport layer of the
/// HTTP protocol.
///
/// These timeouts are separate from any the user may use to bound a
/// blocking call to `wasi:io/poll.poll`.
resource request-options { resource request-options {
/// Construct a default `request-options` value.
constructor(); constructor();
/// The timeout for the initial connect to the HTTP Server.
connect-timeout: func() -> option<duration>; connect-timeout: func() -> option<duration>;
/// Set the timeout for the initial connect to the HTTP Server. An error
/// return value indicates that this timeout is not supported.
set-connect-timeout: func(duration: option<duration>) -> result; set-connect-timeout: func(duration: option<duration>) -> result;
/// The timeout for receiving the first byte of the Response body.
first-byte-timeout: func() -> option<duration>; first-byte-timeout: func() -> option<duration>;
/// Set the timeout for receiving the first byte of the Response body. An
/// error return value indicates that this timeout is not supported.
set-first-byte-timeout: func(duration: option<duration>) -> result; set-first-byte-timeout: func(duration: option<duration>) -> result;
/// The timeout for receiving subsequent chunks of bytes in the Response
/// body stream.
between-bytes-timeout: func() -> option<duration>; between-bytes-timeout: func() -> option<duration>;
/// Set the timeout for receiving subsequent chunks of bytes in the Response
/// body stream. An error return value indicates that this timeout is not
/// supported.
set-between-bytes-timeout: func(duration: option<duration>) -> result; set-between-bytes-timeout: func(duration: option<duration>) -> result;
} }
/// Represents the ability to send an HTTP Response.
///
/// This resource is used by the `wasi:http/incoming-handler` interface to
/// allow a Response to be sent corresponding to the Request provided as the
/// other argument to `incoming-handler.handle`.
resource response-outparam { resource response-outparam {
/// Set the value of the `response-outparam` to either send a response,
/// or indicate an error.
///
/// This method consumes the `response-outparam` to ensure that it is
/// called at most once. If it is never called, the implementation
/// will respond with an error.
///
/// The user may provide an `error` to `response` to allow the
/// implementation determine how to respond with an HTTP error response.
set: static func(param: response-outparam, response: result<outgoing-response, error-code>); set: static func(param: response-outparam, response: result<outgoing-response, error-code>);
} }
/// This type corresponds to the HTTP standard Status Code.
type status-code = u16; type status-code = u16;
/// Represents an incoming HTTP Response.
resource incoming-response { resource incoming-response {
/// Returns the status code from the incoming response.
status: func() -> status-code; status: func() -> status-code;
/// Returns the headers from the incoming response.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `incoming-response` is dropped.
headers: func() -> headers; headers: func() -> headers;
/// Returns the incoming body. May be called at most once. Returns error
/// if called additional times.
consume: func() -> result<incoming-body>; consume: func() -> result<incoming-body>;
} }
/// Represents an incoming HTTP Request or Response's Body.
///
/// A body has both its contents - a stream of bytes - and a (possibly
/// empty) set of trailers, indicating that the full contents of the
/// body have been received. This resource represents the contents as
/// an `input-stream` and the delivery of trailers as a `future-trailers`,
/// and ensures that the user of this interface may only be consuming either
/// the body contents or waiting on trailers at any given time.
resource incoming-body { resource incoming-body {
/// Returns the contents of the body, as a stream of bytes.
///
/// Returns success on first call: the stream representing the contents
/// can be retrieved at most once. Subsequent calls will return error.
///
/// The returned `input-stream` resource is a child: it must be dropped
/// before the parent `incoming-body` is dropped, or consumed by
/// `incoming-body.finish`.
///
/// This invariant ensures that the implementation can determine whether
/// the user is consuming the contents of the body, waiting on the
/// `future-trailers` to be ready, or neither. This allows for network
/// backpressure is to be applied when the user is consuming the body,
/// and for that backpressure to not inhibit delivery of the trailers if
/// the user does not read the entire body.
%stream: func() -> result<input-stream>; %stream: func() -> result<input-stream>;
/// Takes ownership of `incoming-body`, and returns a `future-trailers`.
/// This function will trap if the `input-stream` child is still alive.
finish: static func(this: incoming-body) -> future-trailers; finish: static func(this: incoming-body) -> future-trailers;
} }
/// Represents a future which may eventaully return trailers, or an error.
///
/// In the case that the incoming HTTP Request or Response did not have any
/// trailers, this future will resolve to the empty set of trailers once the
/// complete Request or Response body has been received.
resource future-trailers { resource future-trailers {
/// Returns a pollable which becomes ready when either the trailers have
/// been received, or an error has occured. When this pollable is ready,
/// the `get` method will return `some`.
subscribe: func() -> pollable; subscribe: func() -> pollable;
/// Returns the contents of the trailers, or an error which occured,
/// once the future is ready.
///
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The outer `result` is used to retrieve the trailers or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the HTTP Request or Response
/// body, as well as any trailers, were received successfully, or that an
/// error occured receiving them. The optional `trailers` indicates whether
/// or not trailers were present in the body.
///
/// When some `trailers` are returned by this method, the `trailers`
/// resource is immutable, and a child. Use of the `set`, `append`, or
/// `delete` methods will return an error, and the resource must be
/// dropped before the parent `future-trailers` is dropped.
get: func() -> option<result<result<option<trailers>, error-code>>>; get: func() -> option<result<result<option<trailers>, error-code>>>;
} }
/// Represents an outgoing HTTP Response.
resource outgoing-response { resource outgoing-response {
/// Construct an `outgoing-response`, with a default `status-code` of `200`.
/// If a different `status-code` is needed, it must be set via the
/// `set-status-code` method.
///
/// * `headers` is the HTTP Headers for the Response.
constructor(headers: headers); constructor(headers: headers);
/// Get the HTTP Status Code for the Response.
status-code: func() -> status-code; status-code: func() -> status-code;
/// Set the HTTP Status Code for the Response. Fails if the status-code
/// given is not a valid http status code.
set-status-code: func(status-code: status-code) -> result; set-status-code: func(status-code: status-code) -> result;
/// Get the headers associated with the Request.
///
/// The returned `headers` resource is immutable: `set`, `append`, and
/// `delete` operations will fail with `header-error.immutable`.
///
/// This headers resource is a child: it must be dropped before the parent
/// `outgoing-request` is dropped, or its ownership is transfered to
/// another component by e.g. `outgoing-handler.handle`.
headers: func() -> headers; headers: func() -> headers;
/// Returns the resource corresponding to the outgoing Body for this Response.
///
/// Returns success on the first call: the `outgoing-body` resource for
/// this `outgoing-response` can be retrieved at most once. Subsequent
/// calls will return error.
body: func() -> result<outgoing-body>; body: func() -> result<outgoing-body>;
} }
/// Represents an outgoing HTTP Request or Response's Body.
///
/// A body has both its contents - a stream of bytes - and a (possibly
/// empty) set of trailers, inducating the full contents of the body
/// have been sent. This resource represents the contents as an
/// `output-stream` child resource, and the completion of the body (with
/// optional trailers) with a static function that consumes the
/// `outgoing-body` resource, and ensures that the user of this interface
/// may not write to the body contents after the body has been finished.
///
/// If the user code drops this resource, as opposed to calling the static
/// method `finish`, the implementation should treat the body as incomplete,
/// and that an error has occured. The implementation should propogate this
/// error to the HTTP protocol by whatever means it has available,
/// including: corrupting the body on the wire, aborting the associated
/// Request, or sending a late status code for the Response.
resource outgoing-body { resource outgoing-body {
/// Returns a stream for writing the body contents.
///
/// The returned `output-stream` is a child resource: it must be dropped
/// before the parent `outgoing-body` resource is dropped (or finished),
/// otherwise the `outgoing-body` drop or `finish` will trap.
///
/// Returns success on the first call: the `output-stream` resource for
/// this `outgoing-body` may be retrieved at most once. Subsequent calls
/// will return error.
write: func() -> result<output-stream>; write: func() -> result<output-stream>;
/// Finalize an outgoing body, optionally providing trailers. This must be
/// called to signal that the response is complete. If the `outgoing-body`
/// is dropped without calling `outgoing-body.finalize`, the implementation
/// should treat the body as corrupted.
///
/// Fails if the body's `outgoing-request` or `outgoing-response` was
/// constructed with a Content-Length header, and the contents written
/// to the body (via `write`) does not match the value given in the
/// Content-Length.
finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_, error-code>; finish: static func(this: outgoing-body, trailers: option<trailers>) -> result<_, error-code>;
} }
/// Represents a future which may eventaully return an incoming HTTP
/// Response, or an error.
///
/// This resource is returned by the `wasi:http/outgoing-handler` interface to
/// provide the HTTP Response corresponding to the sent Request.
resource future-incoming-response { resource future-incoming-response {
/// Returns a pollable which becomes ready when either the Response has
/// been received, or an error has occured. When this pollable is ready,
/// the `get` method will return `some`.
subscribe: func() -> pollable; subscribe: func() -> pollable;
/// Returns the incoming HTTP Response, or an error, once one is ready.
///
/// The outer `option` represents future readiness. Users can wait on this
/// `option` to become `some` using the `subscribe` method.
///
/// The outer `result` is used to retrieve the response or error at most
/// once. It will be success on the first call in which the outer option
/// is `some`, and error on subsequent calls.
///
/// The inner `result` represents that either the incoming HTTP Response
/// status and headers have recieved successfully, or that an error
/// occured. Errors may also occur while consuming the response body,
/// but those will be reported by the `incoming-body` and its
/// `output-stream` child.
get: func() -> option<result<result<incoming-response, error-code>>>; get: func() -> option<result<result<incoming-response, error-code>>>;
} }
/// Attempts to extract a http-related `error` from the wasi:io `error`
/// provided.
///
/// Stream operations which return
/// `wasi:io/stream/stream-error::last-operation-failed` have a payload of
/// type `wasi:io/error/error` with more information about the operation
/// that failed. This payload can be passed through to this function to see
/// if there's http-related information about the error to return.
///
/// Note that this function is fallible because not all io-errors are
/// http-related errors.
http-error-code: func(err: borrow<io-error>) -> option<error-code>; http-error-code: func(err: borrow<io-error>) -> option<error-code>;
} }
/// This interface defines a handler of incoming HTTP Requests. It should
/// be exported by components which can respond to HTTP Requests.
interface incoming-handler { interface incoming-handler {
use types.{incoming-request, response-outparam}; use types.{incoming-request, response-outparam};
/// This function is invoked with an incoming HTTP Request, and a resource
/// `response-outparam` which provides the capability to reply with an HTTP
/// Response. The response is sent by calling the `response-outparam.set`
/// method, which allows execution to continue after the response has been
/// sent. This enables both streaming to the response body, and performing other
/// work.
///
/// The implementor of this function must write a response to the
/// `response-outparam` before returning, or else the caller will respond
/// with an error on its behalf.
handle: func(request: incoming-request, response-out: response-outparam); handle: func(request: incoming-request, response-out: response-outparam);
} }
/// This interface defines a handler of outgoing HTTP Requests. It should be
/// imported by components which wish to make HTTP Requests.
interface outgoing-handler { interface outgoing-handler {
use types.{outgoing-request, request-options, future-incoming-response, error-code}; use types.{outgoing-request, request-options, future-incoming-response, error-code};
/// This function is invoked with an outgoing HTTP Request, and it returns
/// a resource `future-incoming-response` which represents an HTTP Response
/// which may arrive in the future.
///
/// The `options` argument accepts optional parameters for the HTTP
/// protocol's transport layer.
///
/// This function may return an error if the `outgoing-request` is invalid
/// or not allowed to be made. Otherwise, protocol errors are reported
/// through the `future-incoming-response`.
handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response, error-code>; handle: func(request: outgoing-request, options: option<request-options>) -> result<future-incoming-response, error-code>;
} }
/// The `wasi:http/proxy` world captures a widely-implementable intersection of
/// hosts that includes HTTP forward and reverse proxies. Components targeting
/// this world may concurrently stream in and out any number of incoming and
/// outgoing HTTP requests.
world proxy {
import wasi:random/random@0.2.0;
import wasi:io/error@0.2.0;
import wasi:io/poll@0.2.0;
import wasi:io/streams@0.2.0;
import wasi:cli/stdout@0.2.0;
import wasi:cli/stderr@0.2.0;
import wasi:cli/stdin@0.2.0;
import wasi:clocks/monotonic-clock@0.2.0;
import types;
import outgoing-handler;
import wasi:clocks/wall-clock@0.2.0;
export incoming-handler;
}

View File

@ -5,6 +5,9 @@ world hello {
import wasi:config/runtime@0.2.0-draft; import wasi:config/runtime@0.2.0-draft;
export wasi:http/incoming-handler@0.2.0;
export wasmcloud:messaging/handler@0.2.0;
import wasmcloud:messaging/consumer@0.2.0; import wasmcloud:messaging/consumer@0.2.0;
import wasi:logging/logging@0.1.0-draft; import wasi:logging/logging@0.1.0-draft;
} }