summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrew Clayton <a.clayton@nginx.com>2023-08-28 14:32:37 +0100
committerAndrew Clayton <a.clayton@nginx.com>2023-08-28 20:44:23 +0100
commitbfba32dc96d8b1183ea8925136565da5425fb5b2 (patch)
treede2ac2657bfa4b35267de345aa98c4ff7bbf1af0
parent0b1ff5207609bb2939fe70e996aa7651eac86c46 (diff)
downloadunit-wasm-bfba32dc96d8b1183ea8925136565da5425fb5b2.tar.gz
unit-wasm-bfba32dc96d8b1183ea8925136565da5425fb5b2.tar.bz2
API-Rust.md: Add a Rust 'rusty' API document
This was done by 'cp API-C.md API-Rust.md' and then adjusted as necessary. Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
-rw-r--r--API-Rust.md885
1 files changed, 885 insertions, 0 deletions
diff --git a/API-Rust.md b/API-Rust.md
new file mode 100644
index 0000000..2ce6e79
--- /dev/null
+++ b/API-Rust.md
@@ -0,0 +1,885 @@
+# '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;
+```
+
+1. ['Rusty' Rust API](#rusty-rust-api)
+2. [Macros](#macros)
+ * [Version](#version)
+ * [String Conversion](#string-conversion)
+ * [uwr_write_str!](#uwr_write_str)
+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)
+ * [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_len](#uwr_get_http_content_len)
+ * [uwr_get_http_content_sent](#uwr_get_http_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_mem_fill_buf_from_req](#uwr_mem_fill_buf_from_req)
+ * [uwr_mem_reset](#uwr_mem_reset)
+ * [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_send_headers](#uwr_http_send_headers)
+ * [uwr_http_response_end](#uwr_http_response_end)
+ * [uwr_mem_get_init_size](#uwr_mem_get_init_size)
+8. [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.
+
+## 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 is currently ignored but will likely be used to
+indicate a HTTP status code.
+
+#### 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 = unsafe { &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,
+ unsafe { &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_len
+
+```Rust
+pub fn uwr_get_http_content_len(ctx: *const luw_ctx_t) -> usize;
+```
+
+This function returns the size of the overall content. I.e Content-Length.
+
+
+### 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_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 = unsafe { &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,
+ unsafe { &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_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_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_http_content_len(ctx)),
+);
+```
+
+### 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).