Last active
December 1, 2023 22:17
-
-
Save ac000/906707af37b42cdcc9d3cc4c2715da99 to your computer and use it in GitHub Desktop.
libunit-wasm vs wasi-http
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This will compare the libunit-wasm luw-echo-request module with the same | |
implemented using wasi-http and built as a component. | |
You will notice we don't get all the same information with wasi-http. | |
I also hasten to add that I have somewhat sanitised the wasi-http API (which of | |
course is an autogenerated monstrosity) by removing `_0_2_0_rc_2023_11_10` and | |
`_0_2_0_RC_2023_11_10` from all the `wasi_` and `WASI_` function/type names. | |
I have also removed _all_ the error checking from the below pasted wasi-http | |
version. | |
The wasi-http component is running under the wasmtime CLI. | |
(I now have a version of this (using the wasi-http wit files from Alex's | |
example) running under the new language module) | |
I'll let you decide which API is nicer! | |
First up is the wasi-http version, followed by the libunit-wasm version. | |
## wasi-http | |
$ curl -X POST -d "Hello World" --cookie "mycookie=hmmm" localhost:8080/echo/?q=a | |
*** Welcome to WebAssembly with wasi-http / C *** | |
[Request Info] | |
REQUEST_PATH = /echo/?q=a | |
METHOD = POST | |
QUERY = q=a | |
[Request Headers] | |
host = localhost:8080 | |
user-agent = curl/8.2.1 | |
accept = */* | |
cookie = mycookie=hmmm | |
content-length = 11 | |
content-type = application/x-www-form-urlencoded | |
[POST data] | |
Hello World | |
## libunit-wasm | |
$ curl -X POST -d "Hello World" --cookie "mycookie=hmmm" localhost:8080/echo/?q=a | |
*** Welcome to WebAssembly on Unit! [libunit-wasm (0.3.0/0x00030000)] *** | |
[Request Info] | |
REQUEST_PATH = /echo/?q=a | |
METHOD = POST | |
VERSION = HTTP/1.1 | |
QUERY = q=a | |
REMOTE = ::1 | |
LOCAL_ADDR = ::1 | |
LOCAL_PORT = 8080 | |
SERVER_NAME = localhost | |
[Request Headers] | |
Host = localhost:8080 | |
User-Agent = curl/8.0.1 | |
Accept = */* | |
Cookie = mycookie=hmmm | |
Content-Length = 11 | |
Content-Type = application/x-www-form-urlencoded | |
[POST data] | |
Hello World |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SPDX-License-Identifier: Apache-2.0 */ | |
/* | |
* component.c - Example of writing a wasi-http Wasm component | |
* | |
* Copyright (C) Andrew Clayton | |
* Copyright (C) F5, Inc. | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdint.h> | |
#include <string.h> | |
#include "proxy.h" | |
static const struct { | |
const char *method; | |
} http_method_map[] = { | |
[WASI_HTTP_TYPES_METHOD_GET] = { "GET" }, | |
[WASI_HTTP_TYPES_METHOD_HEAD] = { "HEAD" }, | |
[WASI_HTTP_TYPES_METHOD_POST] = { "POST" }, | |
[WASI_HTTP_TYPES_METHOD_PUT] = { "PUT" }, | |
[WASI_HTTP_TYPES_METHOD_DELETE] = { "DELETE" }, | |
[WASI_HTTP_TYPES_METHOD_CONNECT] = { "CONNECT" }, | |
[WASI_HTTP_TYPES_METHOD_OPTIONS] = { "OPTIONS" }, | |
[WASI_HTTP_TYPES_METHOD_TRACE] = { "TRACE" }, | |
[WASI_HTTP_TYPES_METHOD_PATCH] = { "PATCH" }, | |
[WASI_HTTP_TYPES_METHOD_OTHER] = { "OTHER" } | |
}; | |
void exports_wasi_http_incoming_handler_handle( | |
exports_wasi_http_incoming_handler_own_incoming_request_t request, | |
exports_wasi_http_incoming_handler_own_response_outparam_t response_out) | |
{ | |
FILE *out; | |
size_t size; | |
char *out_ptr; | |
char *ptr; | |
char clen[32]; | |
wasi_http_types_borrow_incoming_request_t b_req; | |
wasi_http_types_own_headers_t hdrs; | |
wasi_http_types_borrow_fields_t b_hdrs; | |
wasi_http_types_own_incoming_body_t r_body; | |
wasi_http_types_borrow_incoming_body_t b_r_body; | |
wasi_http_types_own_outgoing_response_t resp; | |
wasi_http_types_borrow_outgoing_response_t b_resp; | |
wasi_http_types_own_fields_t fields; | |
wasi_http_types_borrow_fields_t b_fields; | |
wasi_http_types_result_own_outgoing_response_error_code_t rerr = { }; | |
wasi_http_types_own_outgoing_body_t body; | |
wasi_http_types_borrow_outgoing_body_t b_body; | |
wasi_io_streams_own_output_stream_t out_stream; | |
wasi_io_streams_borrow_output_stream_t b_out_stream; | |
wasi_io_streams_list_u8_t stream_data; | |
wasi_io_streams_stream_error_t stream_err; | |
wasi_http_types_header_error_t hdr_err; | |
wasi_http_types_field_key_t key; | |
wasi_http_types_field_value_t value; | |
wasi_http_types_method_t method; | |
wasi_http_types_list_tuple2_field_key_field_value_t fvk; | |
wasi_http_types_own_input_stream_t in_stream; | |
wasi_io_streams_borrow_input_stream_t b_in_stream; | |
wasi_io_streams_list_u8_t data; | |
wasi_io_streams_stream_error_t in_stream_err; | |
proxy_string_t prstr; | |
b_req = wasi_http_types_borrow_incoming_request(request); | |
out = open_memstream(&out_ptr, &size); | |
#define BUF_ADD(fmt, ...) \ | |
fprintf(out, fmt, ##__VA_ARGS__); | |
BUF_ADD("*** Welcome to WebAssembly with wasi-http / C ***\n\n"); | |
BUF_ADD("[Request Info]\n"); | |
wasi_http_types_method_incoming_request_path_with_query(b_req, &prstr); | |
BUF_ADD("REQUEST_PATH = %.*s\n", (int)prstr.len, prstr.ptr); | |
wasi_http_types_method_incoming_request_method(b_req, &method); | |
BUF_ADD("METHOD = %s\n", http_method_map[method.tag].method); | |
ptr = memchr(prstr.ptr, '?', prstr.len); | |
BUF_ADD("QUERY = %.*s\n", | |
ptr ? (int)(((char *)(prstr.ptr + prstr.len)) - ptr - 1) : 0, | |
ptr ? ptr + 1 : ""); | |
BUF_ADD("\n[Request Headers]\n"); | |
hdrs = wasi_http_types_method_incoming_request_headers(b_req); | |
b_hdrs = wasi_http_types_borrow_fields(hdrs); | |
wasi_http_types_method_fields_entries(b_hdrs, &fvk); | |
for (size_t i = 0; i < fvk.len; i++) | |
BUF_ADD("%.*s = %.*s\n", | |
(int)fvk.ptr[i].f0.len, fvk.ptr[i].f0.ptr, | |
(int)fvk.ptr[i].f1.len, fvk.ptr[i].f1.ptr); | |
wasi_http_types_list_tuple2_field_key_field_value_free(&fvk); | |
wasi_http_types_method_incoming_request_consume(b_req, &r_body); | |
b_r_body = wasi_http_types_borrow_incoming_body(r_body); | |
wasi_http_types_method_incoming_body_stream(b_r_body, &in_stream); | |
b_in_stream = wasi_io_streams_borrow_input_stream(in_stream); | |
ok = wasi_io_streams_method_input_stream_blocking_read(b_in_stream, | |
8 * 1024*1024, | |
&data, | |
&in_stream_err); | |
if (method.tag == WASI_HTTP_TYPES_METHOD_POST || | |
method.tag == WASI_HTTP_TYPES_METHOD_PUT) { | |
BUF_ADD("\n[%s data]\n", | |
http_method_map[method.tag].method); | |
BUF_ADD("%.*s\n", (int)data.len, data.ptr); | |
} | |
fclose(out); | |
fields = wasi_http_types_constructor_fields(); | |
b_fields = wasi_http_types_borrow_fields(fields); | |
proxy_string_set((proxy_string_t *)&key, "Content-Length"); | |
sprintf(clen, "%zu", size); | |
proxy_string_set((proxy_string_t *)&value, clen); | |
wasi_http_types_method_fields_append(b_fields, &key, &value, | |
&hdr_err); | |
resp = wasi_http_types_constructor_outgoing_response(fields); | |
b_resp = wasi_http_types_borrow_outgoing_response(resp); | |
wasi_http_types_method_outgoing_response_body(b_resp, &body); | |
b_body = wasi_http_types_borrow_outgoing_body(body); | |
wasi_http_types_method_outgoing_body_write(b_body, &out_stream); | |
b_out_stream = wasi_io_streams_borrow_output_stream(out_stream); | |
stream_data.len = size; | |
stream_data.ptr = (uint8_t *)out_ptr; | |
ok = wasi_io_streams_method_output_stream_blocking_write_and_flush( | |
b_out_stream, | |
&stream_data, | |
&stream_err); | |
free(out_ptr); | |
wasi_http_types_static_response_outparam_set(response_out, &rerr); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* SPDX-License-Identifier: Apache-2.0 */ | |
/* | |
* examples/c/luw-echo-request.c - Example of writing a WASM module for use | |
* with Unit using libunit-wasm | |
* | |
* Copyright (C) Andrew Clayton | |
* Copyright (C) F5, Inc. | |
*/ | |
#define _XOPEN_SOURCE 500 | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <stdbool.h> | |
#include <string.h> | |
#include "unit/unit-wasm.h" | |
static u8 *request_buf; | |
__luw_export_name("luw_module_end_handler") | |
void luw_module_end_handler(void) | |
{ | |
free(request_buf); | |
} | |
__luw_export_name("luw_module_init_handler") | |
void luw_module_init_handler(void) | |
{ | |
request_buf = malloc(luw_mem_get_init_size()); | |
} | |
static bool hdr_iter_func(luw_ctx_t *ctx, const char *name, const char *value, | |
void *user_data __luw_unused) | |
{ | |
luw_mem_writep(ctx, "%s = %s\n", name, value); | |
return true; | |
} | |
__luw_export_name("luw_request_handler") | |
int luw_request_handler(u8 *addr) | |
{ | |
luw_ctx_t ctx; | |
char clen[32]; | |
const char *method; | |
luw_init_ctx(&ctx, addr, 4096 /* Response offset */); | |
/* Take a copy of the request and use that */ | |
luw_set_req_buf(&ctx, &request_buf, LUW_SRB_NONE); | |
#define BUF_ADD(fmt, member) \ | |
luw_mem_writep(&ctx, fmt, luw_get_http_##member(&ctx)); | |
luw_mem_writep(&ctx, | |
" *** Welcome to WebAssembly on Unit! " | |
"[libunit-wasm (%d.%d.%d/%#0.8x)] ***\n\n", | |
LUW_VERSION_MAJOR, LUW_VERSION_MINOR, LUW_VERSION_PATCH, | |
LUW_VERSION_NUMBER); | |
luw_mem_writep(&ctx, "[Request Info]\n"); | |
BUF_ADD("REQUEST_PATH = %s\n", path); | |
BUF_ADD("METHOD = %s\n", method); | |
BUF_ADD("VERSION = %s\n", version); | |
BUF_ADD("QUERY = %s\n", query); | |
BUF_ADD("REMOTE = %s\n", remote); | |
BUF_ADD("LOCAL_ADDR = %s\n", local_addr); | |
BUF_ADD("LOCAL_PORT = %s\n", local_port); | |
BUF_ADD("SERVER_NAME = %s\n", server_name); | |
luw_mem_writep(&ctx, "\n[Request Headers]\n"); | |
luw_http_hdr_iter(&ctx, hdr_iter_func, NULL); | |
method = luw_get_http_method(&ctx); | |
if (memcmp(method, "POST", strlen(method)) == 0 || | |
memcmp(method, "PUT", strlen(method)) == 0) { | |
luw_mem_writep(&ctx, "\n[%s data]\n", method); | |
luw_mem_writep_data(&ctx, luw_get_http_content(&ctx), | |
luw_get_http_content_len(&ctx)); | |
luw_mem_writep(&ctx, "\n"); | |
} | |
luw_http_init_headers(&ctx, 2, 0); | |
snprintf(clen, sizeof(clen), "%lu", luw_get_response_data_size(&ctx)); | |
luw_http_add_header(&ctx, "Content-Type", "text/plain"); | |
luw_http_add_header(&ctx, "Content-Length", clen); | |
luw_http_send_headers(&ctx); | |
luw_http_send_response(&ctx); | |
/* Tell Unit no more data to send */ | |
luw_http_response_end(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment