feat(sdk/go): Implement spin-http for TinyGo

TinyGo bindings of the spin-http wit.

14603bb71f/wit/ephemeral/spin-http.wit
This commit is contained in:
Adam Reese 2022-04-21 20:47:36 -07:00
parent f4426a4019
commit 9b8549d9c2
No known key found for this signature in database
GPG Key ID: 06F35E60A7A18DD6
14 changed files with 703 additions and 211 deletions

View File

@ -6,30 +6,31 @@ import (
"net/http"
"os"
spin_http "github.com/fermyon/spin/sdk/go/http"
spinhttp "github.com/fermyon/spin/sdk/go/http"
)
func main() {
spin_http.HandleRequest(func(w http.ResponseWriter, r *http.Request) {
r1, _ := spin_http.Get("https://some-random-api.ml/facts/dog")
func init() {
spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {
r1, _ := spinhttp.Get("https://some-random-api.ml/facts/dog")
fmt.Fprintln(w, r1.Body)
fmt.Fprintln(w, r1.Header.Get("content-type"))
r2, _ := spin_http.Post("https://postman-echo.com/post", "text/plain", r.Body)
r2, _ := spinhttp.Post("https://postman-echo.com/post", "text/plain", r.Body)
fmt.Fprintln(w, r2.Body)
req, _ := http.NewRequest("PUT", "https://postman-echo.com/put", bytes.NewBufferString("General Kenobi!"))
req.Header.Add("foo", "bar")
r3, _ := spin_http.Send(req)
r3, _ := spinhttp.Send(req)
fmt.Fprintln(w, r3.Body)
// `spin.toml` is not configured to allow outbound HTTP requests to this host,
// so this request will fail.
_, err := spin_http.Get("https://fermyon.com")
if err != nil {
if _, err := spinhttp.Get("https://fermyon.com"); err != nil {
fmt.Fprintf(os.Stderr, "Cannot send HTTP request: %v", err)
}
})
}
func main() {}

View File

@ -8,7 +8,6 @@ version = "1.0.0"
[[component]]
id = "tinygo-hello"
source = "main.wasm"
allowed_http_hosts = [ "https://some-random-api.ml", "https://postman-echo.com" ]
allowed_http_hosts = ["https://some-random-api.ml", "https://postman-echo.com"]
[component.trigger]
route = "/hello"
executor = { type = "wagi" }

View File

@ -2,6 +2,6 @@
build:
tinygo build -wasm-abi=generic -target=wasi -gc=leaking -o main.wasm main.go
. PHONY: serve
.PHONY: serve
serve:
RUST_LOG=spin=trace spin up --file spin.toml

View File

@ -2,13 +2,35 @@ package main
import (
"fmt"
"io"
"net/http"
spin "github.com/fermyon/spin/sdk/go/http"
spinhttp "github.com/fermyon/spin/sdk/go/http"
)
func main() {
spin.HandleRequest(func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, "Hello, Fermyon!")
func init() {
spinhttp.Handle(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "text/plain")
w.Header().Set("foo", "bar")
fmt.Fprintln(w, "== REQUEST ==")
fmt.Fprintln(w, "URL: ", r.URL)
fmt.Fprintln(w, "Method: ", r.Method)
fmt.Fprintln(w, "Headers:")
for k, v := range r.Header {
fmt.Fprintf(w, " %q: %q \n", k, v[0])
}
body, err := io.ReadAll(r.Body)
if err != nil {
fmt.Fprintln(w, "Body Error: ", err)
} else {
fmt.Fprintln(w, "Body: ", string(body))
}
fmt.Fprintln(w, "== RESPONSE ==")
fmt.Fprintln(w, "Hello Fermyon!")
})
}
func main() {}

View File

@ -10,4 +10,3 @@ id = "tinygo-hello"
source = "main.wasm"
[component.trigger]
route = "/hello"
executor = { type = "wagi" }

View File

@ -1,7 +1,12 @@
.PHONY: generate
generate:
wit-bindgen c --import ../../../wit/ephemeral/wasi-outbound-http.wit
wit-bindgen c --export ../../../wit/ephemeral/spin-http.wit
.PHONY: clean
clean:
rm wasi-outbound-http.h wasi-outbound-http.c
rm spin-http.h spin-http.c wasi-outbound-http.h wasi-outbound-http.c
.PHONY: test
test:
tinygo test -wasm-abi=generic -target=wasi -gc=leaking -v

View File

@ -1,24 +1,27 @@
//nolint:staticcheck
// Package http contains the helper functions for writing Spin HTTP components
// in TinyGo, as well as for sending outbound HTTP requests.
package http
import (
"fmt"
"io"
"net/http"
"net/http/cgi"
"os"
)
// HandleRequest is the entrypoint handler for a Spin HTTP component.
//
// This is currently handled using CGI to form the request and reponse,
// but as Go implements support for the component model, the underlying
// implementation of this function can change, but the exported signature
// can continue to always be
// `func HandleRequest(h func(w http.ResponseWriter, r *http.Request)) error`.
func HandleRequest(h func(w http.ResponseWriter, r *http.Request)) error {
return cgi.Serve(http.HandlerFunc(h))
// handler is the function that will be called by the http trigger in Spin.
var handler = defaultHandler
// defaultHandler is a placeholder for returning a useful error to stdout when
// the handler is not set.
var defaultHandler = func(http.ResponseWriter, *http.Request) {
fmt.Fprintln(os.Stderr, "http handler undefined")
}
// Handle sets the handler function for the http trigger.
// It must be set in an init() function.
func Handle(fn func(http.ResponseWriter, *http.Request)) {
handler = fn
}
// Get creates a GET HTTP request to a given URL and returns the HTTP response.

183
sdk/go/http/internals.go Normal file
View File

@ -0,0 +1,183 @@
package http
// #cgo CFLAGS: -Wno-unused-parameter -Wno-switch-bool
// #include<spin-http.h>
// #include<stdlib.h>
import "C"
import (
"bytes"
"fmt"
"io"
"net/http"
"os"
"unsafe"
)
//export spin_http_handle_http_request
func handle_http_request(req *C.spin_http_request_t, res *C.spin_http_response_t) {
defer C.spin_http_request_free(req)
sr := (*spinRequest)(req)
// NOTE Host is not included in the URL
r, err := http.NewRequest(sr.Method(), sr.URL(), bytes.NewReader(sr.Body()))
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
r.Header = fromSpinHeaders(&req.headers)
r.Host = r.Header.Get("Host")
w := newResponse()
// call user function
handler(w, r)
res.status = C.uint16_t(w.status)
if len(w.header) > 0 {
res.headers = C.spin_http_option_headers_t{
tag: true,
val: toSpinHeaders(w.header),
}
} else {
res.headers = C.spin_http_option_headers_t{tag: false}
}
res.body, err = toSpinBody(w.w)
if err != nil {
fmt.Fprintln(os.Stderr, err)
}
}
func toSpinHeaders(hm http.Header) C.spin_http_headers_t {
var reqHeaders C.spin_http_headers_t
headersLen := len(hm)
if headersLen > 0 {
reqHeaders.len = C.ulong(headersLen)
var x C.spin_http_string_t
headersPtr := C.malloc(C.size_t(headersLen) * C.size_t(unsafe.Sizeof(x)))
ptr := (*[1 << 30]C.spin_http_tuple2_string_string_t)(unsafe.Pointer(&headersPtr))[:headersLen:headersLen]
idx := 0
for k, v := range hm {
ptr[idx] = newSpinHeader(k, v[0])
idx++
}
reqHeaders.ptr = &ptr[0]
}
return reqHeaders
}
func toSpinBody(body io.Reader) (C.spin_http_option_body_t, error) {
var spinBody C.spin_http_option_body_t
spinBody.tag = false
if body == nil {
return spinBody, nil
}
buf := new(bytes.Buffer)
len, err := buf.ReadFrom(body)
if err != nil {
return spinBody, err
}
if len > 0 {
spinBody.tag = true
spinBody.val = C.spin_http_body_t{
ptr: &buf.Bytes()[0],
len: C.size_t(len),
}
}
return spinBody, nil
}
// spinString is the go type for C.spin_http_string_t.
type spinString C.spin_http_string_t
// newSpinString creates a new spinString with the given string.
func newSpinString(s string) spinString {
return C.spin_http_string_t{ptr: C.CString(s), len: C.size_t(len(s))}
}
// String returns the spinString as a go string.
func (ss spinString) String() string {
return C.GoStringN(ss.ptr, C.int(ss.len))
}
// spinHeader is the go type for C.spin_http_tuple2_string_string_t.
type spinHeader C.spin_http_tuple2_string_string_t
// newSpinHeader creates a new spinHeader with the given key/value.
func newSpinHeader(k, v string) spinHeader {
return C.spin_http_tuple2_string_string_t{
f0: newSpinString(k),
f1: newSpinString(v),
}
}
// Values returns the key/value as strings.
func (sh spinHeader) Values() (string, string) {
k := spinString(sh.f0).String()
v := spinString(sh.f1).String()
return k, v
}
// spinBody is the go type for C.spin_http_body_t.
type spinBody C.spin_http_body_t
// Bytes returns the body as a go []byte.
func (sb spinBody) Bytes() []byte {
return C.GoBytes(unsafe.Pointer(sb.ptr), C.int(sb.len))
}
// spinRequest is the go type for C.spin_http_request_t.
type spinRequest C.spin_http_request_t
var methods = [...]string{
"GET",
"POST",
"PUT",
"DELETE",
"PATCH",
"HEAD",
"OPTIONS",
}
// Method returns the request method as a go string.
func (sr spinRequest) Method() string {
return methods[sr.method]
}
// URL returns the request URL as a go string.
func (sr spinRequest) URL() string {
return spinString(sr.uri).String()
}
// Body returns the request body as a go []byte.
func (sr spinRequest) Body() []byte {
if !sr.body.tag {
return nil
}
return spinBody(sr.body.val).Bytes()
}
func fromSpinHeaders(hm *C.spin_http_headers_t) http.Header {
headersLen := int(hm.len)
headers := make(http.Header, headersLen)
var headersArr *C.spin_http_tuple2_string_string_t = hm.ptr
headersSlice := unsafe.Slice(headersArr, headersLen)
for i := 0; i < headersLen; i++ {
tuple := headersSlice[i]
k := C.GoStringN(tuple.f0.ptr, C.int(tuple.f0.len))
v := C.GoStringN(tuple.f1.ptr, C.int(tuple.f1.len))
headers.Add(k, v)
}
return headers
}

View File

@ -0,0 +1,21 @@
package http
import "testing"
func TestString(t *testing.T) {
tt := "hello"
if tt != newSpinString(tt).String() {
t.Fatal("strings do not match")
}
}
func TestHeader(t *testing.T) {
k, v := "hello", "world"
gotK, gotV := newSpinHeader(k, v).Values()
if k != gotK {
t.Fatal("keys do not match")
}
if v != gotV {
t.Fatal("values did not match")
}
}

View File

@ -17,6 +17,7 @@ import (
"io"
"io/ioutil"
"net/http"
"strings"
"unsafe"
)
@ -56,36 +57,35 @@ func send(req *http.Request) (*http.Response, error) {
ptr: C.CString(req.URL.String()),
len: C.ulong(len(req.URL.String())),
}
spinReq.headers = toSpinReqHeaders(req.Header)
spinReq.body, err = toSpinReqBody(req.Body)
spinReq.headers = toOutboundHeaders(req.Header)
spinReq.body, err = toOutboundReqBody(req.Body)
if err != nil {
return nil, err
}
code := C.wasi_outbound_http_request(&spinReq, &spinRes)
err = toErr(code, req.URL.String())
if err != nil {
if err := toErr(code, req.URL.String()); err != nil {
return nil, err
}
return toStdHttpResp(&spinRes)
return toResponse(&spinRes)
}
func method(m string) (int, error) {
switch m {
case "GET", "get":
switch strings.ToUpper(m) {
case "GET":
return 0, nil
case "POST", "post":
case "POST":
return 1, nil
case "PUT", "put":
case "PUT":
return 2, nil
case "DELETE", "delete":
case "DELETE":
return 3, nil
case "PATCH", "patch":
case "PATCH":
return 4, nil
case "HEAD", "head":
case "HEAD":
return 5, nil
case "OPTIONS", "options":
case "OPTIONS":
return 6, nil
default:
return -1, fmt.Errorf("Unknown HTTP method %v", m)
@ -93,7 +93,7 @@ func method(m string) (int, error) {
}
// Transform a C outbound HTTP response to a Go *http.Response.
func toStdHttpResp(res *C.wasi_outbound_http_response_t) (*http.Response, error) {
func toResponse(res *C.wasi_outbound_http_response_t) (*http.Response, error) {
var body []byte
if res.body.tag {
body = C.GoBytes(unsafe.Pointer(res.body.val.ptr), C.int(res.body.val.len))
@ -108,12 +108,25 @@ func toStdHttpResp(res *C.wasi_outbound_http_response_t) (*http.Response, error)
Body: ioutil.NopCloser(bytes.NewBuffer(body)),
ContentLength: int64(len(body)),
Request: nil, // we don't really have a request to populate with here
Header: toStdResHeaders(&res.headers),
Header: toHeaders(&res.headers),
}
return t, nil
}
func toSpinReqHeaders(hm http.Header) C.wasi_outbound_http_headers_t {
// outboundString is the go type for C.wasi_outbound_http_string_t.
type outboundString C.wasi_outbound_http_string_t
// newOutboundString creates a new spinString with the given string.
func newOutboundString(s string) spinString {
return C.wasi_outbound_http_string_t{ptr: C.CString(s), len: C.size_t(len(s))}
}
// String returns the outboundString as a go string.
func (ws outboundString) String() string {
return C.GoStringN(ws.ptr, C.int(ws.len))
}
func toOutboundHeaders(hm http.Header) C.wasi_outbound_http_headers_t {
var reqHeaders C.wasi_outbound_http_headers_t
headersLen := len(hm)
@ -125,8 +138,8 @@ func toSpinReqHeaders(hm http.Header) C.wasi_outbound_http_headers_t {
idx := 0
for k, v := range hm {
ptr[idx].f0 = C.wasi_outbound_http_string_t{ptr: C.CString(k), len: C.ulong(len(k))}
ptr[idx].f1 = C.wasi_outbound_http_string_t{ptr: C.CString(v[0]), len: C.ulong(len(v[0]))}
ptr[idx].f0 = newOutboundString(k)
ptr[idx].f1 = newOutboundString(v[0])
idx++
}
reqHeaders.ptr = &ptr[0]
@ -135,7 +148,7 @@ func toSpinReqHeaders(hm http.Header) C.wasi_outbound_http_headers_t {
return reqHeaders
}
func toSpinReqBody(body io.Reader) (C.wasi_outbound_http_option_body_t, error) {
func toOutboundReqBody(body io.Reader) (C.wasi_outbound_http_option_body_t, error) {
var spinBody C.wasi_outbound_http_option_body_t
spinBody.tag = false
@ -158,7 +171,7 @@ func toSpinReqBody(body io.Reader) (C.wasi_outbound_http_option_body_t, error) {
return spinBody, nil
}
func toStdResHeaders(hm *C.wasi_outbound_http_option_headers_t) http.Header {
func toHeaders(hm *C.wasi_outbound_http_option_headers_t) http.Header {
if !hm.tag {
return make(map[string][]string, 0)
}

39
sdk/go/http/response.go Normal file
View File

@ -0,0 +1,39 @@
package http
import (
"bytes"
"net/http"
)
var _ http.ResponseWriter = (*response)(nil)
// response implements http.ResponseWriter
type response struct {
// status code passed to WriteHeader
status int
header http.Header
w *bytes.Buffer
}
func newResponse() *response {
return &response{
// set default status to StatusOK
status: http.StatusOK,
header: make(http.Header),
w: new(bytes.Buffer),
}
}
func (r *response) Header() http.Header {
return r.header
}
func (r *response) WriteHeader(statusCode int) {
r.status = statusCode
}
func (r *response) Write(data []byte) (int, error) {
return r.w.Write(data)
}

159
sdk/go/http/spin-http.c Normal file
View File

@ -0,0 +1,159 @@
#include <stdlib.h>
#include <spin-http.h>
__attribute__((weak, export_name("canonical_abi_realloc")))
void *canonical_abi_realloc(
void *ptr,
size_t orig_size,
size_t org_align,
size_t new_size
) {
void *ret = realloc(ptr, new_size);
if (!ret)
abort();
return ret;
}
__attribute__((weak, export_name("canonical_abi_free")))
void canonical_abi_free(
void *ptr,
size_t size,
size_t align
) {
free(ptr);
}
#include <string.h>
void spin_http_string_set(spin_http_string_t *ret, const char *s) {
ret->ptr = (char*) s;
ret->len = strlen(s);
}
void spin_http_string_dup(spin_http_string_t *ret, const char *s) {
ret->len = strlen(s);
ret->ptr = canonical_abi_realloc(NULL, 0, 1, ret->len);
memcpy(ret->ptr, s, ret->len);
}
void spin_http_string_free(spin_http_string_t *ret) {
canonical_abi_free(ret->ptr, ret->len, 1);
ret->ptr = NULL;
ret->len = 0;
}
void spin_http_body_free(spin_http_body_t *ptr) {
canonical_abi_free(ptr->ptr, ptr->len * 1, 1);
}
void spin_http_tuple2_string_string_free(spin_http_tuple2_string_string_t *ptr) {
spin_http_string_free(&ptr->f0);
spin_http_string_free(&ptr->f1);
}
void spin_http_headers_free(spin_http_headers_t *ptr) {
for (size_t i = 0; i < ptr->len; i++) {
spin_http_tuple2_string_string_free(&ptr->ptr[i]);
}
canonical_abi_free(ptr->ptr, ptr->len * 16, 4);
}
void spin_http_params_free(spin_http_params_t *ptr) {
for (size_t i = 0; i < ptr->len; i++) {
spin_http_tuple2_string_string_free(&ptr->ptr[i]);
}
canonical_abi_free(ptr->ptr, ptr->len * 16, 4);
}
void spin_http_uri_free(spin_http_uri_t *ptr) {
canonical_abi_free(ptr->ptr, ptr->len * 1, 1);
}
void spin_http_option_body_free(spin_http_option_body_t *ptr) {
switch (ptr->tag) {
case 1: {
spin_http_body_free(&ptr->val);
break;
}
}
}
void spin_http_request_free(spin_http_request_t *ptr) {
spin_http_uri_free(&ptr->uri);
spin_http_headers_free(&ptr->headers);
spin_http_params_free(&ptr->params);
spin_http_option_body_free(&ptr->body);
}
void spin_http_option_headers_free(spin_http_option_headers_t *ptr) {
switch (ptr->tag) {
case 1: {
spin_http_headers_free(&ptr->val);
break;
}
}
}
void spin_http_response_free(spin_http_response_t *ptr) {
spin_http_option_headers_free(&ptr->headers);
spin_http_option_body_free(&ptr->body);
}
static int64_t RET_AREA[7];
__attribute__((export_name("handle-http-request")))
int32_t __wasm_export_spin_http_handle_http_request(int32_t arg, int32_t arg0, int32_t arg1, int32_t arg2, int32_t arg3, int32_t arg4, int32_t arg5, int32_t arg6, int32_t arg7, int32_t arg8) {
spin_http_option_body_t variant;
variant.tag = arg6;
switch ((int32_t) variant.tag) {
case 0: {
break;
}
case 1: {
variant.val = (spin_http_body_t) { (uint8_t*)(arg7), (size_t)(arg8) };
break;
}
}
spin_http_request_t arg9 = (spin_http_request_t) {
arg,
(spin_http_uri_t) { (char*)(arg0), (size_t)(arg1) },
(spin_http_headers_t) { (spin_http_tuple2_string_string_t*)(arg2), (size_t)(arg3) },
(spin_http_params_t) { (spin_http_tuple2_string_string_t*)(arg4), (size_t)(arg5) },
variant,
};
spin_http_response_t ret;
spin_http_handle_http_request(&arg9, &ret);
int32_t variant11;
int32_t variant12;
int32_t variant13;
switch ((int32_t) ((ret).headers).tag) {
case 0: {
variant11 = 0;
variant12 = 0;
variant13 = 0;
break;
}
case 1: {
const spin_http_headers_t *payload10 = &((ret).headers).val;
variant11 = 1;
variant12 = (int32_t) (*payload10).ptr;
variant13 = (int32_t) (*payload10).len;
break;
}
}
int32_t variant16;
int32_t variant17;
int32_t variant18;
switch ((int32_t) ((ret).body).tag) {
case 0: {
variant16 = 0;
variant17 = 0;
variant18 = 0;
break;
}
case 1: {
const spin_http_body_t *payload15 = &((ret).body).val;
variant16 = 1;
variant17 = (int32_t) (*payload15).ptr;
variant18 = (int32_t) (*payload15).len;
break;
}
}
int32_t ptr = (int32_t) &RET_AREA;
*((int32_t*)(ptr + 48)) = variant18;
*((int32_t*)(ptr + 40)) = variant17;
*((int32_t*)(ptr + 32)) = variant16;
*((int32_t*)(ptr + 24)) = variant13;
*((int32_t*)(ptr + 16)) = variant12;
*((int32_t*)(ptr + 8)) = variant11;
*((int32_t*)(ptr + 0)) = (int32_t) ((ret).status);
return ptr;
}

86
sdk/go/http/spin-http.h Normal file
View File

@ -0,0 +1,86 @@
#ifndef __BINDINGS_SPIN_HTTP_H
#define __BINDINGS_SPIN_HTTP_H
#ifdef __cplusplus
extern "C"
{
#endif
#include <stdint.h>
#include <stdbool.h>
typedef struct {
char *ptr;
size_t len;
} spin_http_string_t;
void spin_http_string_set(spin_http_string_t *ret, const char *s);
void spin_http_string_dup(spin_http_string_t *ret, const char *s);
void spin_http_string_free(spin_http_string_t *ret);
typedef struct {
uint8_t *ptr;
size_t len;
} spin_http_body_t;
void spin_http_body_free(spin_http_body_t *ptr);
typedef struct {
spin_http_string_t f0;
spin_http_string_t f1;
} spin_http_tuple2_string_string_t;
void spin_http_tuple2_string_string_free(spin_http_tuple2_string_string_t *ptr);
typedef struct {
spin_http_tuple2_string_string_t *ptr;
size_t len;
} spin_http_headers_t;
void spin_http_headers_free(spin_http_headers_t *ptr);
typedef uint8_t spin_http_http_error_t;
#define SPIN_HTTP_HTTP_ERROR_SUCCESS 0
#define SPIN_HTTP_HTTP_ERROR_DESTINATION_NOT_ALLOWED 1
#define SPIN_HTTP_HTTP_ERROR_INVALID_URL 2
#define SPIN_HTTP_HTTP_ERROR_REQUEST_ERROR 3
#define SPIN_HTTP_HTTP_ERROR_RUNTIME_ERROR 4
typedef uint16_t spin_http_http_status_t;
typedef uint8_t spin_http_method_t;
#define SPIN_HTTP_METHOD_GET 0
#define SPIN_HTTP_METHOD_POST 1
#define SPIN_HTTP_METHOD_PUT 2
#define SPIN_HTTP_METHOD_DELETE 3
#define SPIN_HTTP_METHOD_PATCH 4
#define SPIN_HTTP_METHOD_HEAD 5
#define SPIN_HTTP_METHOD_OPTIONS 6
typedef struct {
spin_http_tuple2_string_string_t *ptr;
size_t len;
} spin_http_params_t;
void spin_http_params_free(spin_http_params_t *ptr);
typedef spin_http_string_t spin_http_uri_t;
void spin_http_uri_free(spin_http_uri_t *ptr);
typedef struct {
// `true` if `val` is present, `false` otherwise
bool tag;
spin_http_body_t val;
} spin_http_option_body_t;
void spin_http_option_body_free(spin_http_option_body_t *ptr);
typedef struct {
spin_http_method_t method;
spin_http_uri_t uri;
spin_http_headers_t headers;
spin_http_params_t params;
spin_http_option_body_t body;
} spin_http_request_t;
void spin_http_request_free(spin_http_request_t *ptr);
typedef struct {
// `true` if `val` is present, `false` otherwise
bool tag;
spin_http_headers_t val;
} spin_http_option_headers_t;
void spin_http_option_headers_free(spin_http_option_headers_t *ptr);
typedef struct {
spin_http_http_status_t status;
spin_http_option_headers_t headers;
spin_http_option_body_t body;
} spin_http_response_t;
void spin_http_response_free(spin_http_response_t *ptr);
void spin_http_handle_http_request(spin_http_request_t *req, spin_http_response_t *ret0);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,231 +1,193 @@
#include <stdlib.h>
#include "wasi-outbound-http.h"
#include <wasi-outbound-http.h>
__attribute__((weak, export_name("canonical_abi_realloc"))) void *canonical_abi_realloc(
void *ptr,
size_t orig_size,
size_t org_align,
size_t new_size)
{
__attribute__((weak, export_name("canonical_abi_realloc")))
void *canonical_abi_realloc(
void *ptr,
size_t orig_size,
size_t org_align,
size_t new_size
) {
void *ret = realloc(ptr, new_size);
if (!ret)
abort();
abort();
return ret;
}
__attribute__((weak, export_name("canonical_abi_free"))) void canonical_abi_free(
void *ptr,
size_t size,
size_t align)
{
__attribute__((weak, export_name("canonical_abi_free")))
void canonical_abi_free(
void *ptr,
size_t size,
size_t align
) {
free(ptr);
}
#include <string.h>
void wasi_outbound_http_string_set(wasi_outbound_http_string_t *ret, const char *s)
{
ret->ptr = (char *)s;
void wasi_outbound_http_string_set(wasi_outbound_http_string_t *ret, const char *s) {
ret->ptr = (char*) s;
ret->len = strlen(s);
}
void wasi_outbound_http_string_dup(wasi_outbound_http_string_t *ret, const char *s)
{
void wasi_outbound_http_string_dup(wasi_outbound_http_string_t *ret, const char *s) {
ret->len = strlen(s);
ret->ptr = canonical_abi_realloc(NULL, 0, 1, ret->len);
memcpy(ret->ptr, s, ret->len);
}
void wasi_outbound_http_string_free(wasi_outbound_http_string_t *ret)
{
void wasi_outbound_http_string_free(wasi_outbound_http_string_t *ret) {
canonical_abi_free(ret->ptr, ret->len, 1);
ret->ptr = NULL;
ret->len = 0;
}
void wasi_outbound_http_body_free(wasi_outbound_http_body_t *ptr)
{
void wasi_outbound_http_body_free(wasi_outbound_http_body_t *ptr) {
canonical_abi_free(ptr->ptr, ptr->len * 1, 1);
}
void wasi_outbound_http_tuple2_string_string_free(wasi_outbound_http_tuple2_string_string_t *ptr)
{
void wasi_outbound_http_tuple2_string_string_free(wasi_outbound_http_tuple2_string_string_t *ptr) {
wasi_outbound_http_string_free(&ptr->f0);
wasi_outbound_http_string_free(&ptr->f1);
}
void wasi_outbound_http_headers_free(wasi_outbound_http_headers_t *ptr)
{
for (size_t i = 0; i < ptr->len; i++)
{
void wasi_outbound_http_headers_free(wasi_outbound_http_headers_t *ptr) {
for (size_t i = 0; i < ptr->len; i++) {
wasi_outbound_http_tuple2_string_string_free(&ptr->ptr[i]);
}
canonical_abi_free(ptr->ptr, ptr->len * 16, 4);
}
void wasi_outbound_http_params_free(wasi_outbound_http_params_t *ptr)
{
for (size_t i = 0; i < ptr->len; i++)
{
void wasi_outbound_http_params_free(wasi_outbound_http_params_t *ptr) {
for (size_t i = 0; i < ptr->len; i++) {
wasi_outbound_http_tuple2_string_string_free(&ptr->ptr[i]);
}
canonical_abi_free(ptr->ptr, ptr->len * 16, 4);
}
void wasi_outbound_http_uri_free(wasi_outbound_http_uri_t *ptr)
{
void wasi_outbound_http_uri_free(wasi_outbound_http_uri_t *ptr) {
canonical_abi_free(ptr->ptr, ptr->len * 1, 1);
}
void wasi_outbound_http_option_body_free(wasi_outbound_http_option_body_t *ptr)
{
switch (ptr->tag)
{
case 1:
{
wasi_outbound_http_body_free(&ptr->val);
break;
}
void wasi_outbound_http_option_body_free(wasi_outbound_http_option_body_t *ptr) {
switch (ptr->tag) {
case 1: {
wasi_outbound_http_body_free(&ptr->val);
break;
}
}
}
void wasi_outbound_http_request_free(wasi_outbound_http_request_t *ptr)
{
void wasi_outbound_http_request_free(wasi_outbound_http_request_t *ptr) {
wasi_outbound_http_uri_free(&ptr->uri);
wasi_outbound_http_headers_free(&ptr->headers);
wasi_outbound_http_params_free(&ptr->params);
wasi_outbound_http_option_body_free(&ptr->body);
}
void wasi_outbound_http_option_headers_free(wasi_outbound_http_option_headers_t *ptr)
{
switch (ptr->tag)
{
case 1:
{
wasi_outbound_http_headers_free(&ptr->val);
break;
}
void wasi_outbound_http_option_headers_free(wasi_outbound_http_option_headers_t *ptr) {
switch (ptr->tag) {
case 1: {
wasi_outbound_http_headers_free(&ptr->val);
break;
}
}
}
void wasi_outbound_http_response_free(wasi_outbound_http_response_t *ptr)
{
void wasi_outbound_http_response_free(wasi_outbound_http_response_t *ptr) {
wasi_outbound_http_option_headers_free(&ptr->headers);
wasi_outbound_http_option_body_free(&ptr->body);
}
typedef struct
{
typedef struct {
// 0 if `val` is `ok`, 1 otherwise
uint8_t tag;
union
{
union {
wasi_outbound_http_response_t ok;
wasi_outbound_http_http_error_t err;
} val;
} wasi_outbound_http_expected_response_http_error_t;
static int64_t RET_AREA[8];
__attribute__((import_module("wasi-outbound-http"), import_name("request"))) void __wasm_import_wasi_outbound_http_request(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t);
wasi_outbound_http_http_error_t wasi_outbound_http_request(wasi_outbound_http_request_t *req, wasi_outbound_http_response_t *ret0)
{
__attribute__((import_module("wasi-outbound-http"), import_name("request")))
void __wasm_import_wasi_outbound_http_request(int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t);
wasi_outbound_http_http_error_t wasi_outbound_http_request(wasi_outbound_http_request_t *req, wasi_outbound_http_response_t *ret0) {
int32_t variant;
switch ((int32_t)(*req).method)
{
case 0:
{
variant = 0;
break;
}
case 1:
{
variant = 1;
break;
}
case 2:
{
variant = 2;
break;
}
case 3:
{
variant = 3;
break;
}
case 4:
{
variant = 4;
break;
}
case 5:
{
variant = 5;
break;
}
case 6:
{
variant = 6;
break;
}
switch ((int32_t) (*req).method) {
case 0: {
variant = 0;
break;
}
case 1: {
variant = 1;
break;
}
case 2: {
variant = 2;
break;
}
case 3: {
variant = 3;
break;
}
case 4: {
variant = 4;
break;
}
case 5: {
variant = 5;
break;
}
case 6: {
variant = 6;
break;
}
}
int32_t variant8;
int32_t variant9;
int32_t variant10;
switch ((int32_t)((*req).body).tag)
{
case 0:
{
variant8 = 0;
variant9 = 0;
variant10 = 0;
break;
switch ((int32_t) ((*req).body).tag) {
case 0: {
variant8 = 0;
variant9 = 0;
variant10 = 0;
break;
}
case 1: {
const wasi_outbound_http_body_t *payload7 = &((*req).body).val;
variant8 = 1;
variant9 = (int32_t) (*payload7).ptr;
variant10 = (int32_t) (*payload7).len;
break;
}
}
case 1:
{
const wasi_outbound_http_body_t *payload7 = &((*req).body).val;
variant8 = 1;
variant9 = (int32_t)(*payload7).ptr;
variant10 = (int32_t)(*payload7).len;
break;
}
}
int32_t ptr = (int32_t)&RET_AREA;
__wasm_import_wasi_outbound_http_request(variant, (int32_t)((*req).uri).ptr, (int32_t)((*req).uri).len, (int32_t)((*req).headers).ptr, (int32_t)((*req).headers).len, (int32_t)((*req).params).ptr, (int32_t)((*req).params).len, variant8, variant9, variant10, ptr);
int32_t ptr = (int32_t) &RET_AREA;
__wasm_import_wasi_outbound_http_request(variant, (int32_t) ((*req).uri).ptr, (int32_t) ((*req).uri).len, (int32_t) ((*req).headers).ptr, (int32_t) ((*req).headers).len, (int32_t) ((*req).params).ptr, (int32_t) ((*req).params).len, variant8, variant9, variant10, ptr);
wasi_outbound_http_expected_response_http_error_t variant13;
variant13.tag = *((int32_t *)(ptr + 0));
switch ((int32_t)variant13.tag)
{
case 0:
{
wasi_outbound_http_option_headers_t variant11;
variant11.tag = *((int32_t *)(ptr + 16));
switch ((int32_t)variant11.tag)
{
case 0:
{
break;
}
case 1:
{
variant11.val = (wasi_outbound_http_headers_t){(wasi_outbound_http_tuple2_string_string_t *)(*((int32_t *)(ptr + 24))), (size_t)(*((int32_t *)(ptr + 32)))};
break;
}
}
wasi_outbound_http_option_body_t variant12;
variant12.tag = *((int32_t *)(ptr + 40));
switch ((int32_t)variant12.tag)
{
case 0:
{
break;
}
case 1:
{
variant12.val = (wasi_outbound_http_body_t){(uint8_t *)(*((int32_t *)(ptr + 48))), (size_t)(*((int32_t *)(ptr + 56)))};
break;
}
}
variant13.val.ok = (wasi_outbound_http_response_t){
(uint16_t)(*((int32_t *)(ptr + 8))),
variant13.tag = *((int32_t*) (ptr + 0));
switch ((int32_t) variant13.tag) {
case 0: {
wasi_outbound_http_option_headers_t variant11;
variant11.tag = *((int32_t*) (ptr + 16));
switch ((int32_t) variant11.tag) {
case 0: {
break;
}
case 1: {
variant11.val = (wasi_outbound_http_headers_t) { (wasi_outbound_http_tuple2_string_string_t*)(*((int32_t*) (ptr + 24))), (size_t)(*((int32_t*) (ptr + 32))) };
break;
}
}
wasi_outbound_http_option_body_t variant12;
variant12.tag = *((int32_t*) (ptr + 40));
switch ((int32_t) variant12.tag) {
case 0: {
break;
}
case 1: {
variant12.val = (wasi_outbound_http_body_t) { (uint8_t*)(*((int32_t*) (ptr + 48))), (size_t)(*((int32_t*) (ptr + 56))) };
break;
}
}
variant13.val.ok = (wasi_outbound_http_response_t) {
(uint16_t) (*((int32_t*) (ptr + 8))),
variant11,
variant12,
};
break;
}
case 1:
{
variant13.val.err = *((int32_t *)(ptr + 8));
break;
}
};
break;
}
case 1: {
variant13.val.err = *((int32_t*) (ptr + 8));
break;
}
}
*ret0 = variant13.val.ok;
return variant13.tag ? variant13.val.err : -1;