/* 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 #include #include #include #include #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_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_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); 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_blocking_write_and_flush( b_out_stream, &stream_data, &stream_err); if (!ok) ex("wasi_io_streams_method_output_stream_blocking_write_and_flush() failed\n"); free(out_ptr); wasi_http_types_static_response_outparam_set(response_out, &rerr); }