summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrew Clayton <a.clayton@nginx.com>2025-05-20 19:07:53 +0100
committerAndrew Clayton <a.clayton@nginx.com>2025-05-20 19:07:53 +0100
commit89b20ca4160ab671926477a81b8b2ad83163ccc8 (patch)
tree6a742d99194391e92ed333b2fd47b7bb09924273
parent87a97eb296adfc535fc1cb9208102f8466b9055a (diff)
downloadunit-wasm-master.tar.gz
unit-wasm-master.tar.bz2
Convert docs to reStructuredTextHEADmaster
... it's just better than markdown. Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
-rw-r--r--API-C.md1174
-rw-r--r--API-C.rst1274
-rw-r--r--API-Rust.md1138
-rw-r--r--API-Rust.rst1238
-rw-r--r--CODE_OF_CONDUCT.md74
-rw-r--r--CODE_OF_CONDUCT.rst88
-rw-r--r--CONTRIBUTING.md83
-rw-r--r--CONTRIBUTING.rst88
-rw-r--r--HOWTO.md210
-rw-r--r--HOWTO.rst223
-rw-r--r--README.md490
-rw-r--r--README.rst513
12 files changed, 3424 insertions, 3169 deletions
diff --git a/API-C.md b/API-C.md
deleted file mode 100644
index 298867d..0000000
--- a/API-C.md
+++ /dev/null
@@ -1,1174 +0,0 @@
-# libunit-wasm C API
-
-C Library for creating WebAssembly modules for use with NGINX Unit.
-
-```C
-#include <unit/unit-wasm.h>
-```
-
-1. [libunit-wasm C API](#libunit-wasm-c-api)
-2. [Macros](#macros)
- * [Version](#version)
- * [Misc](#misc)
-3. [Types](#types)
-4. [Enums](#enums)
- * [luw_srb_flags_t](#luw_srb_flags_t)
- * [luw_http_status_t](#luw_http_status_t)
-5. [Structs](#structs)
-6. [Function Handlers](#function-handlers)
- * [Optional](#optional)
- - [luw_module_init_handler](#luw_module_init_handler)
- - [luw_module_end_handler](#luw_module_end_handler)
- - [luw_request_init_handler](#luw_request_init_handler)
- - [luw_request_end_handler](#luw_request_end_handler)
- - [luw_response_end_handler](#luw_response_end_handler)
- * [Required](#required)
- - [luw_request_handler](#luw_request_handler)
- - [luw_free_handler](#luw_free_handler)
- - [luw_malloc_handler](#luw_malloc_handler)
-7. [Functions](#functions)
- * [luw_init_ctx](#luw_init_ctx)
- * [luw_set_req_buf](#luw_set_req_buf)
- * [luw_get_http_path](#luw_get_http_path)
- * [luw_get_http_method](#luw_get_http_method)
- * [luw_get_http_version](#luw_get_http_version)
- * [luw_get_http_query](#luw_get_http_query)
- * [luw_get_http_remote](#luw_get_http_remote)
- * [luw_get_http_local_addr](#luw_get_http_local_addr)
- * [luw_get_http_local_port](#luw_get_http_local_port)
- * [luw_get_http_server_name](#luw_get_http_server_name)
- * [luw_get_http_content](#luw_get_http_content)
- * [luw_get_http_content_len](#luw_get_http_content_len)
- * [luw_get_http_content_sent](#luw_get_http_content_sent)
- * [luw_get_http_total_content_sent](#luw_get_http_total_content_sent)
- * [luw_http_is_tls](#luw_http_is_tls)
- * [luw_http_hdr_iter](#luw_http_hdr_iter)
- * [luw_http_hdr_get_value](#luw_http_hdr_get_value)
- * [luw_get_response_data_size](#luw_get_response_data_size)
- * [luw_mem_writep](#luw_mem_writep)
- * [luw_mem_writep_data](#luw_mem_writep_data)
- * [luw_req_buf_append](#luw_req_buf_append)
- * [luw_req_buf_copy](#luw_req_buf_copy)
- * [luw_mem_splice_file](#luw_mem_splice_file)
- * [luw_mem_fill_buf_from_req](#luw_mem_fill_buf_from_req)
- * [luw_mem_reset](#luw_mem_reset)
- * [luw_http_set_response_status](#luw_http_set_response_status)
- * [luw_http_send_response](#luw_http_send_response)
- * [luw_http_init_headers](#luw_http_init_headers)
- * [luw_http_add_header](#luw_http_add_header)
- * [luw_http_send_headers](#luw_http_send_headers)
- * [luw_http_response_end](#luw_http_response_end)
- * [luw_mem_get_init_size](#luw_mem_get_init_size)
- * [luw_foreach_http_hdr](#luw_foreach_http_hdr)
-8. [Misc. Functions](#misc-functions)
- * [luw_malloc](#luw_malloc)
- * [luw_free](#luw_free)
-
-## Macros
-
-### Version
-
-```C
-#define LUW_VERSION_MAJOR M
-#define LUW_VERSION_MINOR m
-#define LUW_VERSION_PATCH p
-```
-
-```C
-/* Version number in hex 0xMMmmpp00 */
-#define LUW_VERSION_NUMBER \
- ( (LUW_VERSION_MAJOR << 24) | \
- (LUW_VERSION_MINOR << 16) | \
- (LUW_VERSION_PATCH << 8) )
-```
-
-### Misc
-
-```C
-#define __luw_export_name(name) __attribute__((export_name(name)))
-```
-
-```C
-#define __luw_unused __attribute__((unused))
-#define __luw_maybe_unused __luw_unused
-```
-
-```C
-#define luw_foreach_http_hdr(ctx, iter, name, value) \
- for (iter = ctx.req->fields, \
- name = (const char *)ctx.req + iter->name_off; \
- (iter < (ctx.req->fields + ctx.req->nr_fields)) && \
- (value = (const char *)ctx.req + iter->value_off); \
- iter++, name = (const char *)ctx.req + iter->name_off)
-```
-
-## Types
-
-```C
-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;
-```
-
-## Enums
-
-### luw_srb_flags_t
-
-```C
-typedef enum {
- LUW_SRB_NONE = 0x00,
- LUW_SRB_APPEND = 0x01,
- LUW_SRB_ALLOC = 0x02,
- LUW_SRB_FULL_SIZE = 0x04,
-
- LUW_SRB_FLAGS_ALL = (LUW_SRB_NONE|LUW_SRB_APPEND|LUW_SRB_ALLOC|
- LUW_SRB_FULL_SIZE)
-} luw_srb_flags_t;
-```
-
-### luw_http_status_t
-
-```C
-typedef enum {
- LUW_HTTP_CONTINUE = 100,
- LUW_HTTP_SWITCHING_PROTOCOLS = 101,
-
- LUW_HTTP_OK = 200,
- LUW_HTTP_CREATED = 201,
- LUW_HTTP_ACCEPTED = 202,
- LUW_HTTP_NO_CONTENT = 204,
-
- LUW_HTTP_MULTIPLE_CHOICES = 300,
- LUW_HTTP_MOVED_PERMANENTLY = 301,
- LUW_HTTP_FOUND = 302,
- LUW_HTTP_SEE_OTHER = 303,
- LUW_HTTP_NOT_MODIFIED = 304,
- LUW_HTTP_TEMPORARY_REDIRECT = 307,
- LUW_HTTP_PERMANENT_REDIRECT = 308,
-
- LUW_HTTP_BAD_REQUEST = 400,
- LUW_HTTP_UNAUTHORIZED = 401,
- LUW_HTTP_FORBIDDEN = 403,
- LUW_HTTP_NOT_FOUND = 404,
- LUW_HTTP_METHOD_NOT_ALLOWED = 405,
- LUW_HTTP_NOT_ACCEPTABLE = 406,
- LUW_HTTP_REQUEST_TIMEOUT = 408,
- LUW_HTTP_CONFLICT = 409,
- LUW_HTTP_GONE = 410,
- LUW_HTTP_LENGTH_REQUIRED = 411,
- LUW_HTTP_PAYLOAD_TOO_LARGE = 413,
- LUW_HTTP_URI_TOO_LONG = 414,
- LUW_HTTP_UNSUPPORTED_MEDIA_TYPE = 415,
- LUW_HTTP_UPGRADE_REQUIRED = 426,
- LUW_HTTP_TOO_MANY_REQUESTS = 429,
- LUW_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
-
- /* Proposed by RFC 7725 */
- LUW_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
-
- LUW_HTTP_INTERNAL_SERVER_ERROR = 500,
- LUW_HTTP_NOT_IMPLEMENTED = 501,
- LUW_HTTP_BAD_GATEWAY = 502,
- LUW_HTTP_SERVICE_UNAVAILABLE = 503,
- LUW_HTTP_GATEWAY_TIMEOUT = 504,
-} luw_http_status_t;
-```
-
-## Structs
-
-```C
-struct luw_hdr_field {
- u32 name_off;
- u32 name_len;
- u32 value_off;
- u32 value_len;
-};
-```
-
-```C
-struct luw_req {
- u32 method_off;
- u32 method_len;
- u32 version_off;
- u32 version_len;
- u32 path_off;
- u32 path_len;
- u32 query_off;
- u32 query_len;
- u32 remote_off;
- u32 remote_len;
- u32 local_addr_off;
- u32 local_addr_len;
- u32 local_port_off;
- u32 local_port_len;
- u32 server_name_off;
- u32 server_name_len;
-
- u64 content_len;
- u64 total_content_sent;
- u32 content_sent;
- u32 content_off;
-
- u32 request_size;
-
- u32 nr_fields;
-
- u32 tls;
-
- char __pad[4];
-
- struct luw_hdr_field fields[];
-};
-```
-
-```C
-struct luw_resp {
- u32 size;
-
- u8 data[];
-};
-```
-
-```C
-struct luw_resp_hdr {
- u32 nr_fields;
-
- struct luw_hdr_field fields[];
-};
-```
-
-```C
-typedef struct {
- /* pointer to the shared memory */
- u8 *addr;
-
- /* points to the end of ctx->resp->data */
- u8 *mem;
-
- /* struct luw_req representation of the shared memory */
- struct luw_req *req;
-
- /* struct luw_resp representation of the shared memory */
- struct luw_resp *resp;
-
- /* struct luw_resp_hdr representation of the shared memory */
- struct luw_resp_hdr *resp_hdr;
-
- /* offset to where the struct resp starts in the shared memory */
- size_t resp_offset;
-
- /* points to the external buffer used for a copy of the request */
- u8 *req_buf;
-
- /* points to the end of the fields array in struct luw_resp_hdr */
- u8 *hdrp;
-
- /* points to the end of ctx->req_buf */
- u8 *reqp;
-
- /* tracks the response header index number */
- s32 resp_hdr_idx;
-} luw_ctx_t;
-```
-
-```C
-typedef struct luw_hdr_field luw_http_hdr_iter_t;
-```
-
-## Function Handlers
-
-These functions are exported from the WebAssembly module and are called from
-the WebAssembly runtime (the Unit WebAssembly language module in this case).
-
-There are two types of handlers; required & optional.
-
-luw_request_handler(), luw_malloc_handler() & luw_free_handler() are required
-with the rest being optional.
-
-libunit-wasm includes exports for these handlers and some default
-implementations.
-
-These functions are defined as _weak_ symbols and so if a developer writes
-their own function of the same name, that will take precedence.
-
-However, developers are under no obligation to use these and can create their
-own with any (valid) names they like.
-
-Whatever names developers choose, they are specified in the Unit config.
-
-## Required
-
-#### luw_request_handler
-
-```C
-__attribute__((export_name("luw_request_handler"), __weak__))
-int luw_request_handler(u8 *addr);
-```
-
-This is called by Unit during a request. It may be called multiple times for
-a single HTTP request if there is more request data than the available memory
-for host <--> module communications.
-
-You will need to provide your own implementation of this function.
-
-It receives the base address of the shared memory. Essentially what is
-returned by luw_malloc_handler().
-
-This memory will contain a *struct luw_req*.
-
-It returns an int. This should nearly always be _0_.
-
-If you wish to indicate a '500 Internal Server Error', for example if some
-internal API has failed or an OS level error occurred, then you can simply
-return _-1_, _if_ you have haven't already _sent_ any response or headers.
-
-You can still return 0 _and_ set the HTTP response status to 500 using
-[luw_http_set_response_status](#luw_http_set_response_status).
-
-#### luw_malloc_handler
-
-```C
-__attribute__((export_name("luw_malloc_handler"), __weak__))
-u32 luw_malloc_handler(size_t size);
-```
-
-This is called by Unit when it loads the WebAssembly language module. This
-provides the shared memory used for host <--> module communications.
-
-It receives the desired size of the memory, which is currently
-NXT_WASM_MEM_SIZE + NXT_WASM_PAGE_SIZE.
-
-However calls to luw_mem_get_init_size() will return just NXT_WASM_MEM_SIZE
-(which is currently 32MiB). The extra NXT_WASM_PAGE_SIZE is to cater for
-structure sizes in the response so developers can generally assume they have
-the full NXT_WASM_MEM_SIZE for their data.
-
-A default implementation of this function is provided ready for use that
-calls malloc(3).
-
-#### luw_free_handler
-
-```C
-__attribute__((export_name("luw_free_handler"), __weak__))
-void luw_free_handler(u32 addr);
-```
-
-This is called by Unit when it shuts down the WebAssembly language module and
-free's the memory previously allocated by luw_malloc_handler().
-
-It receives the address of the memory to free.
-
-An implementation of this function is provided ready for use that calls
-free(3), in which case it receives the address that was previously returned
-by luw_malloc_handler().
-
-### Optional
-
-#### luw_module_init_handler
-
-```C
-__attribute__((export_name("luw_module_init_handler"), __weak__))
-void luw_module_init_handler(void);
-```
-
-This is called by Unit when it loads the WebAssembly language module.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-#### luw_module_end_handler
-
-```C
-__attribute__((export_name("luw_module_end_handler"), __weak__))
-void luw_module_end_handler(void);
-```
-
-This is called by Unit when it shuts down the WebAssembly language module.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-#### luw_request_init_handler
-
-```C
-__attribute__((export_name("luw_request_init_handler"), __weak__))
-void luw_request_init_handler(void);
-```
-
-This is called by Unit at the start of nxt_wasm_request_handler(), i.e at the
-start of a new request.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-#### luw_request_end_handler
-
-```C
-__attribute__((export_name("luw_request_end_handler"), __weak__))
-void luw_request_end_handler(void);
-```
-
-This is called by Unit at the end of nxt_wasm_request_handler(), i.e at the
-end of a request.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-#### luw_response_end_handler
-
-```C
-__attribute__((export_name("luw_response_end_handler"), __weak__))
-void luw_response_end_handler(void);
-```
-
-This is called by Unit after luw_http_response_end() has been called.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-## Functions
-
-### luw_init_ctx
-
-```C
-void luw_init_ctx(luw_ctx_t *ctx, u8 *addr, size_t offset);
-```
-
-This function sets up a *luw_ctx_t* context structure, this contains stuff
-required all throughout the API. It's a typedef for opaqueness and you should
-not in general be concerned with its contents.
-
-It take a pointer to a stack allocated luw_ctx_t, this will be zeroed and
-have various members initialised.
-
-**addr** is a pointer to the shared memory as passed into luw_request_handler().
-
-**offset** is where in the shared memory it should start writing the response.
-
-#### A quick word about memory
-
-The way the Unit WebAssembly language module (the host/runtime) and the
-WebAssembly module you want to write (the guest) communicate is via a chunk
-of shared memory.
-
-This shared memory is simply the modules (guest) address space from which we
-can allocate a chunk. How this memory is laid out varies on how the module
-is built.
-
-With clang/linker flags of -Wl,--stack-first -Wl,-z,stack-size=$((8*1024*1024))
-we get a memory layout something like
-
-```
- |----------------------------------------------------------------------|
- | | | |
- | <-- Stack | Global Data | Heap --> |
- | | | |
- |----------------------------------------------------------------------|
- 0 0x800000 0x100000000
-
- WebAssembly Module Linear Memory / Process Memory Layout
-```
-
-(The above is assuming _--target=wasm32-wasi_, i.e 32bit)
-
-A chunk of memory from the heap is allocated at Unit WebAssembly language
-module startup.
-
-We currently use this same chunk of memory for both requests and responses.
-This means that depending on what you're doing, you'll want to take a copy
-of the request (and remember luw_request_handler() may be called multiple
-times for a single http request).
-
-That will be covered in more detail by the next function, luw_set_req_buf().
-
-Now back to _offset_, it may be convenient to put the response headers at the
-beginning of this memory and then put the response after it, rather than
-doing the headers and then doing the response as separate steps, if the
-headers depends on some aspect of the response, its size for example and
-Content-Length.
-
-Example
-
-```C
-luw_ctx_t ctx;
-/* ... */
-luw_init_ctx(&ctx, addr, 4096 /* Response offset */);
-```
-
-### luw_set_req_buf
-
-```C
-int luw_set_req_buf(luw_ctx_t *ctx, u8 **buf, unsigned int flags);
-```
-
-This function is used to take a copy of the request buffer (as discussed
-above).
-
-This takes a previously initialised (with luw_init_ctx()) luw_ctx_t.
-
-**buf** is a buffer where the request data will written.
-
-**flags** can be some combination (OR'd) of the following
-
-**LUW_SRB_NONE**
-
-No specific action to be performed. It will simply copy the request data
-into the specified buffer.
-
-**LUW_SRB_APPEND**
-
-Sets up append mode whereby multiple successive requests will be appended
-to the specified buffer.
-
-The first request will have all its metadata copied. Subsequent requests
-will _only_ have the actual body data appended.
-
-**LUW_SRB_ALLOC**
-
-Allocate memory for the specified buffer.
-
-**LUW_SRB_FULL_SIZE**
-
-Used in conjunction with *LUW_SRB_ALLOC*. By default only
-*ctx->req->request_size* is allocated. If this flag is present it says to
-allocate memory for the _entire_ request that will eventually be sent.
-
-Example
-
-```C
-static u8 *request_buf;
-*/ ... */
-int luw_request_handler(u8 *addr)
-{
- if (!request_buf) {
- luw_init_ctx(&ctx, addr, 0);
- /*
- * 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);
- }
-
- /* operate on the request (ctx) */
-
- return 0;
-}
-```
-
-That example is taken from the [luw-upload-reflector.c](https://github.com/nginx/unit-wasm/blob/main/examples/c/luw-upload-reflector.c) demo module. For a
-simpler example see [luw-echo-request.c](https://github.com/nginx/unit-wasm/blob/main/examples/c/luw-echo-request.c)
-
-### luw_get_http_path
-
-```C
-const char *luw_get_http_path(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the HTTP request path.
-
-E.g
-
-Given a request of
-```
-http://localhost:8080/echo/?q=a
-```
-this function will return
-```
-/echo/?q=a
-```
-
-### luw_get_http_method
-
-```C
-const char *luw_get_http_method(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the HTTP method.
-
-E.g
-
-```
-GET
-```
-
-### luw_get_http_version
-
-```C
-const char *luw_get_http_version(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the HTTP version.
-
-E.g
-
-```
-1.1
-```
-
-### luw_get_http_query
-
-```C
-const char *luw_get_http_query(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the query string (empty string for no query
-string).
-
-E.g
-
-Given a request of
-```
-http://localhost:8080/echo/?q=a
-```
-this function will return
-```
-q=a
-```
-
-### luw_get_http_remote
-
-```C
-const char *luw_get_http_remote(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the remote/client/peer address.
-
-E.g
-
-```
-2001:db8::f00
-```
-
-### luw_get_http_local_addr
-
-```C
-const char *luw_get_http_local_addr(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the local/server address.
-
-E.g
-
-```
-2001:db8::1
-```
-
-### luw_get_http_local_port
-
-```C
-const char *luw_get_http_local_port(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the local/server port.
-
-E.g
-
-```
-443
-```
-
-### luw_get_http_server_name
-
-```C
-const char *luw_get_http_server_name(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the local/server name.
-
-E.g
-
-```
-www.example.com
-```
-
-### luw_get_http_content
-
-```C
-const u8 *luw_get_http_content(const luw_ctx_t *ctx);
-```
-
-This function returns a pointer to the start of the request body.
-
-### luw_get_http_content_len
-
-```C
-u64 luw_get_http_content_len(const luw_ctx_t *ctx);
-```
-
-This function returns the size of the overall content. I.e Content-Length.
-
-Prior to version 0.3.0 it returned a size_t
-
-### luw_get_http_content_sent
-
-```C
-size_t luw_get_http_content_sent(const luw_ctx_t *ctx);
-```
-
-This function returns the length of the content that was sent to the
-WebAssembly module in _this_ request. Remember, a single HTTP request may be
-split over several calls to luw_request_handler().
-
-### luw_get_http_total_content_sent
-
-```C
-u64 luw_get_http_total_content_sent(const luw_ctx_t *ctx);
-```
-
-This function returns the total length of the content that was sent to the
-WebAssembly module so far. Remember, a single HTTP request may be split over
-several calls to luw_request_handler().
-
-_Version: 0.2.0_ Prior to 0.3.0 it returned a size_t
-
-### luw_http_is_tls
-
-```C
-bool luw_http_is_tls(const luw_ctx_t *ctx);
-```
-
-This function returns _true_ if the connection to Unit was made over TLS.
-
-### luw_http_hdr_iter
-
-```C
-void luw_http_hdr_iter(luw_ctx_t *ctx,
- bool (*luw_http_hdr_iter_func)(luw_ctx_t *ctx,
- const char *name,
- const char *value,
- void *data),
- void *user_data)
-```
-
-This function allows to iterate over the HTTP headers. For each header it
-will call the given luw_http_hdr_iter_func() function whose prototype is
-
-```C
-bool luw_http_hdr_iter_func(luw_ctx_t *ctx,
- const char *name, const char *value, void *data);
-```
-
-You may call this function whatever you like. For each header it will be
-passed the *luw_ctx_t*, the header name, its value and a user specified
-pointer if any, can be NULL.
-
-Returning _true_ from this function will cause the iteration process to
-continue, returning _false_ will terminate it.
-
-Example
-
-```C
-static bool hdr_iter_func(luw_ctx_t *ctx, const char *name, const char *value,
- void *user_data __luw_unused)
-{
- /* Do something with name & value */
-
- /* Continue iteration or return false to stop */
- return true;
-}
-
-/* ... *
-
-luw_http_hdr_iter(&ctx, hdr_iter_func, NULL);
-```
-
-### luw_http_hdr_get_value
-
-```C
-const char *luw_http_hdr_get_value(const luw_ctx_t *ctx, const char *hdr);
-```
-
-Given a HTTP header _hdr_ this function will look it up in the request and
-return its value if found, otherwise _NULL_.
-
-The lookup is done case insensitively.
-
-### luw_get_response_data_size
-
-```C
-size_t luw_get_response_data_size(const luw_ctx_t *ctx);
-```
-
-This function returns the size of the response data written to memory.
-
-### luw_mem_writep
-
-```C
-__attribute__((__format__(printf, 2, 3)))
-int luw_mem_writep(luw_ctx_t *ctx, const char *fmt, ...);
-```
-
-This function is a cross between vasprintf(3) and mempcpy(3).
-
-It takes a format argument and zero or more arguments that will be
-substituted into the format string.
-
-It then appends this formatted string to the memory. Note this string will
-_not_ be nul terminated. Unit does not expect this response data to be nul
-terminated and we track the size of the response and return that to Unit.
-
-This function returns -1 on error or the length of the string written.
-
-### luw_mem_writep_data
-
-```C
-size_t luw_mem_writep_data(luw_ctx_t *ctx, const u8 *src, size_t size);
-```
-
-This function just appends _size_ bytes from _src_ to the response.
-
-It returns the new size of the response.
-
-### luw_req_buf_append
-
-```C
-void luw_req_buf_append(luw_ctx_t *ctx, const u8 *src);
-```
-
-This function appends the request data contained in _src_ to the previously
-setup *request_buffer* with luw_set_req_buf().
-
-This function would be used after an initial request to append the data from
-subsequent requests to the request_buffer.
-
-Example
-
-```C
-int luw_request_handler(u8 *addr)
-{
- if (!request_buf) {
- luw_init_ctx(&ctx, addr, 0);
- /*
- * 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);
- }
-
- /* Do something with the request (ctx) */
-
- return 0;
-}
-```
-
-### luw_req_buf_copy
-
-```C
-void luw_req_buf_copy(luw_ctx_t *ctx, const u8 *src);
-```
-
-This function is analogous to [luw_req_buf_append](#luw_req_buf_append) but
-rather than appending the request data contained in _src_ to the previously
-setup *request_buffer* with luw_set_req_buf(), it simply overwrites what's
-currently there.
-
-This function could be used to handle large requests/uploads that you want to
-save out to disk or some such and can't buffer it all in memory.
-
-Example
-
-```C
-int luw_request_handler(u8 *addr)
-{
- const u8 *buf;
- ssize_t bytes_wrote;
-
- if (total_bytes_wrote == 0) {
- luw_init_ctx(&ctx, addr, 0);
- luw_set_req_buf(&ctx, &request_buf, LUW_SRB_NONE);
-
- fd = open("/var/tmp/large-file.dat", O_CREAT|O_TRUNC|O_WRONLY,
- 0666);
- } else {
- luw_req_buf_copy(&ctx, addr);
- }
-
- buf = luw_get_http_content(&ctx);
- bytes_wrote = write(fd, buf, luw_get_http_content_sent(&ctx));
- if (bytes_wrote == -1)
- return -1;
-
- total_bytes_wrote += bytes_wrote;
- if (total_bytes_wrote == luw_get_http_content_len(&ctx))
- luw_http_response_end();
-
- return 0;
-}
-```
-
-_Version: 0.3.0_
-
-### luw_mem_splice_file
-
-```C
-ssize_t luw_mem_splice_file(const u8 *src, int fd);
-```
-
-This function write(2)'s the request data directly from the shared memory
-(_src_) to the file represented by the given file-descriptor (_fd_).
-
-This can be used as an alternative to [luw_req_buf_copy](#luw_req_buf_copy)
-and avoids an extra copying of the request data.
-
-Example
-
-```C
-int luw_request_handler(u8 *addr) {
- ssize_t bytes_wrote;
-
- if (total_bytes_wrote == 0) {
- luw_init_ctx(&ctx, addr, 0);
- luw_set_req_buf(&ctx, &request_buf, LUW_SRB_NONE);
-
- fd = open("/var/tmp/large-file.dat", O_CREAT|O_TRUNC|O_WRONLY,
- 0666);
- }
-
- bytes_wrote = luw_mem_splice_file(addr, fd);
- if (bytes_wrote == -1)
- return -1;
-
- total_bytes_wrote += bytes_wrote;
- if (total_bytes_wrote == luw_get_http_content_len(&ctx))
- luw_http_response_end();
-
- return 0;
-}
-```
-
-_Version: 0.3.0_
-
-### luw_mem_fill_buf_from_req
-
-```C
-size_t luw_mem_fill_buf_from_req(luw_ctx_t *ctx, size_t from);
-```
-
-This is a convenience function to fill the response buffer with data from
-the request buffer.
-
-_from_ is basically the offset in the request_buffer where to start copying
-data from.
-
-Example
-
-```C
-/* ... */
-write_bytes = luw_mem_fill_buf_from_req(ctx, total_response_sent);
-total_response_sent += write_bytes;
-/* ... */
-```
-
-This is taken from the [luw-upload-reflector.c](https://github.com/nginx/unit-wasm/blob/main/examples/c/luw-upload-reflector.c) demo module.
-
-In this case we build up a request_buffer on each call of
-luw_request_handler(), so total_response_sent grows each time by how much data
-was sent in _that_ request.
-
-Here are are sending data back to the client after each time we receive it to
-demonstrate the interleaving of requests and responses from the WebAssembly
-module during a single http request.
-
-This function returns the number of bytes written to the response buffer.
-
-### luw_mem_reset
-
-```C
-void luw_mem_reset(luw_ctx_t *ctx);
-```
-
-This function resets the response buffer size and the number of response
-headers back to 0.
-
-### luw_http_set_response_status
-
-```C
-void luw_http_set_response_status(luw_http_status_t status);
-```
-
-This function is used to set the HTTP response status. It takes one of the
-[luw_http_status_t](#luw_http_status_t) enum values.
-
-It should be called before any calls to *luw_http_send_response()* or
-*luw_http_send_headers()*.
-
-If you don't call this function the response status defaults to '200 OK'.
-
-If you wish to error out with a '500 Internal Server Error', you don't need to
-call this function. Simply returning _-1_ from the request_handler function
-will indicate this error.
-
-E.g
-
-Send a '403 Forbidden'
-
-```C
-/* ... */
-luw_http_set_response_status(LUW_HTTP_FORBIDDEN);
-luw_http_send_response(ctx); /* Doesn't require any body */
-luw_http_response_end();
-/* ... */
-return 0;
-```
-
-Send a '307 Temporary Re-direct'
-
-```C
-/* ... */
-luw_http_set_response_status(LUW_HTTP_TEMPORARY_REDIRECT);
-
-luw_http_init_headers(ctx, 1, 0);
-luw_http_add_header(ctx, "Location", "https://example.com/");
-luw_http_send_headers(ctx);
-luw_http_response_end();
-/* ... */
-return 0;
-```
-
-_Version: 0.3.0_
-
-### luw_http_send_response
-
-```C
-void luw_http_send_response(const luw_ctx_t *ctx);
-```
-
-This function calls into Unit to send the response buffer back.
-
-### luw_http_init_headers
-
-```C
-void luw_http_init_headers(luw_ctx_t *ctx, size_t nr, size_t offset);
-```
-
-This function is used in the preparation of sending back response headers.
-
-_nr_ is the number of headers we are sending.
-
-_offset_ is the offset into the response buffer where we are placing these
-headers. This will usually be 0.
-
-Example
-
-```C
-luw_http_init_headers(ctx, 2, 0);
-```
-
-### luw_http_add_header
-
-```C
-void luw_http_add_header(luw_ctx_t *ctx, const char *name, const char *value);
-```
-
-This function is used to add a header to the response.
-
-_name_ is the name of the header.
-
-_value_ is the value of the header.
-
-Example
-
-```C
-char clen[32];
-/* ... */
-snprintf(clen, sizeof(clen), "%lu", luw_get_response_data_size(&ctx));
-luw_http_add_header(&ctx, "Content-Type", "text/plain");
-luw_http_add_header(&ctx, "Content-Length", clen);
-```
-
-### luw_http_send_headers
-
-```C
-void luw_http_send_headers(const luw_ctx_t *ctx);
-```
-
-This function calls into Unit and triggers the sending of the response
-headers.
-
-### luw_http_response_end
-
-```C
-void luw_http_response_end(void);
-```
-
-This function calls into Unit and tells it this is the end of the response
-which will trigger Unit to send it to the client.
-
-### luw_mem_get_init_size
-
-```C
-u32 luw_mem_get_init_size(void);
-```
-
-This function calls into Unit to get the size of the shared memory. This is
-the amount of memory you should assume you have for creating responses.
-Remember you can create multiple responses before calling
-luw_http_response_end().
-
-### luw_foreach_http_hdr
-
-```C
-void luw_foreach_http_hdr(luw_ctx_t ctx, luw_http_hdr_iter_t *iter,
- const char *name, const char *value)
-```
-
-Defined as a macro, this is used to iterate over the HTTP header fields.
-
-It takes a _luw_ctx_t *_ and a _luw_http_hdr_iter_t *_ and returns pointers
-to the field name and value.
-
-Example
-
-```C
-luw_ctx_t ctx;
-luw_http_hdr_iter_t *iter;
-const char *name;
-const char *value;
-/* ... */
-luw_foreach_http_hdr(ctx, iter, name, value) {
- printf("Field name : %s, field value : %s\n", name, value);
- /* do something else with name & value */
-}
-```
-
-## Misc. Functions
-
-The following functions are convenience wrappers for the Rust bindings and
-should **not** be used directly.
-
-### luw_malloc
-
-```C
-void *luw_malloc(size_t size);
-```
-
-Straight wrapper for malloc(3).
-
-### luw_free
-
-```C
-void luw_free(void *ptr);
-```
-
-Straight wrapper for free(3).
diff --git a/API-C.rst b/API-C.rst
new file mode 100644
index 0000000..719fd6f
--- /dev/null
+++ b/API-C.rst
@@ -0,0 +1,1274 @@
+libunit-wasm C API
+==================
+
+C Library for creating WebAssembly modules for use with NGINX Unit.
+
+.. code:: c
+
+ #include <unit/unit-wasm.h>
+
+1. `libunit-wasm C API <#libunit-wasm-c-api>`__
+2. `Macros <#macros>`__
+
+- `Version <#version>`__
+- `Misc <#misc>`__
+
+3. `Types <#types>`__
+4. `Enums <#enums>`__
+
+- `luw_srb_flags_t <#luw_srb_flags_t>`__
+- `luw_http_status_t <#luw_http_status_t>`__
+
+5. `Structs <#structs>`__
+6. `Function Handlers <#function-handlers>`__
+
+- `Optional <#optional>`__
+
+ - `luw_module_init_handler <#luw_module_init_handler>`__
+ - `luw_module_end_handler <#luw_module_end_handler>`__
+ - `luw_request_init_handler <#luw_request_init_handler>`__
+ - `luw_request_end_handler <#luw_request_end_handler>`__
+ - `luw_response_end_handler <#luw_response_end_handler>`__
+
+- `Required <#required>`__
+
+ - `luw_request_handler <#luw_request_handler>`__
+ - `luw_free_handler <#luw_free_handler>`__
+ - `luw_malloc_handler <#luw_malloc_handler>`__
+
+7. `Functions <#functions>`__
+
+- `luw_init_ctx <#luw_init_ctx>`__
+- `luw_set_req_buf <#luw_set_req_buf>`__
+- `luw_get_http_path <#luw_get_http_path>`__
+- `luw_get_http_method <#luw_get_http_method>`__
+- `luw_get_http_version <#luw_get_http_version>`__
+- `luw_get_http_query <#luw_get_http_query>`__
+- `luw_get_http_remote <#luw_get_http_remote>`__
+- `luw_get_http_local_addr <#luw_get_http_local_addr>`__
+- `luw_get_http_local_port <#luw_get_http_local_port>`__
+- `luw_get_http_server_name <#luw_get_http_server_name>`__
+- `luw_get_http_content <#luw_get_http_content>`__
+- `luw_get_http_content_len <#luw_get_http_content_len>`__
+- `luw_get_http_content_sent <#luw_get_http_content_sent>`__
+- `luw_get_http_total_content_sent <#luw_get_http_total_content_sent>`__
+- `luw_http_is_tls <#luw_http_is_tls>`__
+- `luw_http_hdr_iter <#luw_http_hdr_iter>`__
+- `luw_http_hdr_get_value <#luw_http_hdr_get_value>`__
+- `luw_get_response_data_size <#luw_get_response_data_size>`__
+- `luw_mem_writep <#luw_mem_writep>`__
+- `luw_mem_writep_data <#luw_mem_writep_data>`__
+- `luw_req_buf_append <#luw_req_buf_append>`__
+- `luw_req_buf_copy <#luw_req_buf_copy>`__
+- `luw_mem_splice_file <#luw_mem_splice_file>`__
+- `luw_mem_fill_buf_from_req <#luw_mem_fill_buf_from_req>`__
+- `luw_mem_reset <#luw_mem_reset>`__
+- `luw_http_set_response_status <#luw_http_set_response_status>`__
+- `luw_http_send_response <#luw_http_send_response>`__
+- `luw_http_init_headers <#luw_http_init_headers>`__
+- `luw_http_add_header <#luw_http_add_header>`__
+- `luw_http_send_headers <#luw_http_send_headers>`__
+- `luw_http_response_end <#luw_http_response_end>`__
+- `luw_mem_get_init_size <#luw_mem_get_init_size>`__
+- `luw_foreach_http_hdr <#luw_foreach_http_hdr>`__
+
+8. `Misc. Functions <#misc-functions>`__
+
+- `luw_malloc <#luw_malloc>`__
+- `luw_free <#luw_free>`__
+
+Macros
+------
+
+Version
+~~~~~~~
+
+.. code:: c
+
+ #define LUW_VERSION_MAJOR M
+ #define LUW_VERSION_MINOR m
+ #define LUW_VERSION_PATCH p
+
+.. code:: c
+
+ /* Version number in hex 0xMMmmpp00 */
+ #define LUW_VERSION_NUMBER \
+ ( (LUW_VERSION_MAJOR << 24) | \
+ (LUW_VERSION_MINOR << 16) | \
+ (LUW_VERSION_PATCH << 8) )
+
+Misc
+~~~~
+
+.. code:: c
+
+ #define __luw_export_name(name) __attribute__((export_name(name)))
+
+.. code:: c
+
+ #define __luw_unused __attribute__((unused))
+ #define __luw_maybe_unused __luw_unused
+
+.. code:: c
+
+ #define luw_foreach_http_hdr(ctx, iter, name, value) \
+ for (iter = ctx.req->fields, \
+ name = (const char *)ctx.req + iter->name_off; \
+ (iter < (ctx.req->fields + ctx.req->nr_fields)) && \
+ (value = (const char *)ctx.req + iter->value_off); \
+ iter++, name = (const char *)ctx.req + iter->name_off)
+
+Types
+-----
+
+.. code:: c
+
+ 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;
+
+Enums
+-----
+
+luw_srb_flags_t
+~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ typedef enum {
+ LUW_SRB_NONE = 0x00,
+ LUW_SRB_APPEND = 0x01,
+ LUW_SRB_ALLOC = 0x02,
+ LUW_SRB_FULL_SIZE = 0x04,
+
+ LUW_SRB_FLAGS_ALL = (LUW_SRB_NONE|LUW_SRB_APPEND|LUW_SRB_ALLOC|
+ LUW_SRB_FULL_SIZE)
+ } luw_srb_flags_t;
+
+luw_http_status_t
+~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ typedef enum {
+ LUW_HTTP_CONTINUE = 100,
+ LUW_HTTP_SWITCHING_PROTOCOLS = 101,
+
+ LUW_HTTP_OK = 200,
+ LUW_HTTP_CREATED = 201,
+ LUW_HTTP_ACCEPTED = 202,
+ LUW_HTTP_NO_CONTENT = 204,
+
+ LUW_HTTP_MULTIPLE_CHOICES = 300,
+ LUW_HTTP_MOVED_PERMANENTLY = 301,
+ LUW_HTTP_FOUND = 302,
+ LUW_HTTP_SEE_OTHER = 303,
+ LUW_HTTP_NOT_MODIFIED = 304,
+ LUW_HTTP_TEMPORARY_REDIRECT = 307,
+ LUW_HTTP_PERMANENT_REDIRECT = 308,
+
+ LUW_HTTP_BAD_REQUEST = 400,
+ LUW_HTTP_UNAUTHORIZED = 401,
+ LUW_HTTP_FORBIDDEN = 403,
+ LUW_HTTP_NOT_FOUND = 404,
+ LUW_HTTP_METHOD_NOT_ALLOWED = 405,
+ LUW_HTTP_NOT_ACCEPTABLE = 406,
+ LUW_HTTP_REQUEST_TIMEOUT = 408,
+ LUW_HTTP_CONFLICT = 409,
+ LUW_HTTP_GONE = 410,
+ LUW_HTTP_LENGTH_REQUIRED = 411,
+ LUW_HTTP_PAYLOAD_TOO_LARGE = 413,
+ LUW_HTTP_URI_TOO_LONG = 414,
+ LUW_HTTP_UNSUPPORTED_MEDIA_TYPE = 415,
+ LUW_HTTP_UPGRADE_REQUIRED = 426,
+ LUW_HTTP_TOO_MANY_REQUESTS = 429,
+ LUW_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
+
+ /* Proposed by RFC 7725 */
+ LUW_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
+
+ LUW_HTTP_INTERNAL_SERVER_ERROR = 500,
+ LUW_HTTP_NOT_IMPLEMENTED = 501,
+ LUW_HTTP_BAD_GATEWAY = 502,
+ LUW_HTTP_SERVICE_UNAVAILABLE = 503,
+ LUW_HTTP_GATEWAY_TIMEOUT = 504,
+ } luw_http_status_t;
+
+Structs
+-------
+
+.. code:: c
+
+ struct luw_hdr_field {
+ u32 name_off;
+ u32 name_len;
+ u32 value_off;
+ u32 value_len;
+ };
+
+.. code:: c
+
+ struct luw_req {
+ u32 method_off;
+ u32 method_len;
+ u32 version_off;
+ u32 version_len;
+ u32 path_off;
+ u32 path_len;
+ u32 query_off;
+ u32 query_len;
+ u32 remote_off;
+ u32 remote_len;
+ u32 local_addr_off;
+ u32 local_addr_len;
+ u32 local_port_off;
+ u32 local_port_len;
+ u32 server_name_off;
+ u32 server_name_len;
+
+ u64 content_len;
+ u64 total_content_sent;
+ u32 content_sent;
+ u32 content_off;
+
+ u32 request_size;
+
+ u32 nr_fields;
+
+ u32 tls;
+
+ char __pad[4];
+
+ struct luw_hdr_field fields[];
+ };
+
+.. code:: c
+
+ struct luw_resp {
+ u32 size;
+
+ u8 data[];
+ };
+
+.. code:: c
+
+ struct luw_resp_hdr {
+ u32 nr_fields;
+
+ struct luw_hdr_field fields[];
+ };
+
+.. code:: c
+
+ typedef struct {
+ /* pointer to the shared memory */
+ u8 *addr;
+
+ /* points to the end of ctx->resp->data */
+ u8 *mem;
+
+ /* struct luw_req representation of the shared memory */
+ struct luw_req *req;
+
+ /* struct luw_resp representation of the shared memory */
+ struct luw_resp *resp;
+
+ /* struct luw_resp_hdr representation of the shared memory */
+ struct luw_resp_hdr *resp_hdr;
+
+ /* offset to where the struct resp starts in the shared memory */
+ size_t resp_offset;
+
+ /* points to the external buffer used for a copy of the request */
+ u8 *req_buf;
+
+ /* points to the end of the fields array in struct luw_resp_hdr */
+ u8 *hdrp;
+
+ /* points to the end of ctx->req_buf */
+ u8 *reqp;
+
+ /* tracks the response header index number */
+ s32 resp_hdr_idx;
+ } luw_ctx_t;
+
+.. code:: c
+
+ typedef struct luw_hdr_field luw_http_hdr_iter_t;
+
+Function Handlers
+-----------------
+
+These functions are exported from the WebAssembly module and are called
+from the WebAssembly runtime (the Unit WebAssembly language module in
+this case).
+
+There are two types of handlers; required & optional.
+
+luw_request_handler(), luw_malloc_handler() & luw_free_handler() are
+required with the rest being optional.
+
+libunit-wasm includes exports for these handlers and some default
+implementations.
+
+These functions are defined as *weak* symbols and so if a developer
+writes their own function of the same name, that will take precedence.
+
+However, developers are under no obligation to use these and can create
+their own with any (valid) names they like.
+
+Whatever names developers choose, they are specified in the Unit config.
+
+Required
+~~~~~~~~
+
+luw_request_handler
+^^^^^^^^^^^^^^^^^^^
+
+.. code:: c
+
+ __attribute__((export_name("luw_request_handler"), __weak__))
+ int luw_request_handler(u8 *addr);
+
+This is called by Unit during a request. It may be called multiple times
+for a single HTTP request if there is more request data than the
+available memory for host <–> module communications.
+
+You will need to provide your own implementation of this function.
+
+It receives the base address of the shared memory. Essentially what is
+returned by luw_malloc_handler().
+
+This memory will contain a *struct luw_req*.
+
+It returns an int. This should nearly always be *0*.
+
+If you wish to indicate a ‘500 Internal Server Error’, for example if
+some internal API has failed or an OS level error occurred, then you can
+simply return *-1*, *if* you have haven’t already *sent* any response or
+headers.
+
+You can still return 0 *and* set the HTTP response status to 500 using
+`luw_http_set_response_status <#luw_http_set_response_status>`__.
+
+luw_malloc_handler
+^^^^^^^^^^^^^^^^^^
+
+.. code:: c
+
+ __attribute__((export_name("luw_malloc_handler"), __weak__))
+ u32 luw_malloc_handler(size_t size);
+
+This is called by Unit when it loads the WebAssembly language module.
+This provides the shared memory used for host <–> module communications.
+
+It receives the desired size of the memory, which is currently
+NXT_WASM_MEM_SIZE + NXT_WASM_PAGE_SIZE.
+
+However calls to luw_mem_get_init_size() will return just
+NXT_WASM_MEM_SIZE (which is currently 32MiB). The extra
+NXT_WASM_PAGE_SIZE is to cater for structure sizes in the response so
+developers can generally assume they have the full NXT_WASM_MEM_SIZE for
+their data.
+
+A default implementation of this function is provided ready for use that
+calls malloc(3).
+
+luw_free_handler
+^^^^^^^^^^^^^^^^
+
+.. code:: c
+
+ __attribute__((export_name("luw_free_handler"), __weak__))
+ void luw_free_handler(u32 addr);
+
+This is called by Unit when it shuts down the WebAssembly language
+module and free’s the memory previously allocated by
+luw_malloc_handler().
+
+It receives the address of the memory to free.
+
+An implementation of this function is provided ready for use that calls
+free(3), in which case it receives the address that was previously
+returned by luw_malloc_handler().
+
+Optional
+~~~~~~~~
+
+luw_module_init_handler
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: c
+
+ __attribute__((export_name("luw_module_init_handler"), __weak__))
+ void luw_module_init_handler(void);
+
+This is called by Unit when it loads the WebAssembly language module.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+luw_module_end_handler
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: c
+
+ __attribute__((export_name("luw_module_end_handler"), __weak__))
+ void luw_module_end_handler(void);
+
+This is called by Unit when it shuts down the WebAssembly language
+module.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+luw_request_init_handler
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: c
+
+ __attribute__((export_name("luw_request_init_handler"), __weak__))
+ void luw_request_init_handler(void);
+
+This is called by Unit at the start of nxt_wasm_request_handler(), i.e
+at the start of a new request.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+luw_request_end_handler
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: c
+
+ __attribute__((export_name("luw_request_end_handler"), __weak__))
+ void luw_request_end_handler(void);
+
+This is called by Unit at the end of nxt_wasm_request_handler(), i.e at
+the end of a request.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+luw_response_end_handler
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: c
+
+ __attribute__((export_name("luw_response_end_handler"), __weak__))
+ void luw_response_end_handler(void);
+
+This is called by Unit after luw_http_response_end() has been called.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+Functions
+---------
+
+luw_init_ctx
+~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_init_ctx(luw_ctx_t *ctx, u8 *addr, size_t offset);
+
+This function sets up a *luw_ctx_t* context structure, this contains
+stuff required all throughout the API. It’s a typedef for opaqueness and
+you should not in general be concerned with its contents.
+
+It take a pointer to a stack allocated luw_ctx_t, this will be zeroed
+and have various members initialised.
+
+**addr** is a pointer to the shared memory as passed into
+luw_request_handler().
+
+**offset** is where in the shared memory it should start writing the
+response.
+
+A quick word about memory
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The way the Unit WebAssembly language module (the host/runtime) and the
+WebAssembly module you want to write (the guest) communicate is via a
+chunk of shared memory.
+
+This shared memory is simply the modules (guest) address space from
+which we can allocate a chunk. How this memory is laid out varies on how
+the module is built.
+
+With clang/linker flags of -Wl,–stack-first
+-Wl,-z,stack-size=$((8\ *1024*\ 1024)) we get a memory layout something
+like
+
+::
+
+ |----------------------------------------------------------------------|
+ | | | |
+ | <-- Stack | Global Data | Heap --> |
+ | | | |
+ |----------------------------------------------------------------------|
+ 0 0x800000 0x100000000
+
+ WebAssembly Module Linear Memory / Process Memory Layout
+
+(The above is assuming *–target=wasm32-wasi*, i.e 32bit)
+
+A chunk of memory from the heap is allocated at Unit WebAssembly
+language module startup.
+
+We currently use this same chunk of memory for both requests and
+responses. This means that depending on what you’re doing, you’ll want
+to take a copy of the request (and remember luw_request_handler() may be
+called multiple times for a single http request).
+
+That will be covered in more detail by the next function,
+luw_set_req_buf().
+
+Now back to *offset*, it may be convenient to put the response headers
+at the beginning of this memory and then put the response after it,
+rather than doing the headers and then doing the response as separate
+steps, if the headers depends on some aspect of the response, its size
+for example and Content-Length.
+
+Example
+
+.. code:: c
+
+ luw_ctx_t ctx;
+ /* ... */
+ luw_init_ctx(&ctx, addr, 4096 /* Response offset */);
+
+luw_set_req_buf
+~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ int luw_set_req_buf(luw_ctx_t *ctx, u8 **buf, unsigned int flags);
+
+This function is used to take a copy of the request buffer (as discussed
+above).
+
+This takes a previously initialised (with luw_init_ctx()) luw_ctx_t.
+
+**buf** is a buffer where the request data will written.
+
+**flags** can be some combination (OR’d) of the following
+
+**LUW_SRB_NONE**
+
+No specific action to be performed. It will simply copy the request data
+into the specified buffer.
+
+**LUW_SRB_APPEND**
+
+Sets up append mode whereby multiple successive requests will be
+appended to the specified buffer.
+
+The first request will have all its metadata copied. Subsequent requests
+will *only* have the actual body data appended.
+
+**LUW_SRB_ALLOC**
+
+Allocate memory for the specified buffer.
+
+**LUW_SRB_FULL_SIZE**
+
+Used in conjunction with *LUW_SRB_ALLOC*. By default only
+*ctx->req->request_size* is allocated. If this flag is present it says
+to allocate memory for the *entire* request that will eventually be
+sent.
+
+Example
+
+.. code:: c
+
+ static u8 *request_buf;
+ */ ... */
+ int luw_request_handler(u8 *addr)
+ {
+ if (!request_buf) {
+ luw_init_ctx(&ctx, addr, 0);
+ /*
+ * 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);
+ }
+
+ /* operate on the request (ctx) */
+
+ return 0;
+ }
+
+That example is taken from the
+`luw-upload-reflector.c <https://github.com/nginx/unit-wasm/blob/main/examples/c/luw-upload-reflector.c>`__
+demo module. For a simpler example see
+`luw-echo-request.c <https://github.com/nginx/unit-wasm/blob/main/examples/c/luw-echo-request.c>`__
+
+luw_get_http_path
+~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_get_http_path(const luw_ctx_t *ctx);
+
+This function returns a pointer to the HTTP request path.
+
+E.g
+
+Given a request of
+
+::
+
+ http://localhost:8080/echo/?q=a
+
+this function will return
+
+::
+
+ /echo/?q=a
+
+luw_get_http_method
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_get_http_method(const luw_ctx_t *ctx);
+
+This function returns a pointer to the HTTP method.
+
+E.g
+
+::
+
+ GET
+
+luw_get_http_version
+~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_get_http_version(const luw_ctx_t *ctx);
+
+This function returns a pointer to the HTTP version.
+
+E.g
+
+::
+
+ 1.1
+
+luw_get_http_query
+~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_get_http_query(const luw_ctx_t *ctx);
+
+This function returns a pointer to the query string (empty string for no
+query string).
+
+E.g
+
+Given a request of
+
+::
+
+ http://localhost:8080/echo/?q=a
+
+this function will return
+
+::
+
+ q=a
+
+luw_get_http_remote
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_get_http_remote(const luw_ctx_t *ctx);
+
+This function returns a pointer to the remote/client/peer address.
+
+E.g
+
+::
+
+ 2001:db8::f00
+
+luw_get_http_local_addr
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_get_http_local_addr(const luw_ctx_t *ctx);
+
+This function returns a pointer to the local/server address.
+
+E.g
+
+::
+
+ 2001:db8::1
+
+luw_get_http_local_port
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_get_http_local_port(const luw_ctx_t *ctx);
+
+This function returns a pointer to the local/server port.
+
+E.g
+
+::
+
+ 443
+
+luw_get_http_server_name
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_get_http_server_name(const luw_ctx_t *ctx);
+
+This function returns a pointer to the local/server name.
+
+E.g
+
+::
+
+ www.example.com
+
+luw_get_http_content
+~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const u8 *luw_get_http_content(const luw_ctx_t *ctx);
+
+This function returns a pointer to the start of the request body.
+
+luw_get_http_content_len
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ u64 luw_get_http_content_len(const luw_ctx_t *ctx);
+
+This function returns the size of the overall content. I.e
+Content-Length.
+
+Prior to version 0.3.0 it returned a size_t
+
+luw_get_http_content_sent
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ size_t luw_get_http_content_sent(const luw_ctx_t *ctx);
+
+This function returns the length of the content that was sent to the
+WebAssembly module in *this* request. Remember, a single HTTP request
+may be split over several calls to luw_request_handler().
+
+luw_get_http_total_content_sent
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ u64 luw_get_http_total_content_sent(const luw_ctx_t *ctx);
+
+This function returns the total length of the content that was sent to
+the WebAssembly module so far. Remember, a single HTTP request may be
+split over several calls to luw_request_handler().
+
+*Version: 0.2.0* Prior to 0.3.0 it returned a size_t
+
+luw_http_is_tls
+~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ bool luw_http_is_tls(const luw_ctx_t *ctx);
+
+This function returns *true* if the connection to Unit was made over
+TLS.
+
+luw_http_hdr_iter
+~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_http_hdr_iter(luw_ctx_t *ctx,
+ bool (*luw_http_hdr_iter_func)(luw_ctx_t *ctx,
+ const char *name,
+ const char *value,
+ void *data),
+ void *user_data)
+
+This function allows to iterate over the HTTP headers. For each header
+it will call the given luw_http_hdr_iter_func() function whose prototype
+is
+
+.. code:: c
+
+ bool luw_http_hdr_iter_func(luw_ctx_t *ctx,
+ const char *name, const char *value, void *data);
+
+You may call this function whatever you like. For each header it will be
+passed the *luw_ctx_t*, the header name, its value and a user specified
+pointer if any, can be NULL.
+
+Returning *true* from this function will cause the iteration process to
+continue, returning *false* will terminate it.
+
+Example
+
+.. code:: c
+
+ static bool hdr_iter_func(luw_ctx_t *ctx, const char *name, const char *value,
+ void *user_data __luw_unused)
+ {
+ /* Do something with name & value */
+
+ /* Continue iteration or return false to stop */
+ return true;
+ }
+
+ /* ... *
+
+ luw_http_hdr_iter(&ctx, hdr_iter_func, NULL);
+
+luw_http_hdr_get_value
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ const char *luw_http_hdr_get_value(const luw_ctx_t *ctx, const char *hdr);
+
+Given a HTTP header *hdr* this function will look it up in the request
+and return its value if found, otherwise *NULL*.
+
+The lookup is done case insensitively.
+
+luw_get_response_data_size
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ size_t luw_get_response_data_size(const luw_ctx_t *ctx);
+
+This function returns the size of the response data written to memory.
+
+luw_mem_writep
+~~~~~~~~~~~~~~
+
+.. code:: c
+
+ __attribute__((__format__(printf, 2, 3)))
+ int luw_mem_writep(luw_ctx_t *ctx, const char *fmt, ...);
+
+This function is a cross between vasprintf(3) and mempcpy(3).
+
+It takes a format argument and zero or more arguments that will be
+substituted into the format string.
+
+It then appends this formatted string to the memory. Note this string
+will *not* be nul terminated. Unit does not expect this response data to
+be nul terminated and we track the size of the response and return that
+to Unit.
+
+This function returns -1 on error or the length of the string written.
+
+luw_mem_writep_data
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ size_t luw_mem_writep_data(luw_ctx_t *ctx, const u8 *src, size_t size);
+
+This function just appends *size* bytes from *src* to the response.
+
+It returns the new size of the response.
+
+luw_req_buf_append
+~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_req_buf_append(luw_ctx_t *ctx, const u8 *src);
+
+This function appends the request data contained in *src* to the
+previously setup *request_buffer* with luw_set_req_buf().
+
+This function would be used after an initial request to append the data
+from subsequent requests to the request_buffer.
+
+Example
+
+.. code:: c
+
+ int luw_request_handler(u8 *addr)
+ {
+ if (!request_buf) {
+ luw_init_ctx(&ctx, addr, 0);
+ /*
+ * 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);
+ }
+
+ /* Do something with the request (ctx) */
+
+ return 0;
+ }
+
+luw_req_buf_copy
+~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_req_buf_copy(luw_ctx_t *ctx, const u8 *src);
+
+This function is analogous to
+`luw_req_buf_append <#luw_req_buf_append>`__ but rather than appending
+the request data contained in *src* to the previously setup
+*request_buffer* with luw_set_req_buf(), it simply overwrites what’s
+currently there.
+
+This function could be used to handle large requests/uploads that you
+want to save out to disk or some such and can’t buffer it all in memory.
+
+Example
+
+.. code:: c
+
+ int luw_request_handler(u8 *addr)
+ {
+ const u8 *buf;
+ ssize_t bytes_wrote;
+
+ if (total_bytes_wrote == 0) {
+ luw_init_ctx(&ctx, addr, 0);
+ luw_set_req_buf(&ctx, &request_buf, LUW_SRB_NONE);
+
+ fd = open("/var/tmp/large-file.dat", O_CREAT|O_TRUNC|O_WRONLY,
+ 0666);
+ } else {
+ luw_req_buf_copy(&ctx, addr);
+ }
+
+ buf = luw_get_http_content(&ctx);
+ bytes_wrote = write(fd, buf, luw_get_http_content_sent(&ctx));
+ if (bytes_wrote == -1)
+ return -1;
+
+ total_bytes_wrote += bytes_wrote;
+ if (total_bytes_wrote == luw_get_http_content_len(&ctx))
+ luw_http_response_end();
+
+ return 0;
+ }
+
+*Version: 0.3.0*
+
+luw_mem_splice_file
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ ssize_t luw_mem_splice_file(const u8 *src, int fd);
+
+This function write(2)’s the request data directly from the shared
+memory (*src*) to the file represented by the given file-descriptor
+(*fd*).
+
+This can be used as an alternative to
+`luw_req_buf_copy <#luw_req_buf_copy>`__ and avoids an extra copying of
+the request data.
+
+Example
+
+.. code:: c
+
+ int luw_request_handler(u8 *addr) {
+ ssize_t bytes_wrote;
+
+ if (total_bytes_wrote == 0) {
+ luw_init_ctx(&ctx, addr, 0);
+ luw_set_req_buf(&ctx, &request_buf, LUW_SRB_NONE);
+
+ fd = open("/var/tmp/large-file.dat", O_CREAT|O_TRUNC|O_WRONLY,
+ 0666);
+ }
+
+ bytes_wrote = luw_mem_splice_file(addr, fd);
+ if (bytes_wrote == -1)
+ return -1;
+
+ total_bytes_wrote += bytes_wrote;
+ if (total_bytes_wrote == luw_get_http_content_len(&ctx))
+ luw_http_response_end();
+
+ return 0;
+ }
+
+*Version: 0.3.0*
+
+luw_mem_fill_buf_from_req
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ size_t luw_mem_fill_buf_from_req(luw_ctx_t *ctx, size_t from);
+
+This is a convenience function to fill the response buffer with data
+from the request buffer.
+
+*from* is basically the offset in the request_buffer where to start
+copying data from.
+
+Example
+
+.. code:: c
+
+ /* ... */
+ write_bytes = luw_mem_fill_buf_from_req(ctx, total_response_sent);
+ total_response_sent += write_bytes;
+ /* ... */
+
+This is taken from the
+`luw-upload-reflector.c <https://github.com/nginx/unit-wasm/blob/main/examples/c/luw-upload-reflector.c>`__
+demo module.
+
+In this case we build up a request_buffer on each call of
+luw_request_handler(), so total_response_sent grows each time by how
+much data was sent in *that* request.
+
+Here are are sending data back to the client after each time we receive
+it to demonstrate the interleaving of requests and responses from the
+WebAssembly module during a single http request.
+
+This function returns the number of bytes written to the response
+buffer.
+
+luw_mem_reset
+~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_mem_reset(luw_ctx_t *ctx);
+
+This function resets the response buffer size and the number of response
+headers back to 0.
+
+luw_http_set_response_status
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_http_set_response_status(luw_http_status_t status);
+
+This function is used to set the HTTP response status. It takes one of
+the `luw_http_status_t <#luw_http_status_t>`__ enum values.
+
+It should be called before any calls to *luw_http_send_response()* or
+*luw_http_send_headers()*.
+
+If you don’t call this function the response status defaults to ‘200
+OK’.
+
+If you wish to error out with a ‘500 Internal Server Error’, you don’t
+need to call this function. Simply returning *-1* from the
+request_handler function will indicate this error.
+
+E.g
+
+Send a ‘403 Forbidden’
+
+.. code:: c
+
+ /* ... */
+ luw_http_set_response_status(LUW_HTTP_FORBIDDEN);
+ luw_http_send_response(ctx); /* Doesn't require any body */
+ luw_http_response_end();
+ /* ... */
+ return 0;
+
+Send a ‘307 Temporary Re-direct’
+
+.. code:: c
+
+ /* ... */
+ luw_http_set_response_status(LUW_HTTP_TEMPORARY_REDIRECT);
+
+ luw_http_init_headers(ctx, 1, 0);
+ luw_http_add_header(ctx, "Location", "https://example.com/");
+ luw_http_send_headers(ctx);
+ luw_http_response_end();
+ /* ... */
+ return 0;
+
+*Version: 0.3.0*
+
+luw_http_send_response
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_http_send_response(const luw_ctx_t *ctx);
+
+This function calls into Unit to send the response buffer back.
+
+luw_http_init_headers
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_http_init_headers(luw_ctx_t *ctx, size_t nr, size_t offset);
+
+This function is used in the preparation of sending back response
+headers.
+
+*nr* is the number of headers we are sending.
+
+*offset* is the offset into the response buffer where we are placing
+these headers. This will usually be 0.
+
+Example
+
+.. code:: c
+
+ luw_http_init_headers(ctx, 2, 0);
+
+luw_http_add_header
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_http_add_header(luw_ctx_t *ctx, const char *name, const char *value);
+
+This function is used to add a header to the response.
+
+*name* is the name of the header.
+
+*value* is the value of the header.
+
+Example
+
+.. code:: c
+
+ char clen[32];
+ /* ... */
+ snprintf(clen, sizeof(clen), "%lu", luw_get_response_data_size(&ctx));
+ luw_http_add_header(&ctx, "Content-Type", "text/plain");
+ luw_http_add_header(&ctx, "Content-Length", clen);
+
+luw_http_send_headers
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_http_send_headers(const luw_ctx_t *ctx);
+
+This function calls into Unit and triggers the sending of the response
+headers.
+
+luw_http_response_end
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_http_response_end(void);
+
+This function calls into Unit and tells it this is the end of the
+response which will trigger Unit to send it to the client.
+
+luw_mem_get_init_size
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ u32 luw_mem_get_init_size(void);
+
+This function calls into Unit to get the size of the shared memory. This
+is the amount of memory you should assume you have for creating
+responses. Remember you can create multiple responses before calling
+luw_http_response_end().
+
+luw_foreach_http_hdr
+~~~~~~~~~~~~~~~~~~~~
+
+.. code:: c
+
+ void luw_foreach_http_hdr(luw_ctx_t ctx, luw_http_hdr_iter_t *iter,
+ const char *name, const char *value)
+
+Defined as a macro, this is used to iterate over the HTTP header fields.
+
+It takes a \_luw_ctx_t \*\_ and a \_luw_http_hdr_iter_t \*\_ and returns
+pointers to the field name and value.
+
+Example
+
+.. code:: c
+
+ luw_ctx_t ctx;
+ luw_http_hdr_iter_t *iter;
+ const char *name;
+ const char *value;
+ /* ... */
+ luw_foreach_http_hdr(ctx, iter, name, value) {
+ printf("Field name : %s, field value : %s\n", name, value);
+ /* do something else with name & value */
+ }
+
+Misc. Functions
+---------------
+
+The following functions are convenience wrappers for the Rust bindings
+and should **not** be used directly.
+
+luw_malloc
+~~~~~~~~~~
+
+.. code:: c
+
+ void *luw_malloc(size_t size);
+
+Straight wrapper for malloc(3).
+
+luw_free
+~~~~~~~~
+
+.. code:: c
+
+ void luw_free(void *ptr);
+
+Straight wrapper for free(3).
diff --git a/API-Rust.md b/API-Rust.md
deleted file mode 100644
index 9b4a9d9..0000000
--- a/API-Rust.md
+++ /dev/null
@@ -1,1138 +0,0 @@
-# 'Rusty' Rust API
-
-Rusty is a more native Rust wrapper around the auto-generated bindings to
-[libunit-wasm](https://github.com/nginx/unit-wasm/blob/main/API-C.md).
-
-```Rust
-use unit_wasm::rusty::*;
-```
-
-If using
-
-```Rust
-uwr_http_hdr_iter();
-```
-
-```Rust
-use std::ffi::CStr;
-use std::os::raw::c_char;
-use std::os::raw::c_void;
-```
-
-## Naming
-
-You will see references to functions etc starting with *luw_* or *LUW_* and
-*uwr_".
-
-**luw/LUW** (libunit-wasm) come from the underlying C library and in the Rust
-case are the auto-generated bindings with a few manual additions.
-
-**uwr** (Unit Wasm Rust aka '_rusty_') is a more Rust native wrapper ontop of
-the bindings.
-
-In _rusty_ the luw/LUW API is generally the low level stuff like the library
-version macros and the various function handlers where they can be used as is
-and there isn't a real need to create wrappers specifically for them.
-
-1. ['Rusty' Rust API](#rusty-rust-api)
- * [Naming](#naming)
-2. [Macros](#macros)
- * [Version](#version)
- * [String Conversion](#string-conversion)
- * [uwr_write_str!](#uwr_write_str)
-3. [Enums](#enums)
- [luw_http_status_t](#luw_http_status_t)
-3. [Function Handlers](#function-handlers)
- * [Optional](#optional)
- - [luw_module_init_handler](#luw_module_init_handler)
- - [luw_module_end_handler](#luw_module_end_handler)
- - [luw_request_init_handler](#luw_request_init_handler)
- - [luw_request_end_handler](#luw_request_end_handler)
- - [luw_response_end_handler](#luw_response_end_handler)
- * [Required](#required)
- - [luw_request_handler](#luw_request_handler)
- - [luw_free_handler](#luw_free_handler)
- - [luw_malloc_handler](#luw_malloc_handler)
-4. [Functions](#functions)
- * [UWR_CTX_INITIALIZER](#uwr_ctx_initializer)
- * [uwr_init_ctx](#uwr_init_ctx)
- * [uwr_set_req_buf](#uwr_set_req_buf)
- * [uwr_get_http_path](#uwr_get_http_path)
- * [uwr_get_http_method](#uwr_get_http_method)
- * [uwr_get_http_version](#uwr_get_http_version)
- * [uwr_get_http_query](#uwr_get_http_query)
- * [uwr_get_http_remote](#uwr_get_http_remote)
- * [uwr_get_http_local_addr](#uwr_get_http_local_addr)
- * [uwr_get_http_local_port](#uwr_get_http_local_port)
- * [uwr_get_http_server_name](#uwr_get_http_server_name)
- * [uwr_get_http_content](#uwr_get_http_content)
- * [uwr_get_http_content_str](#uwr_get_http_content_str)
- * [uwr_get_http_content_len](#uwr_get_http_content_len)
- * [uwr_get_http_content_sent](#uwr_get_http_content_sent)
- * [uwr_get_http_total_content_sent](#uwr_get_http_total_content_sent)
- * [uwr_http_is_tls](#uwr_http_is_tls)
- * [uwr_http_hdr_iter](#uwr_http_hdr_iter)
- * [uwr_http_hdr_get_value](#uwr_http_hdr_get_value)
- * [uwr_get_response_data_size](#uwr_get_response_data_size)
- * [uwr_mem_write_buf](#uwr_mem_write_buf)
- * [uwr_req_buf_append](#uwr_req_buf_append)
- * [uwr_req_buf_copy](#uwr_req_buf_copy)
- * [uwr_mem_splice_file](#uwr_mem_splice_file)
- * [uwr_mem_fill_buf_from_req](#uwr_mem_fill_buf_from_req)
- * [uwr_mem_reset](#uwr_mem_reset)
- * [uwr_http_set_response_status](#uwr_http_set_response_status)
- * [uwr_http_send_response](#uwr_http_send_response)
- * [uwr_http_init_headers](#uwr_http_init_headers)
- * [uwr_http_add_header](#uwr_http_add_header)
- * [uwr_http_add_header_content_type](#uwr_http_add_header_content_type)
- * [uwr_http_add_header_content_len](#uwr_http_add_header_content_len)
- * [uwr_http_send_headers](#uwr_http_send_headers)
- * [uwr_http_response_end](#uwr_http_response_end)
- * [uwr_mem_get_init_size](#uwr_mem_get_init_size)
-5. [Misc. Functions](#misc-functions)
- * [uwr_malloc](#uwr_malloc)
- * [uwr_free](#uwr_free)
-
-## Macros
-
-### Version
-
-For the underlying libunit-wasm version.
-
-```Rust
-pub const LUW_VERSION_MAJOR: i32;
-pub const LUW_VERSION_MINOR: i32;
-pub const LUW_VERSION_PATCH: i32;
-```
-
-```Rust
-/* Version number in hex 0xMMmmpp00 */
-pub const LUW_VERSION_NUMBER: i32 =
- (LUW_VERSION_MAJOR << 24) | \
- (LUW_VERSION_MINOR << 16) | \
- (LUW_VERSION_PATCH << 8);
-```
-
-### String Conversion
-
-```Rust
-C2S!(string);
-```
-
-Converts a C string into a Rust String
-
-Main use is internally and in the *uwr_http_hdr_iter()* callback function,
-e.g
-
-```Rust
-pub extern "C" fn hdr_iter_func(
- ctx: *mut luw_ctx_t,
- name: *const c_char,
- value: *const c_char,
- _data: *mut c_void,
-) -> bool {
- uwr_write_str!(ctx, "{} = {}\n", C2S!(name), C2S!(value));
-
- return true;
-}
-```
-
-Example taken from the
-[echo-request](https://github.com/nginx/unit-wasm/blob/main/examples/rust/echo-request/src/lib.rs)
-Wasm demo module
-
-```Rust
-S2C!(formatted string);
-```
-
-Converts a Rust String, with optional formatting, to a C string.
-
-Used internally.
-
-### uwr_write_str!
-
-```Rust
-uwr_write_str!*ctx, fmt, ...);
-```
-
-This is essentially a wrapper around
-[luw_mem_writep_data()](https://github.com/nginx/unit-wasm/blob/main/API-C.md#luw_mem_writep_data)
-
-It is the main way to write responses back to the client.
-
-It takes the luw_ctx_t context pointer, a string that will be run through the
-[format!()](https://doc.rust-lang.org/std/macro.format.html) macro and any
-optional arguments.
-
-## Enums
-
-### luw_http_status_t
-```Rust
-pub enum luw_http_status_t {
- LUW_HTTP_CONTINUE = 100,
- LUW_HTTP_SWITCHING_PROTOCOLS = 101,
-
- LUW_HTTP_OK = 200,
- LUW_HTTP_CREATED = 201,
- LUW_HTTP_ACCEPTED = 202,
- LUW_HTTP_NO_CONTENT = 204,
-
- LUW_HTTP_MULTIPLE_CHOICES = 300,
- LUW_HTTP_MOVED_PERMANENTLY = 301,
- LUW_HTTP_FOUND = 302,
- LUW_HTTP_SEE_OTHER = 303,
- LUW_HTTP_NOT_MODIFIED = 304,
- LUW_HTTP_TEMPORARY_REDIRECT = 307,
- LUW_HTTP_PERMANENT_REDIRECT = 308,
-
- LUW_HTTP_BAD_REQUEST = 400,
- LUW_HTTP_UNAUTHORIZED = 401,
- LUW_HTTP_FORBIDDEN = 403,
- LUW_HTTP_NOT_FOUND = 404,
- LUW_HTTP_METHOD_NOT_ALLOWED = 405,
- LUW_HTTP_NOT_ACCEPTABLE = 406,
- LUW_HTTP_REQUEST_TIMEOUT = 408,
- LUW_HTTP_CONFLICT = 409,
- LUW_HTTP_GONE = 410,
- LUW_HTTP_LENGTH_REQUIRED = 411,
- LUW_HTTP_PAYLOAD_TOO_LARGE = 413,
- LUW_HTTP_URI_TOO_LONG = 414,
- LUW_HTTP_UNSUPPORTED_MEDIA_TYPE = 415,
- LUW_HTTP_UPGRADE_REQUIRED = 426,
- LUW_HTTP_TOO_MANY_REQUESTS = 429,
- LUW_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
-
- /* Proposed by RFC 7725 */
- LUW_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
-
- LUW_HTTP_INTERNAL_SERVER_ERROR = 500,
- LUW_HTTP_NOT_IMPLEMENTED = 501,
- LUW_HTTP_BAD_GATEWAY = 502,
- LUW_HTTP_SERVICE_UNAVAILABLE = 503,
- LUW_HTTP_GATEWAY_TIMEOUT = 504,
-}
-```
-
-## Function Handlers
-
-These functions are exported from the WebAssembly module and are called from
-the WebAssembly runtime (the Unit WebAssembly language module in this case).
-
-There are two types of handlers; required & optional.
-
-luw_request_handler(), luw_malloc_handler() & luw_free_handler() are required
-with the rest being optional.
-
-libunit-wasm includes exports for these handlers and some default
-implementations.
-
-These functions are defined as _weak_ symbols and so if a developer writes
-their own function of the same name, that will take precedence.
-
-However, developers are under no obligation to use these and can create their
-own with any (valid) names they like.
-
-Whatever names developers choose, they are specified in the Unit config.
-
-## Required
-
-#### luw_request_handler
-
-```Rust
-#[no_mangle]
-pub extern "C" fn luw_request_handler(addr: *mut u8) -> i32;
-```
-
-This is called by Unit during a request. It may be called multiple times for
-a single HTTP request if there is more request data than the available memory
-for host <--> module communications.
-
-You will need to provide your own implementation of this function.
-
-It receives the base address of the shared memory. Essentially what is
-returned by luw_malloc_handler().
-
-It returns an int. This should nearly always be _0_.
-
-If you wish to indicate a '500 Internal Server Error', for example if some
-internal API has failed or an OS level error occurred, then you can simply
-return _-1_, _if_ you have haven't already _sent_ any response or headers.
-
-You can still return 0 _and_ set the HTTP response status to 500 using
-[uwr_http_set_response_status](#uwr_http_set_response_status).
-
-#### luw_malloc_handler
-
-```Rust
-#[no_mangle]
-pub extern "C" fn luw_malloc_handler(size: usize) -> u32;
-```
-
-This is called by Unit when it loads the WebAssembly language module. This
-provides the shared memory used for host <--> module communications.
-
-It receives the desired size of the memory, which is currently
-NXT_WASM_MEM_SIZE + NXT_WASM_PAGE_SIZE.
-
-However calls to luw_mem_get_init_size() will return just NXT_WASM_MEM_SIZE
-(which is currently 32MiB). The extra NXT_WASM_PAGE_SIZE is to cater for
-structure sizes in the response so developers can generally assume they have
-the full NXT_WASM_MEM_SIZE for their data.
-
-A default implementation of this function is provided ready for use that
-calls malloc(3).
-
-#### luw_free_handler
-
-```Rust
-#[no_mangle]
-pub extern "C" fn luw_free_handler(addr: u32);
-```
-
-This is called by Unit when it shuts down the WebAssembly language module and
-free's the memory previously allocated by luw_malloc_handler().
-
-It receives the address of the memory to free.
-
-An implementation of this function is provided ready for use that calls
-free(3), in which case it receives the address that was previously returned
-by luw_malloc_handler().
-
-### Optional
-
-#### luw_module_init_handler
-
-```Rust
-#[no_mangle]
-pub extern "C" fn luw_module_init_handler();
-```
-
-This is called by Unit when it loads the WebAssembly language module.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-#### luw_module_end_handler
-
-```Rust
-#[no_mangle]
-pub extern "C" fn luw_module_end_handler();
-```
-
-This is called by Unit when it shuts down the WebAssembly language module.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-#### luw_request_init_handler
-
-```Rust
-#[no_mangle]
-pub extern "C" fn luw_request_init_handler();
-```
-
-This is called by Unit at the start of nxt_wasm_request_handler(), i.e at the
-start of a new request.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-#### luw_request_end_handler
-
-```Rust
-#[no_mangle]
-pub extern "C" fn luw_request_end_handler();
-```
-
-This is called by Unit at the end of nxt_wasm_request_handler(), i.e at the
-end of a request.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-#### luw_response_end_handler
-
-```Rust
-#[no_mangle]
-pub extern "C" fn luw_response_end_handler();
-```
-
-This is called by Unit after luw_http_response_end() has been called.
-
-A default dummy function is provided. If this handler is not required, there
-is no need to specify it in the Unit config.
-
-## Functions
-
-### UWR_CTX_INITIALIZER
-
-```Rust
-pub const fn UWR_CTX_INITIALIZER() -> luw_ctx_t;
-```
-
-Used to initialise a luw_ctx_t context structure. E.g
-
-```Rust
-let ctx = &mut UWR_CTX_INITIALIZER();
-```
-
-### uwr_init_ctx
-
-```Rust
-pub fn uwr_init_ctx(ctx: *mut luw_ctx_t, addr: *mut u8, offset: usize);
-```
-
-This function sets up a *luw_ctx_t* context structure, this contains stuff
-required all throughout the API.
-
-**addr** is a pointer to the shared memory as passed into luw_request_handler().
-
-**offset** is where in the shared memory it should start writing the response.
-
-#### A quick word about memory
-
-The way the Unit WebAssembly language module (the host/runtime) and the
-WebAssembly module you want to write (the guest) communicate is via a chunk
-of shared memory.
-
-This shared memory is simply the modules (guest) address space from which we
-can allocate a chunk. How this memory is laid out varies on how the module
-is built.
-
-With clang/linker flags of -Wl,--stack-first -Wl,-z,stack-size=$((8*1024*1024))
-we get a memory layout something like
-
-```
- |----------------------------------------------------------------------|
- | | | |
- | <-- Stack | Global Data | Heap --> |
- | | | |
- |----------------------------------------------------------------------|
- 0 0x800000 0x100000000
-
- WebAssembly Module Linear Memory / Process Memory Layout
-```
-
-(The above is assuming _--target=wasm32-wasi_, i.e 32bit)
-
-A chunk of memory from the heap is allocated at Unit WebAssembly language
-module startup.
-
-We currently use this same chunk of memory for both requests and responses.
-This means that depending on what you're doing, you'll want to take a copy
-of the request (and remember luw_request_handler() may be called multiple
-times for a single http request).
-
-That will be covered in more detail by the next function, uwr_set_req_buf().
-
-Now back to _offset_, it may be convenient to put the response headers at the
-beginning of this memory and then put the response after it, rather than
-doing the headers and then doing the response as separate steps, if the
-headers depends on some aspect of the response, its size for example and
-Content-Length.
-
-Example
-
-```Rust
-#[no_mangle]
-pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
- let ctx = &mut UWR_CTX_INITIALIZER();
- /* ... */
- uwr_init_ctx(ctx, addr, 4096 /* Response offset */);
-```
-
-### uwr_set_req_buf
-
-```Rust
-pub fn uwr_set_req_buf(
- ctx: *mut luw_ctx_t,
- buf: *mut *mut u8,
- flags: u32,
-) -> i32;
-```
-
-This function is used to take a copy of the request buffer (as discussed
-above).
-
-This takes a previously initialised (with uwr_init_ctx()) luw_ctx_t.
-
-**buf** is a buffer where the request data will written.
-
-**flags** can be some combination (OR'd) of the following
-
-**LUW_SRB_NONE**
-
-No specific action to be performed. It will simply copy the request data
-into the specified buffer.
-
-**LUW_SRB_APPEND**
-
-Sets up append mode whereby multiple successive requests will be appended
-to the specified buffer.
-
-The first request will have all its metadata copied. Subsequent requests
-will _only_ have the actual body data appended.
-
-**LUW_SRB_ALLOC**
-
-Allocate memory for the specified buffer.
-
-**LUW_SRB_FULL_SIZE**
-
-Used in conjunction with *LUW_SRB_ALLOC*. By default only
-*ctx->req->request_size* is allocated. If this flag is present it says to
-allocate memory for the _entire_ request that will eventually be sent.
-
-Example
-
-```Rust
-static mut CTX: luw_ctx_t = UWR_CTX_INITIALIZER();
-
-static mut REQUEST_BUF: *mut u8 = null_mut();
-*/ ... */
-#[no_mangle]
-pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
- let ctx: *mut luw_ctx_t = addr_of_mut!(CTX);
-
- if unsafe { REQUEST_BUF.is_null() } {
- uwr_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.
- */
- uwr_set_req_buf(
- ctx,
- addr_of_mut!(REQUEST_BUF),
- LUW_SRB_APPEND | LUW_SRB_ALLOC | LUW_SRB_FULL_SIZE,
- );
- } else {
- uwr_req_buf_append(ctx, addr);
- }
-
- upload_reflector(ctx);
-
- return 0;
-}
-```
-
-That example is taken from the
-[upload-reflector demo](https://github.com/nginx/unit-wasm/blob/main/examples/rust/upload-reflector/src/lib.rs)
-demo module. For a simpler example see the
-[echo-request demo](https://github.com/nginx/unit-wasm/blob/main/examples/rust/echo-request/src/lib.rs)
-
-### uwr_get_http_path
-
-```Rust
-pub fn uwr_get_http_path(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-This function returns a pointer to the HTTP request path.
-
-E.g
-
-Given a request of
-```
-http://localhost:8080/echo/?q=a
-```
-this function will return
-```
-/echo/?q=a
-```
-
-### uwr_get_http_method
-
-```Rust
-pub fn uwr_get_http_method(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-This function returns a pointer to the HTTP method.
-
-E.g
-
-```
-GET
-```
-
-### uwr_get_http_version
-
-```Rust
-pub fn uwr_get_http_version(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-This function returns a pointer to the HTTP version.
-
-E.g
-
-```
-1.1
-```
-
-### uwr_get_http_query
-
-```Rust
-pub fn uwr_get_http_query(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-This function returns a pointer to the query string (empty string for no query
-string).
-
-E.g
-
-Given a request of
-```
-http://localhost:8080/echo/?q=a
-```
-this function will return
-```
-q=a
-```
-
-### uwr_get_http_remote
-
-```Rust
-pub fn uwr_get_http_remote(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-This function returns a pointer to the remote/client/peer address.
-
-E.g
-
-```
-2001:db8::f00
-```
-
-### uwr_get_http_local_addr
-
-```Rust
-pub fn uwr_get_http_local_addr(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-This function returns a pointer to the local/server address.
-
-E.g
-
-```
-2001:db8::1
-```
-
-### uwr_get_http_local_port
-
-```Rust
-pub fn uwr_get_http_local_port(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-This function returns a pointer to the local/server port.
-
-E.g
-
-```
-443
-```
-
-### uwr_get_http_server_name
-
-```Rust
-pub fn uwr_get_http_server_name(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-This function returns a pointer to the local/server name.
-
-E.g
-
-```
-www.example.com
-```
-
-### uwr_get_http_content
-
-```Rust
-pub fn uwr_get_http_content(ctx: *const luw_ctx_t) -> *const u8;
-```
-
-This function returns a pointer to the start of the request body.
-
-### uwr_get_http_content_str
-
-```Rsut
-pub fn uwr_get_http_content_str(ctx: *const luw_ctx_t) -> &'static str;
-```
-
-Same as above but returns a Rust str.
-
-_Version: 0.2.0_
-
-### uwr_get_http_content_len
-
-```Rust
-pub fn uwr_get_http_content_len(ctx: *const luw_ctx_t) -> u64;
-```
-
-This function returns the size of the overall content. I.e Content-Length.
-
-Prior to version 0.3.0 it returned a usize
-
-### uwr_get_http_content_sent
-
-```Rust
-pub fn uwr_get_http_content_sent(ctx: *const luw_ctx_t) -> usize;
-```
-
-This function returns the length of the content that was sent to the
-WebAssembly module in _this_ request. Remember, a single HTTP request may be
-split over several calls to luw_request_handler().
-
-### uwr_get_http_total_content_sent
-
-```Rust
-pub fn uwr_get_http_total_content_sent(ctx: *const luw_ctx_t) -> u64;
-```
-
-This function returns the total length of the content that was sent to the
-WebAssembly module so far. Remember, a single HTTP request may be split over
-several calls to luw_request_handler().
-
-_Version: 0.2.0_ Prior to 0.3.0 it returned a usize
-
-### uwr_http_is_tls
-
-```Rust
-pub fn uwr_http_is_tls(ctx: *const luw_ctx_t) -> bool;
-```
-
-This function returns _true_ if the connection to Unit was made over TLS.
-
-### uwr_http_hdr_iter
-
-```Rust
-pub fn uwr_http_hdr_iter(
- ctx: *mut luw_ctx_t,
- luw_http_hdr_iter_func: ::std::option::Option<
- unsafe extern "C" fn(
- ctx: *mut luw_ctx_t,
- name: *const c_char,
- value: *const c_char,
- data: *mut c_void,
- ) -> bool,
- >,
- user_data: *mut c_void,
-);
-```
-
-This function allows to iterate over the HTTP headers. For each header it
-will call the given luw_http_hdr_iter_func() function whose prototype is
-
-```Rust
-pub extern "C" fn hdr_iter_func(
- ctx: *mut luw_ctx_t,
- name: *const c_char,
- value: *const c_char,
- data: *mut c_void,
-) -> bool;
-```
-
-You may call this function whatever you like. For each header it will be
-passed the *luw_ctx_t*, the header name, its value and a user specified
-pointer if any, can be NULL.
-
-Returning _true_ from this function will cause the iteration process to
-continue, returning _false_ will terminate it.
-
-Example
-
-```Rust
-pub extern "C" fn hdr_iter_func(
- ctx: *mut luw_ctx_t,
- name: *const c_char,
- value: *const c_char,
- _data: *mut c_void,
-) -> bool {
- /* Do something with name & value, ignoring data */
-
- return true;
-}
-
-/* ... *
-
-uwr_http_hdr_iter(ctx, Some(hdr_iter_func), null_mut());
-```
-
-### uwr_http_hdr_get_value
-
-```Rust
-pub fn uwr_http_hdr_get_value(ctx: *const luw_ctx_t, hdr: &str) -> &'static str;
-```
-
-Given a HTTP header _hdr_ this function will look it up in the request and
-return its value if found, otherwise _NULL_.
-
-The lookup is done case insensitively.
-
-### uwr_get_response_data_size
-
-```Rust
-pub fn uwr_get_response_data_size(ctx: *const luw_ctx_t) -> usize;
-```
-
-This function returns the size of the response data written to memory.
-
-### uwr_mem_write_buf
-
-```Rust
-pub fn uwr_mem_write_buf(
- ctx: *mut luw_ctx_t,
- src: *const u8,
- size: usize,
-) -> usize;
-```
-
-This function just appends _size_ bytes from _src_ to the response.
-
-It returns the new size of the response.
-
-### uwr_req_buf_append
-
-```Rust
-pub fn uwr_req_buf_append(ctx: *mut luw_ctx_t, src: *const u8);
-```
-
-This function appends the request data contained in _src_ to the previously
-setup *request_buffer* with uwr_set_req_buf().
-
-This function would be used after an initial request to append the data from
-subsequent requests to the request_buffer.
-
-Example
-
-```Rust
-#[no_mangle]
-pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
- let ctx: *mut luw_ctx_t = addr_of_mut!(CTX);
-
- if unsafe { REQUEST_BUF.is_null() } {
- uwr_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.
- */
- uwr_set_req_buf(
- ctx,
- addr_of_mut!(REQUEST_BUF),
- LUW_SRB_APPEND | LUW_SRB_ALLOC | LUW_SRB_FULL_SIZE,
- );
- } else {
- uwr_req_buf_append(ctx, addr);
- }
-
- upload_reflector(ctx);
-
- return 0;
-}
-```
-
-### uwr_req_buf_copy
-
-```Rust
-pub fn uwr_req_buf_copy(ctx: *mut luw_ctx_t, src: *const u8);
-```
-
-This function is analogous to [uwr_req_buf_append](#uwr_req_buf_append) but
-rather than appending the request data contained in _src_ to the previously
-setup *request_buffer* with uwr_set_req_buf(), it simply overwrites what's
-currently there.
-
-This function could be used to handle large requests/uploads that you want to
-save out to disk or some such and can't buffer it all in memory.
-
-### uwr_mem_splice_file
-
-```Rust
-pub fn uwr_mem_splice_file(src: *const u8, f: &mut File) -> isize;
-```
-This function write(2)'s the request data directly from the shared memory
-(_src_) to the file represented by the given _File_ object (_f_).
-
-This can be used as an alternative to [uwr_req_buf_copy](#uwr_req_buf_copy)
-and avoids an extra copying of the request data.
-
-Example
-
-```Rust
-pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
- let ctx: *mut luw_ctx_t = addr_of_mut!(CTX);
- let mut f;
- let bytes_wrote: isize;
- let mut total = unsafe { TOTAL_BYTES_WROTE };
-
- if total == 0 {
- uwr_init_ctx(ctx, addr, 0);
- uwr_set_req_buf(
- ctx,
- addr_of_mut!(REQUEST_BUF),
- LUW_SRB_NONE
- );
-
- f = File::create("/var/tmp/large-file.dat").unwrap();
- } else {
- f = File::options()
- .append(true)
- .open("/var/tmp/large-file.dat")
- .unwrap();
- }
-
- bytes_wrote = uwr_mem_splice_file(addr, &mut f);
- if bytes_wrote == -1 {
- return -1;
- }
-
- total += bytes_wrote as u64;
- if total == uwr_get_http_content_len(ctx) {
- total = 0;
-
- uwr_http_response_end();
- }
-
- unsafe { TOTAL_BYTES_WROTE = total };
-
- return 0;
-}
-```
-
-### uwr_mem_fill_buf_from_req
-
-```Rust
-pub fn uwr_req_buf_append(ctx: *mut luw_ctx_t, src: *const u8);
-```
-
-This is a convenience function to fill the response buffer with data from
-the request buffer.
-
-_from_ is basically the offset in the request_buffer where to start copying
-data from.
-
-Example
-
-```Rust
-/* ... */
-write_bytes = uwr_mem_fill_buf_from_req(ctx, TOTAL_RESPONSE_SENT);
-TOTAL_RESPONSE_SENT += write_bytes;
-/* ... */
-```
-
-This is taken from the
-[upload-reflector demo](https://github.com/nginx/unit-wasm/blob/main/examples/c/upload-reflector/src/lib.rs)
-demo module.
-
-In this case we build up a request_buffer on each call of
-luw_request_handler(), so TOTAL_RESPONSE_SENT grows each time by how much
-data was sent in _that_ request.
-
-Here are are sending data back to the client after each time we receive it to
-demonstrate the interleaving of requests and responses from the WebAssembly
-module during a single http request.
-
-This function returns the number of bytes written to the response buffer.
-
-### uwr_mem_reset
-
-```Rust
-pub fn uwr_luw_mem_reset(ctx: *mut luw_ctx_t);
-```
-
-This function resets the response buffer size and the number of response
-headers back to 0.
-
-### uwr_http_set_response_status
-
-```Rust
-pub fn uwr_http_set_response_status(status: luw_http_status_t);
-```
-
-This function is used to set the HTTP response status. It takes one of the
-[luw_http_status_t](#luw_http_status_t) enum values.
-
-It should be called before any calls to *uwr_http_send_response()* or
-*uwr_http_send_headers()*.
-
-If you don't call this function the response status defaults to '200 OK'.
-
-If you wish to error out with a '500 Internal Server Error', you don't need to
-call this function. Simply returning _-1_ from the request_handler function
-will indicate this error.
-
-E.g
-
-Send a '403 Forbidden'
-
-```Rust
-/* ... */
-uwr_http_set_response_status(LUW_HTTP_FORBIDDEN);
-uwr_http_send_response(ctx); /* Doesn't require any body */
-uwr_http_response_end();
-/* ... */
-return 0;
-```
-
-Send a '307 Temporary Re-direct'
-
-```Rust
-/* ... */
-uwr_http_set_response_status(LUW_HTTP_TEMPORARY_REDIRECT);
-
-uwr_http_init_headers(ctx, 1, 0);
-uwr_http_add_header(ctx, "Location", "https://example.com/");
-uwr_http_send_headers(ctx);
-uwr_http_response_end();
-/* ... */
-return 0;
-```
-
-_Version: 0.3.0_
-
-### uwr_http_send_response
-
-```Rust
-pub fn uwr_http_send_response(ctx: *const luw_ctx_t);
-```
-
-This function calls into Unit to send the response buffer back.
-
-### uwr_http_init_headers
-
-```Rust
-pub fn uwr_http_init_headers(ctx: *mut luw_ctx_t, nr: usize, offset: usize);
-```
-
-This function is used in the preparation of sending back response headers.
-
-_nr_ is the number of headers we are sending.
-
-_offset_ is the offset into the response buffer where we are placing these
-headers. This will usually be 0.
-
-Example
-
-```Rust
-uwr_http_init_headers(ctx, 2, 0);
-```
-
-### uwr_http_add_header
-
-```Rust
-pub fn uwr_http_add_header(
- ctx: *mut luw_ctx_t,
- name: &str,
- value: &str,
-);
-```
-
-This function is used to add a header to the response.
-
-_name_ is the name of the header.
-
-_value_ is the value of the header.
-
-Example
-
-```Rust
-uwr_http_add_header(&ctx, "Content-Type", "text/plain");
-uwr_http_add_header(
- ctx,
- "Content-Length",
- &format!("{}", uwr_get_response_data_size(ctx)),
-);
-```
-
-### uwr_http_add_header_content_type
-
-```Rust
-pub fn uwr_http_add_header_content_type(ctx: *mut luw_ctx_t, ctype: &str);
-```
-
-A convenience function for setting the 'Content-Type' response header.
-E.g the above example that adds the _Content-Type_ header could be
-written as
-
-```Rust
-uwr_http_add_header_content_type(ctx, "text/plain");
-```
-
-_Version: 0.2.0_
-
-### uwr_http_add_header_content_len
-
-```Rust
-pub fn uwr_http_add_header_content_len(ctx: *mut luw_ctx_t);
-```
-
-A convenience function for setting the 'Content-Length' response header.
-E.g the above example that adds the _Content-Length_ header could be
-written as
-
-```Rust
-uwr_http_add_header_content_len(ctx);
-```
-
-This function uses [uwr_get_response_data_size](#uwr_get_response_data_size)
-internally to get the size of the response data.
-
-_Version: 0.2.0_
-
-### uwr_http_send_headers
-
-```Rust
-pub fn uwr_http_send_headers(ctx: *const luw_ctx_t);
-```
-
-This function calls into Unit and triggers the sending of the response
-headers.
-
-### uwr_http_response_end
-
-```Rust
-pub fn uwr_http_response_end();
-```
-
-This function calls into Unit and tells it this is the end of the response
-which will trigger Unit to send it to the client.
-
-### uwr_mem_get_init_size
-
-```Rust
-pub fn uwr_mem_get_init_size() -> u32;
-```
-
-This function calls into Unit to get the size of the shared memory. This is
-the amount of memory you should assume you have for creating responses.
-Remember you can create multiple responses before calling
-luw_http_response_end().
-
-## Misc. Functions
-
-The following functions are convenience wrappers for the Rust bindings and
-should **not** be used directly.
-
-### uwr_malloc
-
-```Rust
-pub fn uwr_malloc(size: u32) -> *mut u8;
-```
-
-Essentially a straight wrapper for malloc(3).
-
-### uwr_free
-
-```Rust
-pub fn uwr_free(ptr: *mut u8);
-```
-
-Essentially a straight wrapper for free(3).
diff --git a/API-Rust.rst b/API-Rust.rst
new file mode 100644
index 0000000..6bac9a3
--- /dev/null
+++ b/API-Rust.rst
@@ -0,0 +1,1238 @@
+‘Rusty’ Rust API
+================
+
+Rusty is a more native Rust wrapper around the auto-generated bindings
+to
+`libunit-wasm <https://github.com/nginx/unit-wasm/blob/main/API-C.md>`__.
+
+.. code:: rust
+
+ use unit_wasm::rusty::*;
+
+If using
+
+.. code:: rust
+
+ uwr_http_hdr_iter();
+
+.. code:: rust
+
+ use std::ffi::CStr;
+ use std::os::raw::c_char;
+ use std::os::raw::c_void;
+
+Naming
+------
+
+You will see references to functions etc starting with *luw\_* or
+*LUW\_* and \*uwr\_“.
+
+**luw/LUW** (libunit-wasm) come from the underlying C library and in the
+Rust case are the auto-generated bindings with a few manual additions.
+
+**uwr** (Unit Wasm Rust aka ‘*rusty*’) is a more Rust native wrapper
+ontop of the bindings.
+
+In *rusty* the luw/LUW API is generally the low level stuff like the
+library version macros and the various function handlers where they can
+be used as is and there isn’t a real need to create wrappers
+specifically for them.
+
+1. `‘Rusty’ Rust API <#rusty-rust-api>`__
+
+- `Naming <#naming>`__
+
+2. `Macros <#macros>`__
+
+- `Version <#version>`__
+- `String Conversion <#string-conversion>`__
+- `uwr_write_str! <#uwr_write_str>`__
+
+3. `Enums <#enums>`__ `luw_http_status_t <#luw_http_status_t>`__
+4. `Function Handlers <#function-handlers>`__
+
+- `Optional <#optional>`__
+
+ - `luw_module_init_handler <#luw_module_init_handler>`__
+ - `luw_module_end_handler <#luw_module_end_handler>`__
+ - `luw_request_init_handler <#luw_request_init_handler>`__
+ - `luw_request_end_handler <#luw_request_end_handler>`__
+ - `luw_response_end_handler <#luw_response_end_handler>`__
+
+- `Required <#required>`__
+
+ - `luw_request_handler <#luw_request_handler>`__
+ - `luw_free_handler <#luw_free_handler>`__
+ - `luw_malloc_handler <#luw_malloc_handler>`__
+
+4. `Functions <#functions>`__
+
+- `UWR_CTX_INITIALIZER <#uwr_ctx_initializer>`__
+- `uwr_init_ctx <#uwr_init_ctx>`__
+- `uwr_set_req_buf <#uwr_set_req_buf>`__
+- `uwr_get_http_path <#uwr_get_http_path>`__
+- `uwr_get_http_method <#uwr_get_http_method>`__
+- `uwr_get_http_version <#uwr_get_http_version>`__
+- `uwr_get_http_query <#uwr_get_http_query>`__
+- `uwr_get_http_remote <#uwr_get_http_remote>`__
+- `uwr_get_http_local_addr <#uwr_get_http_local_addr>`__
+- `uwr_get_http_local_port <#uwr_get_http_local_port>`__
+- `uwr_get_http_server_name <#uwr_get_http_server_name>`__
+- `uwr_get_http_content <#uwr_get_http_content>`__
+- `uwr_get_http_content_str <#uwr_get_http_content_str>`__
+- `uwr_get_http_content_len <#uwr_get_http_content_len>`__
+- `uwr_get_http_content_sent <#uwr_get_http_content_sent>`__
+- `uwr_get_http_total_content_sent <#uwr_get_http_total_content_sent>`__
+- `uwr_http_is_tls <#uwr_http_is_tls>`__
+- `uwr_http_hdr_iter <#uwr_http_hdr_iter>`__
+- `uwr_http_hdr_get_value <#uwr_http_hdr_get_value>`__
+- `uwr_get_response_data_size <#uwr_get_response_data_size>`__
+- `uwr_mem_write_buf <#uwr_mem_write_buf>`__
+- `uwr_req_buf_append <#uwr_req_buf_append>`__
+- `uwr_req_buf_copy <#uwr_req_buf_copy>`__
+- `uwr_mem_splice_file <#uwr_mem_splice_file>`__
+- `uwr_mem_fill_buf_from_req <#uwr_mem_fill_buf_from_req>`__
+- `uwr_mem_reset <#uwr_mem_reset>`__
+- `uwr_http_set_response_status <#uwr_http_set_response_status>`__
+- `uwr_http_send_response <#uwr_http_send_response>`__
+- `uwr_http_init_headers <#uwr_http_init_headers>`__
+- `uwr_http_add_header <#uwr_http_add_header>`__
+- `uwr_http_add_header_content_type <#uwr_http_add_header_content_type>`__
+- `uwr_http_add_header_content_len <#uwr_http_add_header_content_len>`__
+- `uwr_http_send_headers <#uwr_http_send_headers>`__
+- `uwr_http_response_end <#uwr_http_response_end>`__
+- `uwr_mem_get_init_size <#uwr_mem_get_init_size>`__
+
+5. `Misc. Functions <#misc-functions>`__
+
+- `uwr_malloc <#uwr_malloc>`__
+- `uwr_free <#uwr_free>`__
+
+Macros
+------
+
+Version
+~~~~~~~
+
+For the underlying libunit-wasm version.
+
+.. code:: rust
+
+ pub const LUW_VERSION_MAJOR: i32;
+ pub const LUW_VERSION_MINOR: i32;
+ pub const LUW_VERSION_PATCH: i32;
+
+.. code:: rust
+
+ /* Version number in hex 0xMMmmpp00 */
+ pub const LUW_VERSION_NUMBER: i32 =
+ (LUW_VERSION_MAJOR << 24) | \
+ (LUW_VERSION_MINOR << 16) | \
+ (LUW_VERSION_PATCH << 8);
+
+String Conversion
+~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ C2S!(string);
+
+Converts a C string into a Rust String
+
+Main use is internally and in the *uwr_http_hdr_iter()* callback
+function, e.g
+
+.. code:: rust
+
+ pub extern "C" fn hdr_iter_func(
+ ctx: *mut luw_ctx_t,
+ name: *const c_char,
+ value: *const c_char,
+ _data: *mut c_void,
+ ) -> bool {
+ uwr_write_str!(ctx, "{} = {}\n", C2S!(name), C2S!(value));
+
+ return true;
+ }
+
+Example taken from the
+`echo-request <https://github.com/nginx/unit-wasm/blob/main/examples/rust/echo-request/src/lib.rs>`__
+Wasm demo module
+
+.. code:: rust
+
+ S2C!(formatted string);
+
+Converts a Rust String, with optional formatting, to a C string.
+
+Used internally.
+
+uwr_write_str!
+~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ uwr_write_str!*ctx, fmt, ...);
+
+This is essentially a wrapper around
+`luw_mem_writep_data() <https://github.com/nginx/unit-wasm/blob/main/API-C.md#luw_mem_writep_data>`__
+
+It is the main way to write responses back to the client.
+
+It takes the luw_ctx_t context pointer, a string that will be run
+through the
+`format!() <https://doc.rust-lang.org/std/macro.format.html>`__ macro
+and any optional arguments.
+
+Enums
+-----
+
+luw_http_status_t
+~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub enum luw_http_status_t {
+ LUW_HTTP_CONTINUE = 100,
+ LUW_HTTP_SWITCHING_PROTOCOLS = 101,
+
+ LUW_HTTP_OK = 200,
+ LUW_HTTP_CREATED = 201,
+ LUW_HTTP_ACCEPTED = 202,
+ LUW_HTTP_NO_CONTENT = 204,
+
+ LUW_HTTP_MULTIPLE_CHOICES = 300,
+ LUW_HTTP_MOVED_PERMANENTLY = 301,
+ LUW_HTTP_FOUND = 302,
+ LUW_HTTP_SEE_OTHER = 303,
+ LUW_HTTP_NOT_MODIFIED = 304,
+ LUW_HTTP_TEMPORARY_REDIRECT = 307,
+ LUW_HTTP_PERMANENT_REDIRECT = 308,
+
+ LUW_HTTP_BAD_REQUEST = 400,
+ LUW_HTTP_UNAUTHORIZED = 401,
+ LUW_HTTP_FORBIDDEN = 403,
+ LUW_HTTP_NOT_FOUND = 404,
+ LUW_HTTP_METHOD_NOT_ALLOWED = 405,
+ LUW_HTTP_NOT_ACCEPTABLE = 406,
+ LUW_HTTP_REQUEST_TIMEOUT = 408,
+ LUW_HTTP_CONFLICT = 409,
+ LUW_HTTP_GONE = 410,
+ LUW_HTTP_LENGTH_REQUIRED = 411,
+ LUW_HTTP_PAYLOAD_TOO_LARGE = 413,
+ LUW_HTTP_URI_TOO_LONG = 414,
+ LUW_HTTP_UNSUPPORTED_MEDIA_TYPE = 415,
+ LUW_HTTP_UPGRADE_REQUIRED = 426,
+ LUW_HTTP_TOO_MANY_REQUESTS = 429,
+ LUW_HTTP_REQUEST_HEADER_FIELDS_TOO_LARGE = 431,
+
+ /* Proposed by RFC 7725 */
+ LUW_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS = 451,
+
+ LUW_HTTP_INTERNAL_SERVER_ERROR = 500,
+ LUW_HTTP_NOT_IMPLEMENTED = 501,
+ LUW_HTTP_BAD_GATEWAY = 502,
+ LUW_HTTP_SERVICE_UNAVAILABLE = 503,
+ LUW_HTTP_GATEWAY_TIMEOUT = 504,
+ }
+
+Function Handlers
+-----------------
+
+These functions are exported from the WebAssembly module and are called
+from the WebAssembly runtime (the Unit WebAssembly language module in
+this case).
+
+There are two types of handlers; required & optional.
+
+luw_request_handler(), luw_malloc_handler() & luw_free_handler() are
+required with the rest being optional.
+
+libunit-wasm includes exports for these handlers and some default
+implementations.
+
+These functions are defined as *weak* symbols and so if a developer
+writes their own function of the same name, that will take precedence.
+
+However, developers are under no obligation to use these and can create
+their own with any (valid) names they like.
+
+Whatever names developers choose, they are specified in the Unit config.
+
+Required
+~~~~~~~~
+
+luw_request_handler
+^^^^^^^^^^^^^^^^^^^
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn luw_request_handler(addr: *mut u8) -> i32;
+
+This is called by Unit during a request. It may be called multiple times
+for a single HTTP request if there is more request data than the
+available memory for host <–> module communications.
+
+You will need to provide your own implementation of this function.
+
+It receives the base address of the shared memory. Essentially what is
+returned by luw_malloc_handler().
+
+It returns an int. This should nearly always be *0*.
+
+If you wish to indicate a ‘500 Internal Server Error’, for example if
+some internal API has failed or an OS level error occurred, then you can
+simply return *-1*, *if* you have haven’t already *sent* any response or
+headers.
+
+You can still return 0 *and* set the HTTP response status to 500 using
+`uwr_http_set_response_status <#uwr_http_set_response_status>`__.
+
+luw_malloc_handler
+^^^^^^^^^^^^^^^^^^
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn luw_malloc_handler(size: usize) -> u32;
+
+This is called by Unit when it loads the WebAssembly language module.
+This provides the shared memory used for host <–> module communications.
+
+It receives the desired size of the memory, which is currently
+NXT_WASM_MEM_SIZE + NXT_WASM_PAGE_SIZE.
+
+However calls to luw_mem_get_init_size() will return just
+NXT_WASM_MEM_SIZE (which is currently 32MiB). The extra
+NXT_WASM_PAGE_SIZE is to cater for structure sizes in the response so
+developers can generally assume they have the full NXT_WASM_MEM_SIZE for
+their data.
+
+A default implementation of this function is provided ready for use that
+calls malloc(3).
+
+luw_free_handler
+^^^^^^^^^^^^^^^^
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn luw_free_handler(addr: u32);
+
+This is called by Unit when it shuts down the WebAssembly language
+module and free’s the memory previously allocated by
+luw_malloc_handler().
+
+It receives the address of the memory to free.
+
+An implementation of this function is provided ready for use that calls
+free(3), in which case it receives the address that was previously
+returned by luw_malloc_handler().
+
+Optional
+~~~~~~~~
+
+luw_module_init_handler
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn luw_module_init_handler();
+
+This is called by Unit when it loads the WebAssembly language module.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+luw_module_end_handler
+^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn luw_module_end_handler();
+
+This is called by Unit when it shuts down the WebAssembly language
+module.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+luw_request_init_handler
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn luw_request_init_handler();
+
+This is called by Unit at the start of nxt_wasm_request_handler(), i.e
+at the start of a new request.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+luw_request_end_handler
+^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn luw_request_end_handler();
+
+This is called by Unit at the end of nxt_wasm_request_handler(), i.e at
+the end of a request.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+luw_response_end_handler
+^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn luw_response_end_handler();
+
+This is called by Unit after luw_http_response_end() has been called.
+
+A default dummy function is provided. If this handler is not required,
+there is no need to specify it in the Unit config.
+
+Functions
+---------
+
+UWR_CTX_INITIALIZER
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub const fn UWR_CTX_INITIALIZER() -> luw_ctx_t;
+
+Used to initialise a luw_ctx_t context structure. E.g
+
+.. code:: rust
+
+ let ctx = &mut UWR_CTX_INITIALIZER();
+
+uwr_init_ctx
+~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_init_ctx(ctx: *mut luw_ctx_t, addr: *mut u8, offset: usize);
+
+This function sets up a *luw_ctx_t* context structure, this contains
+stuff required all throughout the API.
+
+**addr** is a pointer to the shared memory as passed into
+luw_request_handler().
+
+**offset** is where in the shared memory it should start writing the
+response.
+
+A quick word about memory
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The way the Unit WebAssembly language module (the host/runtime) and the
+WebAssembly module you want to write (the guest) communicate is via a
+chunk of shared memory.
+
+This shared memory is simply the modules (guest) address space from
+which we can allocate a chunk. How this memory is laid out varies on how
+the module is built.
+
+With clang/linker flags of -Wl,–stack-first
+-Wl,-z,stack-size=$((8\ *1024*\ 1024)) we get a memory layout something
+like
+
+::
+
+ |----------------------------------------------------------------------|
+ | | | |
+ | <-- Stack | Global Data | Heap --> |
+ | | | |
+ |----------------------------------------------------------------------|
+ 0 0x800000 0x100000000
+
+ WebAssembly Module Linear Memory / Process Memory Layout
+
+(The above is assuming *–target=wasm32-wasi*, i.e 32bit)
+
+A chunk of memory from the heap is allocated at Unit WebAssembly
+language module startup.
+
+We currently use this same chunk of memory for both requests and
+responses. This means that depending on what you’re doing, you’ll want
+to take a copy of the request (and remember luw_request_handler() may be
+called multiple times for a single http request).
+
+That will be covered in more detail by the next function,
+uwr_set_req_buf().
+
+Now back to *offset*, it may be convenient to put the response headers
+at the beginning of this memory and then put the response after it,
+rather than doing the headers and then doing the response as separate
+steps, if the headers depends on some aspect of the response, its size
+for example and Content-Length.
+
+Example
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
+ let ctx = &mut UWR_CTX_INITIALIZER();
+ /* ... */
+ uwr_init_ctx(ctx, addr, 4096 /* Response offset */);
+
+uwr_set_req_buf
+~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_set_req_buf(
+ ctx: *mut luw_ctx_t,
+ buf: *mut *mut u8,
+ flags: u32,
+ ) -> i32;
+
+This function is used to take a copy of the request buffer (as discussed
+above).
+
+This takes a previously initialised (with uwr_init_ctx()) luw_ctx_t.
+
+**buf** is a buffer where the request data will written.
+
+**flags** can be some combination (OR’d) of the following
+
+**LUW_SRB_NONE**
+
+No specific action to be performed. It will simply copy the request data
+into the specified buffer.
+
+**LUW_SRB_APPEND**
+
+Sets up append mode whereby multiple successive requests will be
+appended to the specified buffer.
+
+The first request will have all its metadata copied. Subsequent requests
+will *only* have the actual body data appended.
+
+**LUW_SRB_ALLOC**
+
+Allocate memory for the specified buffer.
+
+**LUW_SRB_FULL_SIZE**
+
+Used in conjunction with *LUW_SRB_ALLOC*. By default only
+*ctx->req->request_size* is allocated. If this flag is present it says
+to allocate memory for the *entire* request that will eventually be
+sent.
+
+Example
+
+.. code:: rust
+
+ static mut CTX: luw_ctx_t = UWR_CTX_INITIALIZER();
+
+ static mut REQUEST_BUF: *mut u8 = null_mut();
+ */ ... */
+ #[no_mangle]
+ pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
+ let ctx: *mut luw_ctx_t = addr_of_mut!(CTX);
+
+ if unsafe { REQUEST_BUF.is_null() } {
+ uwr_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.
+ */
+ uwr_set_req_buf(
+ ctx,
+ addr_of_mut!(REQUEST_BUF),
+ LUW_SRB_APPEND | LUW_SRB_ALLOC | LUW_SRB_FULL_SIZE,
+ );
+ } else {
+ uwr_req_buf_append(ctx, addr);
+ }
+
+ upload_reflector(ctx);
+
+ return 0;
+ }
+
+That example is taken from the `upload-reflector
+demo <https://github.com/nginx/unit-wasm/blob/main/examples/rust/upload-reflector/src/lib.rs>`__
+demo module. For a simpler example see the `echo-request
+demo <https://github.com/nginx/unit-wasm/blob/main/examples/rust/echo-request/src/lib.rs>`__
+
+uwr_get_http_path
+~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_path(ctx: *const luw_ctx_t) -> &'static str;
+
+This function returns a pointer to the HTTP request path.
+
+E.g
+
+Given a request of
+
+::
+
+ http://localhost:8080/echo/?q=a
+
+this function will return
+
+::
+
+ /echo/?q=a
+
+uwr_get_http_method
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_method(ctx: *const luw_ctx_t) -> &'static str;
+
+This function returns a pointer to the HTTP method.
+
+E.g
+
+::
+
+ GET
+
+uwr_get_http_version
+~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_version(ctx: *const luw_ctx_t) -> &'static str;
+
+This function returns a pointer to the HTTP version.
+
+E.g
+
+::
+
+ 1.1
+
+uwr_get_http_query
+~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_query(ctx: *const luw_ctx_t) -> &'static str;
+
+This function returns a pointer to the query string (empty string for no
+query string).
+
+E.g
+
+Given a request of
+
+::
+
+ http://localhost:8080/echo/?q=a
+
+this function will return
+
+::
+
+ q=a
+
+uwr_get_http_remote
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_remote(ctx: *const luw_ctx_t) -> &'static str;
+
+This function returns a pointer to the remote/client/peer address.
+
+E.g
+
+::
+
+ 2001:db8::f00
+
+uwr_get_http_local_addr
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_local_addr(ctx: *const luw_ctx_t) -> &'static str;
+
+This function returns a pointer to the local/server address.
+
+E.g
+
+::
+
+ 2001:db8::1
+
+uwr_get_http_local_port
+~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_local_port(ctx: *const luw_ctx_t) -> &'static str;
+
+This function returns a pointer to the local/server port.
+
+E.g
+
+::
+
+ 443
+
+uwr_get_http_server_name
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_server_name(ctx: *const luw_ctx_t) -> &'static str;
+
+This function returns a pointer to the local/server name.
+
+E.g
+
+::
+
+ www.example.com
+
+uwr_get_http_content
+~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_content(ctx: *const luw_ctx_t) -> *const u8;
+
+This function returns a pointer to the start of the request body.
+
+uwr_get_http_content_str
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rsut
+
+ pub fn uwr_get_http_content_str(ctx: *const luw_ctx_t) -> &'static str;
+
+Same as above but returns a Rust str.
+
+*Version: 0.2.0*
+
+uwr_get_http_content_len
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_content_len(ctx: *const luw_ctx_t) -> u64;
+
+This function returns the size of the overall content. I.e
+Content-Length.
+
+Prior to version 0.3.0 it returned a usize
+
+uwr_get_http_content_sent
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_content_sent(ctx: *const luw_ctx_t) -> usize;
+
+This function returns the length of the content that was sent to the
+WebAssembly module in *this* request. Remember, a single HTTP request
+may be split over several calls to luw_request_handler().
+
+uwr_get_http_total_content_sent
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_http_total_content_sent(ctx: *const luw_ctx_t) -> u64;
+
+This function returns the total length of the content that was sent to
+the WebAssembly module so far. Remember, a single HTTP request may be
+split over several calls to luw_request_handler().
+
+*Version: 0.2.0* Prior to 0.3.0 it returned a usize
+
+uwr_http_is_tls
+~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_is_tls(ctx: *const luw_ctx_t) -> bool;
+
+This function returns *true* if the connection to Unit was made over
+TLS.
+
+uwr_http_hdr_iter
+~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_hdr_iter(
+ ctx: *mut luw_ctx_t,
+ luw_http_hdr_iter_func: ::std::option::Option<
+ unsafe extern "C" fn(
+ ctx: *mut luw_ctx_t,
+ name: *const c_char,
+ value: *const c_char,
+ data: *mut c_void,
+ ) -> bool,
+ >,
+ user_data: *mut c_void,
+ );
+
+This function allows to iterate over the HTTP headers. For each header
+it will call the given luw_http_hdr_iter_func() function whose prototype
+is
+
+.. code:: rust
+
+ pub extern "C" fn hdr_iter_func(
+ ctx: *mut luw_ctx_t,
+ name: *const c_char,
+ value: *const c_char,
+ data: *mut c_void,
+ ) -> bool;
+
+You may call this function whatever you like. For each header it will be
+passed the *luw_ctx_t*, the header name, its value and a user specified
+pointer if any, can be NULL.
+
+Returning *true* from this function will cause the iteration process to
+continue, returning *false* will terminate it.
+
+Example
+
+.. code:: rust
+
+ pub extern "C" fn hdr_iter_func(
+ ctx: *mut luw_ctx_t,
+ name: *const c_char,
+ value: *const c_char,
+ _data: *mut c_void,
+ ) -> bool {
+ /* Do something with name & value, ignoring data */
+
+ return true;
+ }
+
+ /* ... *
+
+ uwr_http_hdr_iter(ctx, Some(hdr_iter_func), null_mut());
+
+uwr_http_hdr_get_value
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_hdr_get_value(ctx: *const luw_ctx_t, hdr: &str) -> &'static str;
+
+Given a HTTP header *hdr* this function will look it up in the request
+and return its value if found, otherwise *NULL*.
+
+The lookup is done case insensitively.
+
+uwr_get_response_data_size
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_get_response_data_size(ctx: *const luw_ctx_t) -> usize;
+
+This function returns the size of the response data written to memory.
+
+uwr_mem_write_buf
+~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_mem_write_buf(
+ ctx: *mut luw_ctx_t,
+ src: *const u8,
+ size: usize,
+ ) -> usize;
+
+This function just appends *size* bytes from *src* to the response.
+
+It returns the new size of the response.
+
+uwr_req_buf_append
+~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_req_buf_append(ctx: *mut luw_ctx_t, src: *const u8);
+
+This function appends the request data contained in *src* to the
+previously setup *request_buffer* with uwr_set_req_buf().
+
+This function would be used after an initial request to append the data
+from subsequent requests to the request_buffer.
+
+Example
+
+.. code:: rust
+
+ #[no_mangle]
+ pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
+ let ctx: *mut luw_ctx_t = addr_of_mut!(CTX);
+
+ if unsafe { REQUEST_BUF.is_null() } {
+ uwr_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.
+ */
+ uwr_set_req_buf(
+ ctx,
+ addr_of_mut!(REQUEST_BUF),
+ LUW_SRB_APPEND | LUW_SRB_ALLOC | LUW_SRB_FULL_SIZE,
+ );
+ } else {
+ uwr_req_buf_append(ctx, addr);
+ }
+
+ upload_reflector(ctx);
+
+ return 0;
+ }
+
+uwr_req_buf_copy
+~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_req_buf_copy(ctx: *mut luw_ctx_t, src: *const u8);
+
+This function is analogous to
+`uwr_req_buf_append <#uwr_req_buf_append>`__ but rather than appending
+the request data contained in *src* to the previously setup
+*request_buffer* with uwr_set_req_buf(), it simply overwrites what’s
+currently there.
+
+This function could be used to handle large requests/uploads that you
+want to save out to disk or some such and can’t buffer it all in memory.
+
+uwr_mem_splice_file
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_mem_splice_file(src: *const u8, f: &mut File) -> isize;
+
+This function write(2)’s the request data directly from the shared
+memory (*src*) to the file represented by the given *File* object (*f*).
+
+This can be used as an alternative to
+`uwr_req_buf_copy <#uwr_req_buf_copy>`__ and avoids an extra copying of
+the request data.
+
+Example
+
+.. code:: rust
+
+ pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
+ let ctx: *mut luw_ctx_t = addr_of_mut!(CTX);
+ let mut f;
+ let bytes_wrote: isize;
+ let mut total = unsafe { TOTAL_BYTES_WROTE };
+
+ if total == 0 {
+ uwr_init_ctx(ctx, addr, 0);
+ uwr_set_req_buf(
+ ctx,
+ addr_of_mut!(REQUEST_BUF),
+ LUW_SRB_NONE
+ );
+
+ f = File::create("/var/tmp/large-file.dat").unwrap();
+ } else {
+ f = File::options()
+ .append(true)
+ .open("/var/tmp/large-file.dat")
+ .unwrap();
+ }
+
+ bytes_wrote = uwr_mem_splice_file(addr, &mut f);
+ if bytes_wrote == -1 {
+ return -1;
+ }
+
+ total += bytes_wrote as u64;
+ if total == uwr_get_http_content_len(ctx) {
+ total = 0;
+
+ uwr_http_response_end();
+ }
+
+ unsafe { TOTAL_BYTES_WROTE = total };
+
+ return 0;
+ }
+
+uwr_mem_fill_buf_from_req
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_req_buf_append(ctx: *mut luw_ctx_t, src: *const u8);
+
+This is a convenience function to fill the response buffer with data
+from the request buffer.
+
+*from* is basically the offset in the request_buffer where to start
+copying data from.
+
+Example
+
+.. code:: rust
+
+ /* ... */
+ write_bytes = uwr_mem_fill_buf_from_req(ctx, TOTAL_RESPONSE_SENT);
+ TOTAL_RESPONSE_SENT += write_bytes;
+ /* ... */
+
+This is taken from the `upload-reflector
+demo <https://github.com/nginx/unit-wasm/blob/main/examples/c/upload-reflector/src/lib.rs>`__
+demo module.
+
+In this case we build up a request_buffer on each call of
+luw_request_handler(), so TOTAL_RESPONSE_SENT grows each time by how
+much data was sent in *that* request.
+
+Here are are sending data back to the client after each time we receive
+it to demonstrate the interleaving of requests and responses from the
+WebAssembly module during a single http request.
+
+This function returns the number of bytes written to the response
+buffer.
+
+uwr_mem_reset
+~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_luw_mem_reset(ctx: *mut luw_ctx_t);
+
+This function resets the response buffer size and the number of response
+headers back to 0.
+
+uwr_http_set_response_status
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_set_response_status(status: luw_http_status_t);
+
+This function is used to set the HTTP response status. It takes one of
+the `luw_http_status_t <#luw_http_status_t>`__ enum values.
+
+It should be called before any calls to *uwr_http_send_response()* or
+*uwr_http_send_headers()*.
+
+If you don’t call this function the response status defaults to ‘200
+OK’.
+
+If you wish to error out with a ‘500 Internal Server Error’, you don’t
+need to call this function. Simply returning *-1* from the
+request_handler function will indicate this error.
+
+E.g
+
+Send a ‘403 Forbidden’
+
+.. code:: rust
+
+ /* ... */
+ uwr_http_set_response_status(LUW_HTTP_FORBIDDEN);
+ uwr_http_send_response(ctx); /* Doesn't require any body */
+ uwr_http_response_end();
+ /* ... */
+ return 0;
+
+Send a ‘307 Temporary Re-direct’
+
+.. code:: rust
+
+ /* ... */
+ uwr_http_set_response_status(LUW_HTTP_TEMPORARY_REDIRECT);
+
+ uwr_http_init_headers(ctx, 1, 0);
+ uwr_http_add_header(ctx, "Location", "https://example.com/");
+ uwr_http_send_headers(ctx);
+ uwr_http_response_end();
+ /* ... */
+ return 0;
+
+*Version: 0.3.0*
+
+uwr_http_send_response
+~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_send_response(ctx: *const luw_ctx_t);
+
+This function calls into Unit to send the response buffer back.
+
+uwr_http_init_headers
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_init_headers(ctx: *mut luw_ctx_t, nr: usize, offset: usize);
+
+This function is used in the preparation of sending back response
+headers.
+
+*nr* is the number of headers we are sending.
+
+*offset* is the offset into the response buffer where we are placing
+these headers. This will usually be 0.
+
+Example
+
+.. code:: rust
+
+ uwr_http_init_headers(ctx, 2, 0);
+
+uwr_http_add_header
+~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_add_header(
+ ctx: *mut luw_ctx_t,
+ name: &str,
+ value: &str,
+ );
+
+This function is used to add a header to the response.
+
+*name* is the name of the header.
+
+*value* is the value of the header.
+
+Example
+
+.. code:: rust
+
+ uwr_http_add_header(&ctx, "Content-Type", "text/plain");
+ uwr_http_add_header(
+ ctx,
+ "Content-Length",
+ &format!("{}", uwr_get_response_data_size(ctx)),
+ );
+
+uwr_http_add_header_content_type
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_add_header_content_type(ctx: *mut luw_ctx_t, ctype: &str);
+
+A convenience function for setting the ‘Content-Type’ response header.
+E.g the above example that adds the *Content-Type* header could be
+written as
+
+.. code:: rust
+
+ uwr_http_add_header_content_type(ctx, "text/plain");
+
+*Version: 0.2.0*
+
+uwr_http_add_header_content_len
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_add_header_content_len(ctx: *mut luw_ctx_t);
+
+A convenience function for setting the ‘Content-Length’ response header.
+E.g the above example that adds the *Content-Length* header could be
+written as
+
+.. code:: rust
+
+ uwr_http_add_header_content_len(ctx);
+
+This function uses
+`uwr_get_response_data_size <#uwr_get_response_data_size>`__ internally
+to get the size of the response data.
+
+*Version: 0.2.0*
+
+uwr_http_send_headers
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_send_headers(ctx: *const luw_ctx_t);
+
+This function calls into Unit and triggers the sending of the response
+headers.
+
+uwr_http_response_end
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_http_response_end();
+
+This function calls into Unit and tells it this is the end of the
+response which will trigger Unit to send it to the client.
+
+uwr_mem_get_init_size
+~~~~~~~~~~~~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_mem_get_init_size() -> u32;
+
+This function calls into Unit to get the size of the shared memory. This
+is the amount of memory you should assume you have for creating
+responses. Remember you can create multiple responses before calling
+luw_http_response_end().
+
+Misc. Functions
+---------------
+
+The following functions are convenience wrappers for the Rust bindings
+and should **not** be used directly.
+
+uwr_malloc
+~~~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_malloc(size: u32) -> *mut u8;
+
+Essentially a straight wrapper for malloc(3).
+
+uwr_free
+~~~~~~~~
+
+.. code:: rust
+
+ pub fn uwr_free(ptr: *mut u8);
+
+Essentially a straight wrapper for free(3).
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
deleted file mode 100644
index aea287f..0000000
--- a/CODE_OF_CONDUCT.md
+++ /dev/null
@@ -1,74 +0,0 @@
-# Contributor Covenant Code of Conduct
-
-## Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, sex characteristics, gender identity and expression,
-level of experience, education, socio-economic status, nationality, personal
-appearance, race, religion, or sexual identity and orientation.
-
-## Our Standards
-
-Examples of behavior that contributes to creating a positive environment
-include:
-
-- Using welcoming and inclusive language
-- Being respectful of differing viewpoints and experiences
-- Gracefully accepting constructive criticism
-- Focusing on what is best for the community
-- Showing empathy towards other community members
-
-Examples of unacceptable behavior by participants include:
-
-- The use of sexualized language or imagery and unwelcome sexual attention or
- advances
-- Trolling, insulting/derogatory comments, and personal or political attacks
-- Public or private harassment
-- Publishing others' private information, such as a physical or electronic
- address, without explicit permission
-- Other conduct which could reasonably be considered inappropriate in a
- professional setting
-
-## Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
-
-## Scope
-
-This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
-
-## Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the moderation team at nginx-oss-community@f5.com. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project's leadership.
-
-## Attribution
-
-This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 1.4,
-available at <https://www.contributor-covenant.org/version/1/4/code-of-conduct.html>
-
-For answers to common questions about this code of conduct, see
-<https://www.contributor-covenant.org/faq>
diff --git a/CODE_OF_CONDUCT.rst b/CODE_OF_CONDUCT.rst
new file mode 100644
index 0000000..60233d9
--- /dev/null
+++ b/CODE_OF_CONDUCT.rst
@@ -0,0 +1,88 @@
+Contributor Covenant Code of Conduct
+====================================
+
+Our Pledge
+----------
+
+In the interest of fostering an open and welcoming environment, we as
+contributors and maintainers pledge to making participation in our
+project and our community a harassment-free experience for everyone,
+regardless of age, body size, disability, ethnicity, sex
+characteristics, gender identity and expression, level of experience,
+education, socio-economic status, nationality, personal appearance,
+race, religion, or sexual identity and orientation.
+
+Our Standards
+-------------
+
+Examples of behavior that contributes to creating a positive environment
+include:
+
+- Using welcoming and inclusive language
+- Being respectful of differing viewpoints and experiences
+- Gracefully accepting constructive criticism
+- Focusing on what is best for the community
+- Showing empathy towards other community members
+
+Examples of unacceptable behavior by participants include:
+
+- The use of sexualized language or imagery and unwelcome sexual
+ attention or advances
+- Trolling, insulting/derogatory comments, and personal or political
+ attacks
+- Public or private harassment
+- Publishing others’ private information, such as a physical or
+ electronic address, without explicit permission
+- Other conduct which could reasonably be considered inappropriate in a
+ professional setting
+
+Our Responsibilities
+--------------------
+
+Project maintainers are responsible for clarifying the standards of
+acceptable behavior and are expected to take appropriate and fair
+corrective action in response to any instances of unacceptable behavior.
+
+Project maintainers have the right and responsibility to remove, edit,
+or reject comments, commits, code, wiki edits, issues, and other
+contributions that are not aligned to this Code of Conduct, or to ban
+temporarily or permanently any contributor for other behaviors that they
+deem inappropriate, threatening, offensive, or harmful.
+
+Scope
+-----
+
+This Code of Conduct applies both within project spaces and in public
+spaces when an individual is representing the project or its community.
+Examples of representing a project or community include using an
+official project e-mail address, posting via an official social media
+account, or acting as an appointed representative at an online or
+offline event. Representation of a project may be further defined and
+clarified by project maintainers.
+
+Enforcement
+-----------
+
+Instances of abusive, harassing, or otherwise unacceptable behavior may
+be reported by contacting the moderation team at
+nginx-oss-community@f5.com. All complaints will be reviewed and
+investigated and will result in a response that is deemed necessary and
+appropriate to the circumstances. The project team is obligated to
+maintain confidentiality with regard to the reporter of an incident.
+Further details of specific enforcement policies may be posted
+separately.
+
+Project maintainers who do not follow or enforce the Code of Conduct in
+good faith may face temporary or permanent repercussions as determined
+by other members of the project’s leadership.
+
+Attribution
+-----------
+
+This Code of Conduct is adapted from the `Contributor
+Covenant <https://www.contributor-covenant.org>`__, version 1.4,
+available at
+https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
+
+For answers to common questions about this code of conduct, see
+https://www.contributor-covenant.org/faq
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
deleted file mode 100644
index 90917bf..0000000
--- a/CONTRIBUTING.md
+++ /dev/null
@@ -1,83 +0,0 @@
-# Contributing Guidelines
-
-The following is a set of guidelines for contributing to unit-wasm. We do
-appreciate that you are considering contributing!
-
-## Table Of Contents
-
-- [Getting Started](#getting-started)
-- [Ask a Question](#ask-a-question)
-- [Contributing](#contributing)
-- [Git Style Guide](#git-style-guide)
-
-
-## Getting Started
-
-Check out the [README](README.md).
-
-
-## Ask a Question
-
-Please open an [issue](https://github.com/nginx/unit-wasm/issues/new) on
-GitHub with the label `question`. You can also ask a question on
-[Slack](https://nginxcommunity.slack.com) or the NGINX Unit mailing list,
-unit@nginx.org (subscribe
-[here](https://mailman.nginx.org/mailman3/lists/unit.nginx.org/)).
-
-
-## Contributing
-
-### Report a Bug
-
-Ensure the bug was not already reported by searching on GitHub under
-[Issues](https://github.com/nginx/unit-wasm/issues).
-
-If the bug is a potential security vulnerability, please report using our
-[security policy](https://unit.nginx.org/troubleshooting/#getting-support).
-
-To report a non-security bug, open an
-[issue](https://github.com/nginx/unit-wasm/issues/new) on GitHub with the
-label `bug`. Be sure to include a title and clear description, as much
-relevant information as possible, and a code sample or an executable test
-case showing the expected behavior that doesn't occur.
-
-
-### Suggest an Enhancement
-
-To suggest an enhancement, open an
-[issue](https://github.com/nginx/unit-wasm/issues/new) on GitHub with the
-label `enhancement`. Please do this before implementing a new feature to
-discuss the feature first.
-
-
-### Open a Pull Request
-
-Clone the repo, create a branch, and submit a PR when your changes are tested
-and ready for review. Again, if you'd like to implement a new feature, please
-consider creating a feature request issue first to start a discussion about
-the feature.
-
-
-## Git Style Guide
-
-- Split your work into multiple commits is necessary. Each commit should make
- one logical change. I.e don't mix code re-formatting with a fix in the same
- commit.
-
-- Subject lines should be short (around 50 characters, not a hard rule) and
- concisely describe the change.
-
-- The commit message body should be limited to 72 character lines.
-
-- You can use subject line prefixes for commits that affect a specific
- portion of the code; examples include "libunit-wasm:" and "rust-bindings:".
-
-- Reference issues and PRs at the end of the commit messages, e.g if the
- commit remedies a GitHub issue add a tag like
-
- Closes: <https://github.com/nginx/unit-wasm/issues/NNN>
-
- If the commit fixes an issue introduced in a previous commit use the "Fixes"
- tag to reference it, e.g
-
- Fixes: abbrev commit id ("Commit subject line")
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
new file mode 100644
index 0000000..0cacb11
--- /dev/null
+++ b/CONTRIBUTING.rst
@@ -0,0 +1,88 @@
+Contributing Guidelines
+=======================
+
+The following is a set of guidelines for contributing to unit-wasm. We
+do appreciate that you are considering contributing!
+
+Table Of Contents
+-----------------
+
+- `Getting Started <#getting-started>`__
+- `Ask a Question <#ask-a-question>`__
+- `Contributing <#contributing>`__
+- `Git Style Guide <#git-style-guide>`__
+
+Getting Started
+---------------
+
+Check out the `README <README.md>`__.
+
+Ask a Question
+--------------
+
+Please open an `issue <https://github.com/nginx/unit-wasm/issues/new>`__
+on GitHub with the label ``question``. You can also ask a question on
+`Slack <https://nginxcommunity.slack.com>`__ or the NGINX Unit mailing
+list, unit@nginx.org (subscribe
+`here <https://mailman.nginx.org/mailman3/lists/unit.nginx.org/>`__).
+
+Contributing
+------------
+
+Report a Bug
+~~~~~~~~~~~~
+
+Ensure the bug was not already reported by searching on GitHub under
+`Issues <https://github.com/nginx/unit-wasm/issues>`__.
+
+If the bug is a potential security vulnerability, please report using
+our `security
+policy <https://unit.nginx.org/troubleshooting/#getting-support>`__.
+
+To report a non-security bug, open an
+`issue <https://github.com/nginx/unit-wasm/issues/new>`__ on GitHub with
+the label ``bug``. Be sure to include a title and clear description, as
+much relevant information as possible, and a code sample or an
+executable test case showing the expected behavior that doesn’t occur.
+
+Suggest an Enhancement
+~~~~~~~~~~~~~~~~~~~~~~
+
+To suggest an enhancement, open an
+`issue <https://github.com/nginx/unit-wasm/issues/new>`__ on GitHub with
+the label ``enhancement``. Please do this before implementing a new
+feature to discuss the feature first.
+
+Open a Pull Request
+~~~~~~~~~~~~~~~~~~~
+
+Clone the repo, create a branch, and submit a PR when your changes are
+tested and ready for review. Again, if you’d like to implement a new
+feature, please consider creating a feature request issue first to start
+a discussion about the feature.
+
+Git Style Guide
+---------------
+
+- Split your work into multiple commits is necessary. Each commit
+ should make one logical change. I.e don’t mix code re-formatting with
+ a fix in the same commit.
+
+- Subject lines should be short (around 50 characters, not a hard rule)
+ and concisely describe the change.
+
+- The commit message body should be limited to 72 character lines.
+
+- You can use subject line prefixes for commits that affect a specific
+ portion of the code; examples include “libunit-wasm:” and
+ “rust-bindings:”.
+
+- Reference issues and PRs at the end of the commit messages, e.g if
+ the commit remedies a GitHub issue add a tag like
+
+ Closes: https://github.com/nginx/unit-wasm/issues/NNN
+
+ If the commit fixes an issue introduced in a previous commit use the
+ “Fixes” tag to reference it, e.g
+
+ Fixes: abbrev commit id (“Commit subject line”)
diff --git a/HOWTO.md b/HOWTO.md
deleted file mode 100644
index 7f1cd92..0000000
--- a/HOWTO.md
+++ /dev/null
@@ -1,210 +0,0 @@
-Trying it out
-=============
-
-For a quick and simple 'hello world' experience, you can use docker with
-
-```shell
-$ make docker
-```
-
-which will create two images:
-
- 1. `unit:wasm` (based on the Docker Official image, with Wasm Module)
- 2. `unit:demo-wasm` (based on the Wasm image, with demo application)
-
-Manual build instructions below.
-
-## Prerequisites and Assumptions
-
-You will need:
- * Modern Linux platform (might work on others, not yet tested).
- * Ability to build Unit from source.
- If you haven't done this before, please first run through the
-[Building From Source how-to guide](https://unit.nginx.org/howto/source/).
- * Additional build tools (required for the demo Wasm Module)
- - clang
- - llvm
- - lld
-
-## Building the Wasm Language Module
-
-0. Do a test build of Unit from source ([see docs](https://unit.nginx.org/howto/source/)) with this PR/patch applied. The following steps assume you're
-starting in the `unit` directory and used `./configure --prefix=$PWD/build`.
-
-2. Download and extract the Wasmtime C API (newer versions may or may not
-work). Notice that we use `$(arch)` to substitute-in the appropriate CPU
-architecture. This works for **x86_64** and **aarch64** (ARM) platforms.
-```
-wget -O- https://github.com/bytecodealliance/wasmtime/releases/download/v11.0.0/wasmtime-v11.0.0-$(arch)-linux-c-api.tar.xz | tar Jxfv -
-```
-
-3. Configure the Wasm Language Module for Unit
-```
-./configure wasm --include-path=$PWD/wasmtime-v11.0.0-$(arch)-linux-c-api/include \
- --lib-path=$PWD/wasmtime-v11.0.0-$(arch)-linux-c-api/lib --rpath
-```
-
-4. Build the Wasm Language Module
-```
-make
-```
-
-5. Test that **unitd** Can Load the Language Module
-
-Run `unitd` in the foreground (attached to the console) to check that Unit
-can discover and load the `wasm` Language Module at startup. You should see
-console output similar to this:
-```
-$ $PWD/build/sbin/unitd --no-daemon --log /dev/stderr
-2023/06/15 11:29:31 [info] 1#1 unit 1.31.0 started
-2023/06/15 11:29:31 [info] 43#43 discovery started
-2023/06/15 11:29:31 [notice] 43#43 module: wasm 0.1 "/path/to/modules/wasm.unit.so"
-```
-
-## Building the demo application
-
-From a suitable directory...
-
-Clone the [unit-wasm](https://github.com/nginx/unit-wasm) repository
-
-```shell
-$ git clone https://github.com/nginx/unit-wasm.git
-```
-
-Download and extract the wasi-sysroot from the [WASI SDK](https://github.com/WebAssembly/wasi-sdk)
-
-```shell
-wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sysroot-20.0.tar.gz | tar zxfv -
-```
-
-Next Compile the C demo Wasm Modules to `.wasm` files. This requires at least
-the following; make and clang, llvm, compiler-rt, and lld from LLVM 9.0+
-
-```shell
-$ cd unit-wasm
-$ make WASI_SYSROOT=../wasi-sysroot examples
-```
-
-If the above fails like
-
-```
-wasm-ld: error: cannot open /usr/lib/llvm-11/lib/clang/11.0.1/lib/wasi/libclang_rt.builtins-wasm32.a: No such file or directory
-clang: error: linker command failed with exit code 1 (use -v to see invocation)
-```
-Then you need to download the wasm32 clang runtime and copy it into the
-location mentioned in the error message.
-
-E.g
-
-In the above case we would untar
-*libclang_rt.builtins-wasm32-wasi-20.0.tar.gz* into
-*/usr/lib/llvm-11/lib/clang/11.0.1/*
-
-On Fedora this would be more like */usr/lib64/clang/16/*
-
-Adjust the tar '-C ...' option accordingly below...
-
-```shell
-wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | sudo tar -xvzf - -C /usr/lib/llvm-11/lib/clang/11.0.1
-```
-
-With recent enough versions of Clang (that support the -print-runtime-dir
-option) you can use the following command (as root)
-
-```shell
-wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | tar --strip-components=1 -xvzf - -C $(dirname $(clang -print-runtime-dir))
-```
-
-Then try again...
-
-If everything built OK then you should have the following two WASM modules
-
-```
-examples/c/luw-echo-request.wasm
-examples/c/luw-upload-reflector.wasm
-```
-
-## Configure Unit to run the demo application
-
-```json
- {
- "listeners": {
- "[::1]:8080": {
- "pass": "routes"
- }
- },
-
- "settings": {
- "http": {
- "max_body_size": 1073741824
- }
- },
-
- "routes": [
- {
- "match": {
- "uri": "/echo*"
- },
- "action": {
- "pass": "applications/luw-echo-request"
- }
- },
- {
- "match": {
- "uri": "/upload*"
- },
- "action": {
- "pass": "applications/luw-upload-reflector"
- }
- }
- ],
-
- "applications": {
- "luw-echo-request": {
- "type": "wasm",
- "module": "/path/to/unit-wasm/examples/c/luw-echo-request.wasm",
- "request_handler": "luw_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "module_init_handler": "luw_module_init_handler",
- "module_end_handler": "luw_module_end_handler",
- "access": {
- "filesystem": [
- "/tmp",
- "/foo/bar"
- ]
- }
- },
- "luw-upload-reflector": {
- "type": "wasm",
- "module": "/path/to/unit-wasm/examples/c/luw-upload-reflector.wasm",
- "request_handler": "luw_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "request_end_handler": "luw_request_end_handler",
- "response_end_handler": "luw_response_end_handler"
- }
- }
-}
-
-```
-
-Apply the above configuration to the **/config** URI of Unit's Control API.
-With the JSON in a file, you can use the CLI to apply it.
-```
-cat conf.json | tools/unitc /config
-```
-
-The following messages should then appear in the Unit log file (or console if
-running with `--no-daemon`).
-```
-2023/07/26 13:28:14 [info] 182585#182585 "luw-echo-request" prototype started
-2023/07/26 13:28:14 [info] 182590#182590 "luw-echo-request" application started
-2023/07/26 13:28:14 [info] 182591#182591 "luw-upload-reflector" prototype started
-2023/07/26 13:28:14 [info] 182596#182596 "luw-upload-reflector" application started
-```
-
-Now make a request to the demo application.
-```
-curl http://localhost:8080/echo
-```
diff --git a/HOWTO.rst b/HOWTO.rst
new file mode 100644
index 0000000..5883a5d
--- /dev/null
+++ b/HOWTO.rst
@@ -0,0 +1,223 @@
+Trying it out
+=============
+
+For a quick and simple ‘hello world’ experience, you can use docker with
+
+.. code:: shell
+
+ $ make docker
+
+which will create two images:
+
+1. ``unit:wasm`` (based on the Docker Official image, with Wasm Module)
+2. ``unit:demo-wasm`` (based on the Wasm image, with demo application)
+
+Manual build instructions below.
+
+Prerequisites and Assumptions
+-----------------------------
+
+You will need: \* Modern Linux platform (might work on others, not yet
+tested). \* Ability to build Unit from source. If you haven’t done this
+before, please first run through the `Building From Source how-to
+guide <https://unit.nginx.org/howto/source/>`__. \* Additional build
+tools (required for the demo Wasm Module) - clang - llvm - lld
+
+Building the Wasm Language Module
+---------------------------------
+
+0. Do a test build of Unit from source (`see
+ docs <https://unit.nginx.org/howto/source/>`__) with this PR/patch
+ applied. The following steps assume you’re starting in the ``unit``
+ directory and used ``./configure --prefix=$PWD/build``.
+
+1. Download and extract the Wasmtime C API (newer versions may or may
+ not work). Notice that we use ``$(arch)`` to substitute-in the
+ appropriate CPU architecture. This works for **x86_64** and
+ **aarch64** (ARM) platforms.
+
+::
+
+ wget -O- https://github.com/bytecodealliance/wasmtime/releases/download/v11.0.0/wasmtime-v11.0.0-$(arch)-linux-c-api.tar.xz | tar Jxfv -
+
+3. Configure the Wasm Language Module for Unit
+
+::
+
+ ./configure wasm --include-path=$PWD/wasmtime-v11.0.0-$(arch)-linux-c-api/include \
+ --lib-path=$PWD/wasmtime-v11.0.0-$(arch)-linux-c-api/lib --rpath
+
+4. Build the Wasm Language Module
+
+::
+
+ make
+
+5. Test that **unitd** Can Load the Language Module
+
+Run ``unitd`` in the foreground (attached to the console) to check that
+Unit can discover and load the ``wasm`` Language Module at startup. You
+should see console output similar to this:
+
+::
+
+ $ $PWD/build/sbin/unitd --no-daemon --log /dev/stderr
+ 2023/06/15 11:29:31 [info] 1#1 unit 1.31.0 started
+ 2023/06/15 11:29:31 [info] 43#43 discovery started
+ 2023/06/15 11:29:31 [notice] 43#43 module: wasm 0.1 "/path/to/modules/wasm.unit.so"
+
+Building the demo application
+-----------------------------
+
+From a suitable directory…
+
+Clone the `unit-wasm <https://github.com/nginx/unit-wasm>`__ repository
+
+.. code:: shell
+
+ $ git clone https://github.com/nginx/unit-wasm.git
+
+Download and extract the wasi-sysroot from the `WASI
+SDK <https://github.com/WebAssembly/wasi-sdk>`__
+
+.. code:: shell
+
+ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sysroot-20.0.tar.gz | tar zxfv -
+
+Next Compile the C demo Wasm Modules to ``.wasm`` files. This requires
+at least the following; make and clang, llvm, compiler-rt, and lld from
+LLVM 9.0+
+
+.. code:: shell
+
+ $ cd unit-wasm
+ $ make WASI_SYSROOT=../wasi-sysroot examples
+
+If the above fails like
+
+::
+
+ wasm-ld: error: cannot open /usr/lib/llvm-11/lib/clang/11.0.1/lib/wasi/libclang_rt.builtins-wasm32.a: No such file or directory
+ clang: error: linker command failed with exit code 1 (use -v to see invocation)
+
+Then you need to download the wasm32 clang runtime and copy it into the
+location mentioned in the error message.
+
+E.g
+
+In the above case we would untar
+*libclang_rt.builtins-wasm32-wasi-20.0.tar.gz* into
+*/usr/lib/llvm-11/lib/clang/11.0.1/*
+
+On Fedora this would be more like */usr/lib64/clang/16/*
+
+Adjust the tar ‘-C …’ option accordingly below…
+
+.. code:: shell
+
+ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | sudo tar -xvzf - -C /usr/lib/llvm-11/lib/clang/11.0.1
+
+With recent enough versions of Clang (that support the
+-print-runtime-dir option) you can use the following command (as root)
+
+.. code:: shell
+
+ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | tar --strip-components=1 -xvzf - -C $(dirname $(clang -print-runtime-dir))
+
+Then try again…
+
+If everything built OK then you should have the following two WASM
+modules
+
+::
+
+ examples/c/luw-echo-request.wasm
+ examples/c/luw-upload-reflector.wasm
+
+Configure Unit to run the demo application
+------------------------------------------
+
+.. code:: json
+
+ {
+ "listeners": {
+ "[::1]:8080": {
+ "pass": "routes"
+ }
+ },
+
+ "settings": {
+ "http": {
+ "max_body_size": 1073741824
+ }
+ },
+
+ "routes": [
+ {
+ "match": {
+ "uri": "/echo*"
+ },
+ "action": {
+ "pass": "applications/luw-echo-request"
+ }
+ },
+ {
+ "match": {
+ "uri": "/upload*"
+ },
+ "action": {
+ "pass": "applications/luw-upload-reflector"
+ }
+ }
+ ],
+
+ "applications": {
+ "luw-echo-request": {
+ "type": "wasm",
+ "module": "/path/to/unit-wasm/examples/c/luw-echo-request.wasm",
+ "request_handler": "luw_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "module_init_handler": "luw_module_init_handler",
+ "module_end_handler": "luw_module_end_handler",
+ "access": {
+ "filesystem": [
+ "/tmp",
+ "/foo/bar"
+ ]
+ }
+ },
+ "luw-upload-reflector": {
+ "type": "wasm",
+ "module": "/path/to/unit-wasm/examples/c/luw-upload-reflector.wasm",
+ "request_handler": "luw_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "request_end_handler": "luw_request_end_handler",
+ "response_end_handler": "luw_response_end_handler"
+ }
+ }
+ }
+
+Apply the above configuration to the **/config** URI of Unit’s Control
+API. With the JSON in a file, you can use the CLI to apply it.
+
+::
+
+ cat conf.json | tools/unitc /config
+
+The following messages should then appear in the Unit log file (or
+console if running with ``--no-daemon``).
+
+::
+
+ 2023/07/26 13:28:14 [info] 182585#182585 "luw-echo-request" prototype started
+ 2023/07/26 13:28:14 [info] 182590#182590 "luw-echo-request" application started
+ 2023/07/26 13:28:14 [info] 182591#182591 "luw-upload-reflector" prototype started
+ 2023/07/26 13:28:14 [info] 182596#182596 "luw-upload-reflector" application started
+
+Now make a request to the demo application.
+
+::
+
+ curl http://localhost:8080/echo
diff --git a/README.md b/README.md
deleted file mode 100644
index 76dec73..0000000
--- a/README.md
+++ /dev/null
@@ -1,490 +0,0 @@
-# C & Rust Library & Examples for Building WebAssembly Modules for NGINX Unit
-
-This provides a C library (lbunit-wasm) and Rust crates based on that library
-to aid in the creation of WebAssembly modules in C and Rust.
-
-It also has some demo WebAssembly modules written in C and Rust.
-
-1. [C & Rust Library & Examples for Building WebAssembly Modules for NGINX Unit](#c---rust-library---examples-for-building-webassembly-modules-for-nginx-unit)
-2. [Repository Layout](#repository-layout)
-3. [Setup a Suitable Environment](#setup-a-suitable-environment)
- 1. [Fedora](#fedora)
- 2. [Debian / Ubuntu](#debian--ubuntu)
-4. [Quickstart in Developing Rust WebAssembly Modules for Unit](#quickstart-in-developing-rust-webassembly-modules-for-unit)
-5. [Working With the Repository](#working-with-the-repository)
-6. [Using With Unit](#using-with-unit)
-7. [Consuming the C Library](#consuming-the-c-library)
-8. [License](#license)
-
-## Repository Layout
-
-**src/c** contains the main libunit-wasm library.
-
-**src/rust** contains the rust version of the above.
-
-**examples/c** contains some demo WebAssembly modules that show both the raw
-interface to Unit (\*-raw.c) and also the use of libunit-wasm (luw-\*.c).
-
-**examples/rust** contains rust versions of the above C demo modules and more.
-
-**examples/docker** contains docker files for building Unit with WebAssembly
-support and the C examples.
-
-## Setup a Suitable Environment
-
-To make full use of this repository you will require numerous tools/packages.
-
-Exactly what you need and how to get it will depend on your Operating System.
-
-This has been primarily developed and tested on Fedora & Ubuntu Linux.
-
-### Fedora
-
-On Fedora make sure you have the following installed
-
-```
-# dnf install make clang llvm compiler-rt lld wasi-libc-devel \
- wasi-libc-static cargo rust rustfmt rust-std-static \
- rust-std-static-wasm32-unknown-unknown \
- rust-std-static-wasm32-wasi
-```
-
-One last item you will need is the libclang wasm32-wasi runtime library, this
-can be done with
-
-```
-# wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | tar --strip-components=1 -xvzf - -C $(dirname $(clang -print-runtime-dir))
-```
-
-This will install the following, path may vary slightly
-
-```
-/usr/lib64/clang/16/lib/wasi/libclang_rt.builtins-wasm32.a
-```
-
-The above should also work (perhaps with slight alterations) on recent
-CentOS/RHEL etc...
-
-**NOTE:** If you get a major Clang version update, you may need to repeat
-that last task.
-
-### Debian / Ubuntu
-
-Install the following as normal
-
-```
-# apt install wasi-libc make clang llvm lld
-```
-
-For the rest you will likely need to use [rustup](https://rustup.rs). Caveat
-Emptor.
-
-After you've completed the _rustup_ installation by following the on screen
-instructions as yourself (defaults are fine), do the following
-
-```shell
-$ rustup target add wasm32-wasi
-```
-
-You will also need to grab the wasi-sysroot, this is essentially a C library
-targeting WebAssembly (it is based partly on cloudlibc and musl libc) and
-is required for building server side WebAssembly modules.
-
-It's up to you where you put this.
-
-```shell
-$ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sysroot-20.0.tar.gz | tar -xzf -
-```
-
-And finally similarly as Fedora (this requires a recentish clang)
-
-```
-# wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | tar --strip-components=1 -xvzf - -C $(dirname $(clang -print-runtime-dir))
-```
-
-## Quickstart in Developing Rust WebAssembly Modules for Unit
-
-1) Setup a suitable build environment as above.
-
-2) Create a new rust project
-
-```shell
-$ cargo init --lib my-wasm-example
-```
-
-3) Add the [unit-wasm crate](https://crates.io/crates/unit-wasm) as dependency
-
-```shell
-$ cd my-wasm-example
-$ cargo add unit-wasm
-```
-
-4) Set the crate type
-
-```shell
-$ printf '\n[lib]\ncrate-type = ["cdylib"]\n' >>Cargo.toml
-```
-
-5) Create an example application
-
-To do this you can simply take a copy of our echo-request demo in this
-repository
-
-```shell
-$ wget -O src/lib.rs https://raw.githubusercontent.com/nginx/unit-wasm/main/examples/rust/echo-request/src/lib.rs
-```
-
-6) Build it!
-
-```shell
-$ cargo build --target wasm32-wasi
-```
-
-You should now have a *target/wasm32-wasi/debug/my_wasm_example.wasm* file
-(yes, hyphens will be turned to underscores)
-
-You can now use this in Unit with the following config
-
-```JSON
-{
- "listeners": {
- "[::1]:8888": {
- "pass": "applications/my-wasm-example"
- }
- },
-
- "applications": {
- "my-wasm-example": {
- "type": "wasm",
- "module": "/path/to/my-wasm-example/target/wasm32-wasi/debug/my_wasm_example.wasm",
- "request_handler": "uwr_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "module_init_handler": "uwr_module_init_handler",
- "module_end_handler": "uwr_module_end_handler"
- }
- }
-}
-```
-
-and curl command
-
-```shell
-$ curl http://localhost:8888/
-```
-
-7) Start writing your own Wasm modules in Rust!
-
-To help you get started, you can check out the Rust examples under
-[examples/rust](https://github.com/nginx/unit-wasm/tree/main/examples/rust)
-and also the
-[API-Rust.md](https://github.com/nginx/unit-wasm/blob/main/API-Rust.md)
-for an overview of the API.
-
-## Working With the Repository
-
-The project uses good old _make(1)_ as the build system.
-
-Typing _make help_ will show the list of available targets and the various
-make variables you can set. E.g
-
-```
-$ make help
-Available Targets:
- default /
- libunit-wasm - Builds libunit-wasm C library
- examples - Builds the above as well as C examples
- examples-raw - Builds raw (non libunit-wasm) C examples
- rust - Builds the libunit-wasm rust crate
- examples-rust _ Builds the above and rust examples
- all - Builds all the above
- docker - Builds demo docker images
- clean - Removes auto generated artifacts
- tags - Generate ctags
-
-Variables:
- make CC= - Specify compiler to use
- Defaults to clang
- make WASI_SYSROOT= - Specify the path to the WASI sysroot
- Defaults to autodetected
- make V=1 - Enables verbose output
- make D=1 - Enables debug builds (-O0)
- make E=1 - Enables Werror
-```
-
-If you have previously followed the steps outlined above in
-[Setup a Suitable Environment](#setup-a-suitable-environment)
-
-You can build the libunit-wasm C library, C example Wasm modules, the Rust
-crates that provides Rust bindings for the libunit-wasm and the Rust example
-Wasm modules.
-
-E.g
-
-```shell
-$ make # Build just the C library
-$ make examples # Build the C library and C examples
-$ make rust # Build the Rust crates
-$ make examples-rust # Build the Rust examples
-$ make all # Build all the above
-```
-
-The C and Rust example Wasm modules will be located at
-
-```
-examples/c/luw-echo-request.wasm
-examples/c/luw-upload-reflector.wasm
-examples/rust/echo-request/target/wasm32-wasi/debug/rust_echo_request.wasm
-examples/rust/hello-world/target/wasm32-wasi/debug/rust_hello_world.wasm
-examples/rust/upload-reflector/target/wasm32-wasi/debug/rust_upload_reflector.wasm
-```
-
-**NOTE:** To build the C library and examples you will need to specify the
-wasi-sysroot.
-
-E.g
-
-```shell
-$ make WASI_SYSROOT=/path/to/wasi-sysroot all
-```
-
-**However** if you are on Fedora and installed the _wasi-*_ packages listed
-above in the [Setup a Suitable Environment](#fedora) then the wasi-sysroot
-path will be autodetected and set by the Makefile. You can override the
-autodetection by explicitly specifying it as above.
-
-## Using With Unit
-
-If you have all the above built, you are now ready to test it out with Unit.
-
-We won't go into the details of building Unit from source and enabling the Unit
-WebAssembly language module here (see the
-[HOWTO.md](https://github.com/nginx/unit-wasm/blob/main/HOWTO.md) in the
-repository root for more details) but will instead assume you already have a
-Unit with the WebAssembly language module already running, perhaps installed
-via a package.
-
-Create the following Unit config (editing the module paths as appropriate)
-
-```JSON
-{
- "listeners": {
- "[::1]:8888": {
- "pass": "routes"
- }
- },
-
- "settings": {
- "http": {
- "max_body_size": 8589934592
- }
- },
-
- "routes": [
- {
- "match": {
- "uri": "/echo*"
- },
- "action": {
- "pass": "applications/luw-echo-request"
- }
- },
- {
- "match": {
- "uri": "/upload*"
- },
- "action": {
- "pass": "applications/luw-upload-reflector"
- }
- },
- {
- "match": {
- "uri": "/large-upload*"
- },
- "action": {
- "pass": "applications/large-upload"
- }
- },
- {
- "match": {
- "uri": "/rust-echo*"
- },
- "action": {
- "pass": "applications/rust-echo-request"
- }
- },
- {
- "match": {
- "uri": "/rust-upload*"
- },
- "action": {
- "pass": "applications/rust-upload-reflector"
- }
- },
- {
- "match": {
- "uri": "/rust-large-upload*"
- },
- "action": {
- "pass": "applications/rust-large-upload"
- }
- },
- {
- "match": {
- "uri": "/rust-hello-world*"
- },
- "action": {
- "pass": "applications/rust-hello-world"
- }
- }
- ],
-
- "applications": {
- "luw-echo-request": {
- "type": "wasm",
- "module": "/path/to/unit-wasm/examples/c/luw-echo-request.wasm",
- "request_handler": "luw_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "module_init_handler": "luw_module_init_handler",
- "module_end_handler": "luw_module_end_handler"
- },
- "luw-upload-reflector": {
- "type": "wasm",
- "module": "/path/to/unit-wasm/examples/c/luw-upload-reflector.wasm",
- "request_handler": "luw_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "request_end_handler": "luw_request_end_handler",
- "response_end_handler": "luw_response_end_handler"
- },
- "large-upload": {
- "type": "wasm",
- "module": "/path/to/unit-wasm/examples/c/large-upload.wasm",
- "request_handler": "luw_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "module_init_handler": "luw_module_init_handler",
- "module_end_handler": "luw_module_end_handler",
- "response_end_handler": "luw_response_end_handler",
- "access": {
- "filesystem": [
- "/var/tmp"
- ]
- }
- },
- "rust-echo-request": {
- "type": "wasm",
- "module": "/path/to/unit-wasm/examples/rust/echo-request/target/wasm32-wasi/debug/rust_echo_request.wasm",
- "request_handler": "uwr_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "module_init_handler": "uwr_module_init_handler",
- "module_end_handler": "uwr_module_end_handler"
- },
- "rust-upload-reflector": {
- "type": "wasm",
- "module": "/path/to/unit-wasm/examples/rust/upload-reflector/rust_upload_reflector.wasm",
- "request_handler": "uwr_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "request_end_handler": "uwr_request_end_handler",
- "response_end_handler": "uwr_response_end_handler"
- },
- "rust-large-upload": {
- "type": "wasm",
- "module": "/path/to/src/unit-wasm/examples/rust/large-upload/target/wasm32-wasi/debug/rust_large_upload.wasm",
- "request_handler": "uwr_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler",
- "module_init_handler": "uwr_module_init_handler",
- "module_end_handler": "uwr_module_end_handler",
- "response_end_handler": "uwr_response_end_handler",
- "access": {
- "filesystem": [
- "/var/tmp"
- ]
- }
- },
- "rust-hello-world": {
- "type": "wasm",
- "module": "/path/to/unit-wasm/examples/rust/hello-world/target/wasm32-wasi/debug/rust_hello_world.wasm",
- "request_handler": "uwr_request_handler",
- "malloc_handler": "luw_malloc_handler",
- "free_handler": "luw_free_handler"
- }
- }
-}
-```
-
-Load this config then you should be ready to try it.
-
-```
-$ curl -X POST -d "Hello World" --cookie "mycookie=hmmm" http://localhost:8888/echo/?q=a
- *** Welcome to WebAssembly on Unit! [libunit-wasm (0.1.0/0x00010000)] ***
-
-[Request Info]
-REQUEST_PATH = /echo/?q=a
-METHOD = POST
-VERSION = HTTP/1.1
-QUERY = q=a
-REMOTE = ::1
-LOCAL_ADDR = ::1
-LOCAL_PORT = 8080
-SERVER_NAME = localhost
-
-[Request Headers]
-Host = localhost:8080
-User-Agent = curl/8.0.1
-Accept = */*
-Cookie = mycookie=hmmm
-Content-Length = 11
-Content-Type = application/x-www-form-urlencoded
-
-[POST data]
-Hello World
-```
-
-```
-$ curl -v -X POST --data-binary @audio.flac -H "Content-Type: audio/flac" http://localhost:8888/upload-reflector/ -o wasm-test.dat
-...
-> Content-Type: audio/flac
-> Content-Length: 60406273
-...
- % Total % Received % Xferd Average Speed Time Time Time Current
- Dload Upload Total Spent Left Speed
-100 115M 100 57.6M 100 57.6M 47.6M 47.6M 0:00:01 0:00:01 --:--:-- 95.2M
-...
-< Content-Type: audio/flac
-< Content-Length: 60406273
-...
-$ sha1sum audio.flac wasm-test.dat
-ef5c9c228544b237022584a8ac4612005cd6263e audio.flac
-ef5c9c228544b237022584a8ac4612005cd6263e wasm-test.dat
-```
-
-## Consuming the C Library
-
-If **unit/unit-wasm.h** and **libunit.a** are installed into standard
-include/library directories then
-
-Include the libunit-wasm header file
-
-```C
-....
-#include <unit/unit-wasm.h>
-...
-```
-
-Link against libunit-wasm
-
-```shell
-$ clang ... -o myapp.wasm myapp.c -lunit-wasm
-```
-
-See [API-C.md](https://github.com/nginx/unit-wasm/blob/main/API-C.md) for an
-overview of the API.
-
-## License
-
-This project is licensed under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..a13f157
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,513 @@
+C & Rust Library & Examples for Building WebAssembly Modules for NGINX Unit
+===========================================================================
+
+This provides a C library (lbunit-wasm) and Rust crates based on that
+library to aid in the creation of WebAssembly modules in C and Rust.
+
+It also has some demo WebAssembly modules written in C and Rust.
+
+1. `C & Rust Library & Examples for Building WebAssembly Modules for
+ NGINX
+ Unit <#c---rust-library---examples-for-building-webassembly-modules-for-nginx-unit>`__
+2. `Repository Layout <#repository-layout>`__
+3. `Setup a Suitable Environment <#setup-a-suitable-environment>`__
+
+ 1. `Fedora <#fedora>`__
+ 2. `Debian / Ubuntu <#debian--ubuntu>`__
+
+4. `Quickstart in Developing Rust WebAssembly Modules for
+ Unit <#quickstart-in-developing-rust-webassembly-modules-for-unit>`__
+5. `Working With the Repository <#working-with-the-repository>`__
+6. `Using With Unit <#using-with-unit>`__
+7. `Consuming the C Library <#consuming-the-c-library>`__
+8. `License <#license>`__
+
+Repository Layout
+-----------------
+
+**src/c** contains the main libunit-wasm library.
+
+**src/rust** contains the rust version of the above.
+
+**examples/c** contains some demo WebAssembly modules that show both the
+raw interface to Unit (\*-raw.c) and also the use of libunit-wasm
+(luw-\*.c).
+
+**examples/rust** contains rust versions of the above C demo modules and
+more.
+
+**examples/docker** contains docker files for building Unit with
+WebAssembly support and the C examples.
+
+Setup a Suitable Environment
+----------------------------
+
+To make full use of this repository you will require numerous
+tools/packages.
+
+Exactly what you need and how to get it will depend on your Operating
+System.
+
+This has been primarily developed and tested on Fedora & Ubuntu Linux.
+
+Fedora
+~~~~~~
+
+On Fedora make sure you have the following installed
+
+::
+
+ # dnf install make clang llvm compiler-rt lld wasi-libc-devel \
+ wasi-libc-static cargo rust rustfmt rust-std-static \
+ rust-std-static-wasm32-unknown-unknown \
+ rust-std-static-wasm32-wasi
+
+One last item you will need is the libclang wasm32-wasi runtime library,
+this can be done with
+
+::
+
+ # wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | tar --strip-components=1 -xvzf - -C $(dirname $(clang -print-runtime-dir))
+
+This will install the following, path may vary slightly
+
+::
+
+ /usr/lib64/clang/16/lib/wasi/libclang_rt.builtins-wasm32.a
+
+The above should also work (perhaps with slight alterations) on recent
+CentOS/RHEL etc…
+
+**NOTE:** If you get a major Clang version update, you may need to
+repeat that last task.
+
+Debian / Ubuntu
+~~~~~~~~~~~~~~~
+
+Install the following as normal
+
+::
+
+ # apt install wasi-libc make clang llvm lld
+
+For the rest you will likely need to use `rustup <https://rustup.rs>`__.
+Caveat Emptor.
+
+After you’ve completed the *rustup* installation by following the on
+screen instructions as yourself (defaults are fine), do the following
+
+.. code:: shell
+
+ $ rustup target add wasm32-wasi
+
+You will also need to grab the wasi-sysroot, this is essentially a C
+library targeting WebAssembly (it is based partly on cloudlibc and musl
+libc) and is required for building server side WebAssembly modules.
+
+It’s up to you where you put this.
+
+.. code:: shell
+
+ $ wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/wasi-sysroot-20.0.tar.gz | tar -xzf -
+
+And finally similarly as Fedora (this requires a recentish clang)
+
+::
+
+ # wget -O- https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-20/libclang_rt.builtins-wasm32-wasi-20.0.tar.gz | tar --strip-components=1 -xvzf - -C $(dirname $(clang -print-runtime-dir))
+
+Quickstart in Developing Rust WebAssembly Modules for Unit
+----------------------------------------------------------
+
+1) Setup a suitable build environment as above.
+
+2) Create a new rust project
+
+.. code:: shell
+
+ $ cargo init --lib my-wasm-example
+
+3) Add the `unit-wasm crate <https://crates.io/crates/unit-wasm>`__ as
+ dependency
+
+.. code:: shell
+
+ $ cd my-wasm-example
+ $ cargo add unit-wasm
+
+4) Set the crate type
+
+.. code:: shell
+
+ $ printf '\n[lib]\ncrate-type = ["cdylib"]\n' >>Cargo.toml
+
+5) Create an example application
+
+To do this you can simply take a copy of our echo-request demo in this
+repository
+
+.. code:: shell
+
+ $ wget -O src/lib.rs https://raw.githubusercontent.com/nginx/unit-wasm/main/examples/rust/echo-request/src/lib.rs
+
+6) Build it!
+
+.. code:: shell
+
+ $ cargo build --target wasm32-wasi
+
+You should now have a *target/wasm32-wasi/debug/my_wasm_example.wasm*
+file (yes, hyphens will be turned to underscores)
+
+You can now use this in Unit with the following config
+
+.. code:: json
+
+ {
+ "listeners": {
+ "[::1]:8888": {
+ "pass": "applications/my-wasm-example"
+ }
+ },
+
+ "applications": {
+ "my-wasm-example": {
+ "type": "wasm",
+ "module": "/path/to/my-wasm-example/target/wasm32-wasi/debug/my_wasm_example.wasm",
+ "request_handler": "uwr_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "module_init_handler": "uwr_module_init_handler",
+ "module_end_handler": "uwr_module_end_handler"
+ }
+ }
+ }
+
+and curl command
+
+.. code:: shell
+
+ $ curl http://localhost:8888/
+
+7) Start writing your own Wasm modules in Rust!
+
+To help you get started, you can check out the Rust examples under
+`examples/rust <https://github.com/nginx/unit-wasm/tree/main/examples/rust>`__
+and also the
+`API-Rust.md <https://github.com/nginx/unit-wasm/blob/main/API-Rust.md>`__
+for an overview of the API.
+
+Working With the Repository
+---------------------------
+
+The project uses good old *make(1)* as the build system.
+
+Typing *make help* will show the list of available targets and the
+various make variables you can set. E.g
+
+::
+
+ $ make help
+ Available Targets:
+ default /
+ libunit-wasm - Builds libunit-wasm C library
+ examples - Builds the above as well as C examples
+ examples-raw - Builds raw (non libunit-wasm) C examples
+ rust - Builds the libunit-wasm rust crate
+ examples-rust _ Builds the above and rust examples
+ all - Builds all the above
+ docker - Builds demo docker images
+ clean - Removes auto generated artifacts
+ tags - Generate ctags
+
+ Variables:
+ make CC= - Specify compiler to use
+ Defaults to clang
+ make WASI_SYSROOT= - Specify the path to the WASI sysroot
+ Defaults to autodetected
+ make V=1 - Enables verbose output
+ make D=1 - Enables debug builds (-O0)
+ make E=1 - Enables Werror
+
+If you have previously followed the steps outlined above in `Setup a
+Suitable Environment <#setup-a-suitable-environment>`__
+
+You can build the libunit-wasm C library, C example Wasm modules, the
+Rust crates that provides Rust bindings for the libunit-wasm and the
+Rust example Wasm modules.
+
+E.g
+
+.. code:: shell
+
+ $ make # Build just the C library
+ $ make examples # Build the C library and C examples
+ $ make rust # Build the Rust crates
+ $ make examples-rust # Build the Rust examples
+ $ make all # Build all the above
+
+The C and Rust example Wasm modules will be located at
+
+::
+
+ examples/c/luw-echo-request.wasm
+ examples/c/luw-upload-reflector.wasm
+ examples/rust/echo-request/target/wasm32-wasi/debug/rust_echo_request.wasm
+ examples/rust/hello-world/target/wasm32-wasi/debug/rust_hello_world.wasm
+ examples/rust/upload-reflector/target/wasm32-wasi/debug/rust_upload_reflector.wasm
+
+**NOTE:** To build the C library and examples you will need to specify
+the wasi-sysroot.
+
+E.g
+
+.. code:: shell
+
+ $ make WASI_SYSROOT=/path/to/wasi-sysroot all
+
+**However** if you are on Fedora and installed the \_wasi-\*\_ packages
+listed above in the `Setup a Suitable Environment <#fedora>`__ then the
+wasi-sysroot path will be autodetected and set by the Makefile. You can
+override the autodetection by explicitly specifying it as above.
+
+Using With Unit
+---------------
+
+If you have all the above built, you are now ready to test it out with
+Unit.
+
+We won’t go into the details of building Unit from source and enabling
+the Unit WebAssembly language module here (see the
+`HOWTO.md <https://github.com/nginx/unit-wasm/blob/main/HOWTO.md>`__ in
+the repository root for more details) but will instead assume you
+already have a Unit with the WebAssembly language module already
+running, perhaps installed via a package.
+
+Create the following Unit config (editing the module paths as
+appropriate)
+
+.. code:: json
+
+ {
+ "listeners": {
+ "[::1]:8888": {
+ "pass": "routes"
+ }
+ },
+
+ "settings": {
+ "http": {
+ "max_body_size": 8589934592
+ }
+ },
+
+ "routes": [
+ {
+ "match": {
+ "uri": "/echo*"
+ },
+ "action": {
+ "pass": "applications/luw-echo-request"
+ }
+ },
+ {
+ "match": {
+ "uri": "/upload*"
+ },
+ "action": {
+ "pass": "applications/luw-upload-reflector"
+ }
+ },
+ {
+ "match": {
+ "uri": "/large-upload*"
+ },
+ "action": {
+ "pass": "applications/large-upload"
+ }
+ },
+ {
+ "match": {
+ "uri": "/rust-echo*"
+ },
+ "action": {
+ "pass": "applications/rust-echo-request"
+ }
+ },
+ {
+ "match": {
+ "uri": "/rust-upload*"
+ },
+ "action": {
+ "pass": "applications/rust-upload-reflector"
+ }
+ },
+ {
+ "match": {
+ "uri": "/rust-large-upload*"
+ },
+ "action": {
+ "pass": "applications/rust-large-upload"
+ }
+ },
+ {
+ "match": {
+ "uri": "/rust-hello-world*"
+ },
+ "action": {
+ "pass": "applications/rust-hello-world"
+ }
+ }
+ ],
+
+ "applications": {
+ "luw-echo-request": {
+ "type": "wasm",
+ "module": "/path/to/unit-wasm/examples/c/luw-echo-request.wasm",
+ "request_handler": "luw_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "module_init_handler": "luw_module_init_handler",
+ "module_end_handler": "luw_module_end_handler"
+ },
+ "luw-upload-reflector": {
+ "type": "wasm",
+ "module": "/path/to/unit-wasm/examples/c/luw-upload-reflector.wasm",
+ "request_handler": "luw_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "request_end_handler": "luw_request_end_handler",
+ "response_end_handler": "luw_response_end_handler"
+ },
+ "large-upload": {
+ "type": "wasm",
+ "module": "/path/to/unit-wasm/examples/c/large-upload.wasm",
+ "request_handler": "luw_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "module_init_handler": "luw_module_init_handler",
+ "module_end_handler": "luw_module_end_handler",
+ "response_end_handler": "luw_response_end_handler",
+ "access": {
+ "filesystem": [
+ "/var/tmp"
+ ]
+ }
+ },
+ "rust-echo-request": {
+ "type": "wasm",
+ "module": "/path/to/unit-wasm/examples/rust/echo-request/target/wasm32-wasi/debug/rust_echo_request.wasm",
+ "request_handler": "uwr_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "module_init_handler": "uwr_module_init_handler",
+ "module_end_handler": "uwr_module_end_handler"
+ },
+ "rust-upload-reflector": {
+ "type": "wasm",
+ "module": "/path/to/unit-wasm/examples/rust/upload-reflector/rust_upload_reflector.wasm",
+ "request_handler": "uwr_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "request_end_handler": "uwr_request_end_handler",
+ "response_end_handler": "uwr_response_end_handler"
+ },
+ "rust-large-upload": {
+ "type": "wasm",
+ "module": "/path/to/src/unit-wasm/examples/rust/large-upload/target/wasm32-wasi/debug/rust_large_upload.wasm",
+ "request_handler": "uwr_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler",
+ "module_init_handler": "uwr_module_init_handler",
+ "module_end_handler": "uwr_module_end_handler",
+ "response_end_handler": "uwr_response_end_handler",
+ "access": {
+ "filesystem": [
+ "/var/tmp"
+ ]
+ }
+ },
+ "rust-hello-world": {
+ "type": "wasm",
+ "module": "/path/to/unit-wasm/examples/rust/hello-world/target/wasm32-wasi/debug/rust_hello_world.wasm",
+ "request_handler": "uwr_request_handler",
+ "malloc_handler": "luw_malloc_handler",
+ "free_handler": "luw_free_handler"
+ }
+ }
+ }
+
+Load this config then you should be ready to try it.
+
+::
+
+ $ curl -X POST -d "Hello World" --cookie "mycookie=hmmm" http://localhost:8888/echo/?q=a
+ *** Welcome to WebAssembly on Unit! [libunit-wasm (0.1.0/0x00010000)] ***
+
+ [Request Info]
+ REQUEST_PATH = /echo/?q=a
+ METHOD = POST
+ VERSION = HTTP/1.1
+ QUERY = q=a
+ REMOTE = ::1
+ LOCAL_ADDR = ::1
+ LOCAL_PORT = 8080
+ SERVER_NAME = localhost
+
+ [Request Headers]
+ Host = localhost:8080
+ User-Agent = curl/8.0.1
+ Accept = */*
+ Cookie = mycookie=hmmm
+ Content-Length = 11
+ Content-Type = application/x-www-form-urlencoded
+
+ [POST data]
+ Hello World
+
+::
+
+ $ curl -v -X POST --data-binary @audio.flac -H "Content-Type: audio/flac" http://localhost:8888/upload-reflector/ -o wasm-test.dat
+ ...
+ > Content-Type: audio/flac
+ > Content-Length: 60406273
+ ...
+ % Total % Received % Xferd Average Speed Time Time Time Current
+ Dload Upload Total Spent Left Speed
+ 100 115M 100 57.6M 100 57.6M 47.6M 47.6M 0:00:01 0:00:01 --:--:-- 95.2M
+ ...
+ < Content-Type: audio/flac
+ < Content-Length: 60406273
+ ...
+ $ sha1sum audio.flac wasm-test.dat
+ ef5c9c228544b237022584a8ac4612005cd6263e audio.flac
+ ef5c9c228544b237022584a8ac4612005cd6263e wasm-test.dat
+
+Consuming the C Library
+-----------------------
+
+If **unit/unit-wasm.h** and **libunit.a** are installed into standard
+include/library directories then
+
+Include the libunit-wasm header file
+
+.. code:: c
+
+ ....
+ #include <unit/unit-wasm.h>
+ ...
+
+Link against libunit-wasm
+
+.. code:: shell
+
+ $ clang ... -o myapp.wasm myapp.c -lunit-wasm
+
+See `API-C.md <https://github.com/nginx/unit-wasm/blob/main/API-C.md>`__
+for an overview of the API.
+
+License
+-------
+
+This project is licensed under the `Apache License
+2.0 <https://www.apache.org/licenses/LICENSE-2.0>`__.