summaryrefslogtreecommitdiffhomepage
path: root/examples/c/upload-reflector-raw.c
diff options
context:
space:
mode:
authorAndrew Clayton <a.clayton@nginx.com>2023-08-02 17:03:48 +0100
committerAndrew Clayton <a.clayton@nginx.com>2023-08-21 23:24:12 +0100
commitd6ed6a219b31a58526721f96195c80061d41ce54 (patch)
tree17a1fd6ecf72a327916ff0f8bc7aaf85b981ceff /examples/c/upload-reflector-raw.c
downloadunit-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.c223
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;
+}