diff options
author | Andrew Clayton <a.clayton@nginx.com> | 2023-11-28 23:53:57 +0000 |
---|---|---|
committer | Andrew Clayton <a.clayton@nginx.com> | 2023-11-28 23:58:28 +0000 |
commit | 76a6880605195d253dd4837204a252816bd5a396 (patch) | |
tree | 08621e679127f757e367671aee497396b62bb013 /c/wasi-http/echo-request/component.c | |
parent | e3a37a1bb4908b02553096afaeb380dbc85bb7bb (diff) | |
download | project_blackbird-76a6880605195d253dd4837204a252816bd5a396.tar.gz project_blackbird-76a6880605195d253dd4837204a252816bd5a396.tar.bz2 |
Add a wasi-http echo-request component in C
This adds a wasi-http version of luw-echo-request.c[0]
This works under the wasmtime v15 CLI serve command.
e.g
$ ~/src/c/wasm/wasmtime-v15.0.0-x86_64-linux/wasmtime serve c/wasi-http/echo-request/component.wasm
Serving HTTP on http://0.0.0.0:8080/
$ curl localhost:8080/hello
*** Welcome to WebAssembly with wasi-http / C ***
[Request Info]
REQUEST_PATH = /hello
METHOD = GET
QUERY =
[Request Headers]
host = localhost:8080
user-agent = curl/8.2.1
accept = */*
[0]: <https://github.com/nginx/unit-wasm/blob/main/examples/c/luw-echo-request.c>
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
Diffstat (limited to 'c/wasi-http/echo-request/component.c')
-rw-r--r-- | c/wasi-http/echo-request/component.c | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/c/wasi-http/echo-request/component.c b/c/wasi-http/echo-request/component.c new file mode 100644 index 0000000..cecf390 --- /dev/null +++ b/c/wasi-http/echo-request/component.c @@ -0,0 +1,173 @@ +/* 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 <stdbool.h> +#include <stdint.h> +#include <string.h> + +#include "proxy.h" + +#define ex(...) \ + do { \ + printf(__VA_ARGS__); \ + exit(EXIT_FAILURE); \ + } while (0); + +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) +{ + bool ok; + 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_error_code_t http_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); + + ok = wasi_http_types_method_incoming_request_consume(b_req, &r_body); + if (!ok) + ex("wasi_http_types_method_incoming_request_consume() failed\n"); + b_r_body = wasi_http_types_borrow_incoming_body(r_body); + ok = wasi_http_types_method_incoming_body_stream(b_r_body, &in_stream); + if (!ok) + ex("wasi_http_types_method_incoming_body_stream() failed\n"); + b_in_stream = wasi_io_streams_borrow_input_stream(in_stream); + + ok = wasi_io_streams_method_input_stream_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); + + ok = wasi_http_types_method_fields_append(b_fields, &key, &value, + &hdr_err); + if (!ok) + ex("wasi_http_types_method_fields_append() failed\n"); + + resp = wasi_http_types_constructor_outgoing_response(fields); + + b_resp = wasi_http_types_borrow_outgoing_response(resp); + ok = wasi_http_types_method_outgoing_response_body(b_resp, &body); + if (!ok) + ex("wasi_http_types_method_outgoing_response_body() failed\n"); + b_body = wasi_http_types_borrow_outgoing_body(body); + + ok = wasi_http_types_method_outgoing_body_write(b_body, &out_stream); + if (!ok) + ex("wasi_http_types_method_outgoing_body_write() failed\n"); + 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_write(b_out_stream, + &stream_data, + &stream_err); + if (!ok) + ex("wasi_io_streams_method_output_stream_write() failed\n"); + + free(out_ptr); + + wasi_http_types_static_response_outparam_set(response_out, &rerr); + + wasi_io_streams_output_stream_drop_borrow(out_stream); + + ok = wasi_http_types_static_outgoing_body_finish(body, NULL, &http_err); + if (!ok) + ex("wasi_http_types_static_outgoing_body_finish() failed\n"); +} |