diff options
author | Andrew Clayton <a.clayton@nginx.com> | 2023-08-02 17:03:48 +0100 |
---|---|---|
committer | Andrew Clayton <a.clayton@nginx.com> | 2023-08-21 23:24:12 +0100 |
commit | d6ed6a219b31a58526721f96195c80061d41ce54 (patch) | |
tree | 17a1fd6ecf72a327916ff0f8bc7aaf85b981ceff /examples/c/upload-reflector-raw.c | |
download | unit-wasm-d6ed6a219b31a58526721f96195c80061d41ce54.tar.gz unit-wasm-d6ed6a219b31a58526721f96195c80061d41ce54.tar.bz2 |
Initial commitv0.1.0
libunit-wasm and example C and Rust WebAssembly modules for NGINX Unit.
Co-developed-by: Timo Stark <t.stark@nginx.com>
Co-developed-by: Liam Crilly <liam@nginx.com>
Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
Diffstat (limited to 'examples/c/upload-reflector-raw.c')
-rw-r--r-- | examples/c/upload-reflector-raw.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/examples/c/upload-reflector-raw.c b/examples/c/upload-reflector-raw.c new file mode 100644 index 0000000..3da4f8d --- /dev/null +++ b/examples/c/upload-reflector-raw.c @@ -0,0 +1,223 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* + * Copyright (C) Andrew Clayton + * Copyright (C) F5, Inc. + */ + +/* + * upload-reflector-raw.c - Raw example of writing a WASM module for use with + * Unit + * + * Download the wasi-sysroot tarball from https://github.com/WebAssembly/wasi-sdk/releases + */ + +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "unit-wasm-raw.h" + +static size_t total_response_sent; + +static u8 *request_buf; + +__attribute__((import_module("env"), import_name("nxt_wasm_get_init_mem_size"))) +u32 nxt_wasm_get_init_mem_size(void); +__attribute__((import_module("env"), import_name("nxt_wasm_response_end"))) +void nxt_wasm_response_end(void); +__attribute__((import_module("env"), import_name("nxt_wasm_send_response"))) +void nxt_wasm_send_response(u32 offset); + +__attribute__((export_name("wasm_response_end_handler"))) +void wasm_response_end_handler(void) +{ + total_response_sent = 0; +} + +__attribute__((export_name("wasm_request_end_handler"))) +void wasm_request_end_handler(void) +{ + if (!request_buf) + return; + + free(request_buf); + request_buf = NULL; +} + +__attribute__((export_name("wasm_free_handler"))) +void wasm_free_handler(u32 addr) +{ + free((void *)addr); +} + +__attribute__((export_name("wasm_malloc_handler"))) +u32 wasm_malloc_handler(size_t size) +{ + return (u32)malloc(size); +} + +static int upload_reflector(u8 *addr) +{ + size_t mem_size = nxt_wasm_get_init_mem_size(); + size_t rsize = sizeof(struct resp); + size_t write_bytes; + struct req *req; + struct resp *resp; + + printf("==[WASM RESP]== %s:\n", __func__); + + resp = (struct resp *)addr; + req = (struct req *)request_buf; + + printf("==[WASM RESP]== resp@%p\n", resp); + printf("==[WASM RESP]== req@%p\n", req); + printf("==[WASM RESP]== req->content_len : %u\n", req->content_len); + + resp = (struct resp *)addr; + + /* Send headers */ + if (total_response_sent == 0) { + const char *field; + struct hdr_field *f; + struct hdr_field *f_end; + char ct[256]; + + /* Try to set the Content-Type */ + f_end = req->fields + req->nr_fields; + for (f = req->fields; f < f_end; f++) { + field = (const char *)(u8 *)req + f->name_offs; + + if (strncasecmp(field, "Content-Type", 12) == 0) { + snprintf(ct, sizeof(ct), "%.*s", f->value_len, + (u8 *)req + f->value_offs); + break; + } + + field = NULL; + } + if (!field) + sprintf(ct, "application/octet-stream"); + + send_headers(addr, ct, req->content_len); + } + + write_bytes = req->content_sent; + if (write_bytes > mem_size - rsize) + write_bytes = mem_size - rsize; + + printf("==[WASM RESP]== write_bytes : %lu\n", write_bytes); + printf("==[WASM RESP]== req->content_len : %u\n", req->content_len); + printf("==[WASM RESP]== total_response_sent : %lu\n", + total_response_sent); + + printf("==[WASM RESP]== Copying (%lu) bytes of data from [%p+%lx] to " + "[%p]\n", write_bytes, req, + req->content_offs + total_response_sent, resp->data); + memcpy(resp->data, + (u8 *)req + req->content_offs + total_response_sent, + write_bytes); + + total_response_sent += write_bytes; + resp->size = write_bytes; + printf("==[WASM RESP]== resp->size : %u\n", resp->size); + + nxt_wasm_send_response(0); + + if (total_response_sent == req->content_len) { + printf("==[WASM RESP]== All data sent. Cleaning up...\n"); + total_response_sent = 0; + + free(request_buf); + request_buf = NULL; + + /* Tell Unit no more data to send */ + nxt_wasm_response_end(); + } + + return 0; +} + +__attribute__((export_name("wasm_request_handler"))) +int wasm_request_handler(u8 *addr) +{ + struct req *req = (struct req *)addr; + struct req *rb = (struct req *)request_buf; + + printf("==[WASM REQ]== %s:\n", __func__); + + /* + * This function _may_ be called multiple times during a single + * request if there is a large amount of data to transfer. + * + * Some useful request meta data: + * + * req->content_len contains the overall size of the POST/PUT + * data. + * req->content_sent shows how much of the body content has been + * in _this_ request. + * req->total_content_sent shows how much of it has been sent in + * total. + * req->content_offs is the offset in the passed in memory where + * the body content starts. + * + * For new requests req->request_size shows the total size of + * _this_ request, incl the req structure itself. + * For continuation requests, req->request_size is just the amount + * of new content, i.e req->content_sent + * + * When req->content_len == req->total_content_sent, that's the end + * of that request. + */ + + if (!request_buf) { + /* + * Just allocate memory for the total amount of data we + * expect to get, this includes the request structure + * itself as well as any body content. + */ + printf("==[WASM REQ]== malloc(%u)\n", + req->content_offs + req->content_len); + request_buf = malloc(req->content_offs + req->content_len); + + /* + * Regardless of how much memory we allocated above, here + * we only want to copy the amount of data we actually + * received in this request. + */ + printf("==[WASM REQ]== req->request_size : %u\n", + req->request_size); + memcpy(request_buf, addr, req->request_size); + + rb = (struct req *)request_buf; + printf("==[WASM REQ]== rb@%p\n", rb); + printf("==[WASM REQ]== request_buf@%p\n", request_buf); + printf("==[WASM REQ]== rb->content_offs : %u\n", + rb->content_offs); + printf("==[WASM REQ]== rb->content_len : %u\n", + rb->content_len); + printf("==[WASM REQ]== rb->content_sent : %u\n", + rb->content_sent); + printf("==[WASM REQ]== rb->request_size : %u\n", + rb->request_size); + } else { + memcpy(request_buf + rb->request_size, addr + req->content_offs, + req->request_size); + + printf("==[WASM REQ +]== req->content_offs : %u\n", + req->content_offs); + printf("==[WASM REQ +]== req->content_sent : %u\n", + req->content_sent); + printf("==[WASM REQ +]== req->request_size : %u\n", + req->request_size); + + rb->content_sent = req->content_sent; + rb->total_content_sent = req->total_content_sent; + } + + upload_reflector(addr); + + return 0; +} |