summaryrefslogtreecommitdiffhomepage
path: root/examples/c
diff options
context:
space:
mode:
Diffstat (limited to 'examples/c')
-rw-r--r--examples/c/Makefile40
-rw-r--r--examples/c/echo-request-raw.c187
-rw-r--r--examples/c/luw-echo-request.c98
-rw-r--r--examples/c/luw-upload-reflector.c101
-rw-r--r--examples/c/unit-wasm-raw.c46
-rw-r--r--examples/c/unit-wasm-raw.h87
-rw-r--r--examples/c/upload-reflector-raw.c223
7 files changed, 782 insertions, 0 deletions
diff --git a/examples/c/Makefile b/examples/c/Makefile
new file mode 100644
index 0000000..1b10269
--- /dev/null
+++ b/examples/c/Makefile
@@ -0,0 +1,40 @@
+include ../../shared.mk
+
+CFLAGS += -I../../src/c/include
+LIBS = -L../../src/c -lunit-wasm
+
+SDIR = examples/c
+
+LUW_SRCDIR = ../../src/c
+
+luw_deps = $(LUW_SRCDIR)/libunit-wasm.a \
+ $(LUW_SRCDIR)/include/unit/unit-wasm.h
+
+examples: examples-luw
+
+examples-luw: luw-echo-request.wasm luw-upload-reflector.wasm
+
+examples-raw: echo-request-raw.wasm upload-reflector-raw.wasm
+
+luw-echo-request.wasm: luw-echo-request.c $(luw_deps)
+ $(PP_CCLNK) $(SDIR)/$@
+ $(v)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+luw-upload-reflector.wasm: luw-upload-reflector.c $(luw_deps)
+ $(PP_CCLNK) $(SDIR)/$@
+ $(v)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
+
+unit-wasm-raw.o: unit-wasm-raw.c unit-wasm-raw.h
+ $(PP_CC) $(SDIR)/$@
+ $(v)$(CC) $(CFLAGS) -c $<
+
+echo-request-raw.wasm: echo-request-raw.c unit-wasm-raw.o
+ $(PP_CCLNK) $(SDIR)/$@
+ $(v)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< unit-wasm-raw.o
+
+upload-reflector-raw.wasm: upload-reflector-raw.c unit-wasm-raw.o
+ $(PP_CCLNK) $(SDIR)/$@
+ $(v)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< unit-wasm-raw.o
+
+clean:
+ rm -f *.wasm *.o *.gch
diff --git a/examples/c/echo-request-raw.c b/examples/c/echo-request-raw.c
new file mode 100644
index 0000000..2071597
--- /dev/null
+++ b/examples/c/echo-request-raw.c
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/*
+ * Copyright (C) Andrew Clayton
+ * Copyright (C) F5, Inc.
+ */
+
+/*
+ * echo-request-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 <stdint.h>
+#include <string.h>
+
+#include "unit-wasm-raw.h"
+
+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_module_end_handler")))
+void wasm_module_end_handler(void)
+{
+ free(request_buf);
+}
+
+__attribute__((export_name("wasm_module_init_handler")))
+void wasm_module_init_handler(void)
+{
+ request_buf = malloc(nxt_wasm_get_init_mem_size());
+}
+
+__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 echo_request(u8 *addr)
+{
+ u8 *p;
+ const char *method;
+ struct req *req;
+ struct resp *resp;
+ struct hdr_field *hf;
+ struct hdr_field *hf_end;
+ static const int resp_offs = 4096;
+
+ printf("==[WASM RESP]== %s:\n", __func__);
+
+ /*
+ * For convenience, we will return our headers at the start
+ * of the shared memory so leave a little space (resp_offs)
+ * before storing the main response.
+ *
+ * send_headers() will return the start of the shared memory,
+ * echo_request() will return the start of the shared memory
+ * plus resp_offs.
+ */
+ resp = (struct resp *)(addr + resp_offs);
+
+ req = (struct req *)request_buf;
+
+#define BUF_ADD(name, member) \
+ do { \
+ p = mempcpy(p, name, strlen(name)); \
+ p = mempcpy(p, (u8 *)req + req->member##_offs, req->member##_len); \
+ p = mempcpy(p, "\n", 1); \
+ } while (0)
+
+#define BUF_ADD_HF() \
+ do { \
+ p = mempcpy(p, (u8 *)req + hf->name_offs, hf->name_len); \
+ p = mempcpy(p, " = ", 3); \
+ p = mempcpy(p, (u8 *)req + hf->value_offs, hf->value_len); \
+ p = mempcpy(p, "\n", 1); \
+ } while (0)
+
+ p = resp->data;
+
+ p = mempcpy(p, "Welcome to WebAssembly on Unit!\n\n", 33);
+
+ p = mempcpy(p, "[Request Info]\n", 15);
+ BUF_ADD("REQUEST_PATH = ", path);
+ BUF_ADD("METHOD = ", method);
+ BUF_ADD("VERSION = ", version);
+ BUF_ADD("QUERY = ", query);
+ BUF_ADD("REMOTE = ", remote);
+ BUF_ADD("LOCAL_ADDR = ", local_addr);
+ BUF_ADD("LOCAL_PORT = ", local_port);
+ BUF_ADD("SERVER_NAME = ", server_name);
+
+ p = mempcpy(p, "\n[Request Headers]\n", 19);
+ hf_end = req->fields + req->nr_fields;
+ for (hf = req->fields; hf < hf_end; hf++)
+ BUF_ADD_HF();
+
+ method = (char *)req + req->method_offs;
+ if (memcmp(method, "POST", req->method_len) == 0 ||
+ memcmp(method, "PUT", req->method_len) == 0) {
+ p = mempcpy(p, "\n[", 2);
+ p = mempcpy(p, method, req->method_len);
+ p = mempcpy(p, " data]\n", 7);
+ p = mempcpy(p, (u8 *)req + req->content_offs, req->content_len);
+ p = mempcpy(p, "\n", 1);
+ }
+
+ p = memcpy(p, "\0", 1);
+
+ resp->size = p - resp->data;
+
+ send_headers(addr, "text/plain", resp->size);
+
+ nxt_wasm_send_response(resp_offs);
+ /* 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.
+ *
+ * In this simple demo, we are only expecting it to be called
+ * once per request.
+ *
+ * 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.
+ */
+
+ 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);
+
+ echo_request(addr);
+
+ return 0;
+}
diff --git a/examples/c/luw-echo-request.c b/examples/c/luw-echo-request.c
new file mode 100644
index 0000000..5655c65
--- /dev/null
+++ b/examples/c/luw-echo-request.c
@@ -0,0 +1,98 @@
+/* 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, 0, "Content-Type", "text/plain");
+ luw_http_add_header(&ctx, 1, "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;
+}
diff --git a/examples/c/luw-upload-reflector.c b/examples/c/luw-upload-reflector.c
new file mode 100644
index 0000000..95bc514
--- /dev/null
+++ b/examples/c/luw-upload-reflector.c
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/*
+ * examples/c/luw-upload-reflector.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 "unit/unit-wasm.h"
+
+static luw_ctx_t ctx;
+
+static size_t total_response_sent;
+
+static u8 *request_buf;
+
+/*
+ * While these first two _handlers_ aren't technically required, they
+ * could be combined or the code could just go in upload_reflector(),
+ * they demonstrate their use in ensuring the module is in the right
+ * state for a new request.
+ */
+__luw_export_name("luw_response_end_handler")
+void luw_response_end_handler(void)
+{
+ total_response_sent = 0;
+}
+
+__luw_export_name("luw_request_end_handler")
+void luw_request_end_handler(void)
+{
+ if (!request_buf)
+ return;
+
+ free(request_buf);
+ request_buf = NULL;
+}
+
+static int upload_reflector(luw_ctx_t *ctx)
+{
+ size_t write_bytes;
+
+ /* Send headers */
+ if (total_response_sent == 0) {
+ static const char *defct = "application/octet-stream";
+ const char *ct = luw_http_hdr_get_value(ctx, "Content-Type");
+ char clen[32];
+
+ snprintf(clen, sizeof(clen), "%lu",
+ luw_get_http_content_len(ctx));
+
+ luw_http_init_headers(ctx, 2, 0);
+ luw_http_add_header(ctx, 0, "Content-Type", ct ? ct : defct);
+ luw_http_add_header(ctx, 1, "Content-Length", clen);
+ luw_http_send_headers(ctx);
+ }
+
+ write_bytes = luw_mem_fill_buf_from_req(ctx, total_response_sent);
+ total_response_sent += write_bytes;
+
+ luw_http_send_response(ctx);
+
+ if (total_response_sent == luw_get_http_content_len(ctx)) {
+ /* Tell Unit no more data to send */
+ luw_http_response_end();
+ }
+
+ return 0;
+}
+
+__luw_export_name("luw_request_handler")
+int luw_request_handler(u8 *addr)
+{
+ if (!request_buf) {
+ luw_init_ctx(&ctx, addr, 0 /* Response offset */);
+ /*
+ * Take a copy of the request and use that, we do this
+ * in APPEND mode so we can build up request_buf from
+ * multiple requests.
+ *
+ * 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.
+ */
+ luw_set_req_buf(&ctx, &request_buf,
+ LUW_SRB_APPEND|LUW_SRB_ALLOC|LUW_SRB_FULL_SIZE);
+ } else {
+ luw_req_buf_append(&ctx, addr);
+ }
+
+ upload_reflector(&ctx);
+
+ return 0;
+}
diff --git a/examples/c/unit-wasm-raw.c b/examples/c/unit-wasm-raw.c
new file mode 100644
index 0000000..42ebcbf
--- /dev/null
+++ b/examples/c/unit-wasm-raw.c
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+/*
+ * Copyright (C) Andrew Clayton
+ * Copyright (C) F5, Inc.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+
+#include "unit-wasm-raw.h"
+
+__attribute__((import_module("env"), import_name("nxt_wasm_send_headers")))
+void nxt_wasm_send_headers(u32 offset);
+
+void send_headers(u8 *addr, const char *ct, size_t len)
+{
+ struct resp_hdr *rh;
+ char clen[32];
+ u8 *p;
+ static const u32 hdr_offs = 0;
+
+ rh = (struct resp_hdr *)addr;
+
+#define SET_HDR_FIELD(idx, name, val) \
+ do { \
+ rh->fields[idx].name_offs = p - addr; \
+ rh->fields[idx].name_len = strlen(name); \
+ p = mempcpy(p, name, rh->fields[idx].name_len); \
+ rh->fields[idx].value_offs = p - addr; \
+ rh->fields[idx].value_len = strlen(val); \
+ p = mempcpy(p, val, rh->fields[idx].value_len); \
+ } while (0)
+
+ rh->nr_fields = 2;
+ p = addr + sizeof(struct resp_hdr) +
+ (rh->nr_fields * sizeof(struct hdr_field));
+
+ SET_HDR_FIELD(0, "Content-Type", ct);
+ snprintf(clen, sizeof(clen), "%lu", len);
+ SET_HDR_FIELD(1, "Content-Length", clen);
+
+ nxt_wasm_send_headers(hdr_offs);
+}
diff --git a/examples/c/unit-wasm-raw.h b/examples/c/unit-wasm-raw.h
new file mode 100644
index 0000000..6fd9d35
--- /dev/null
+++ b/examples/c/unit-wasm-raw.h
@@ -0,0 +1,87 @@
+#ifndef _UNIT_WASM_H_
+#define _UNIT_WASM_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef uint64_t u64;
+typedef int64_t s64;
+typedef uint32_t u32;
+typedef int32_t s32;
+typedef uint16_t u16;
+typedef int16_t s16;
+typedef uint8_t u8;
+typedef int8_t s8;
+
+#ifndef __unused
+#define __unused __attribute__((unused))
+#endif
+#ifndef __maybe_unused
+#define __maybe_unused __unused
+#endif
+#ifndef __always_unused
+#define __always_unused __unused
+#endif
+
+struct hdr_field {
+ u32 name_offs;
+ u32 name_len;
+ u32 value_offs;
+ u32 value_len;
+};
+
+struct req {
+ u32 method_offs;
+ u32 method_len;
+ u32 version_offs;
+ u32 version_len;
+ u32 path_offs;
+ u32 path_len;
+ u32 query_offs;
+ u32 query_len;
+ u32 remote_offs;
+ u32 remote_len;
+ u32 local_addr_offs;
+ u32 local_addr_len;
+ u32 local_port_offs;
+ u32 local_port_len;
+ u32 server_name_offs;
+ u32 server_name_len;
+
+ u32 content_offs;
+ u32 content_len;
+ u32 content_sent;
+ u32 total_content_sent;
+
+ u32 request_size;
+
+ u32 nr_fields;
+
+ u32 tls;
+
+ struct hdr_field fields[];
+};
+
+struct resp {
+ u32 size;
+
+ u8 data[];
+};
+
+struct resp_hdr {
+ u32 nr_fields;
+
+ struct hdr_field fields[];
+};
+
+extern void wasm_module_end_handler(void);
+extern void wasm_module_init_handler(void);
+extern void wasm_response_end_handler(void);
+extern void wasm_request_end_handler(void);
+extern void wasm_free_handler(u32 addr);
+extern u32 wasm_malloc_handler(size_t size);
+extern int wasm_request_handler(u8 *addr);
+
+extern void send_headers(u8 *addr, const char *ct, size_t len);
+
+#endif /* _UNIT_WASM_H_ */
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;
+}