diff --git a/API-C.md b/API-C.md index fad90ea..8b99870 100644 --- a/API-C.md +++ b/API-C.md @@ -48,6 +48,8 @@ C Library for creating WebAssembly modules for use with NGINX Unit. * [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) @@ -207,10 +209,10 @@ struct luw_req { u32 server_name_off; u32 server_name_len; - u32 content_off; - u32 content_len; + u64 content_len; + u64 total_content_sent; u32 content_sent; - u32 total_content_sent; + u32 content_off; u32 request_size; @@ -218,6 +220,8 @@ struct luw_req { u32 tls; + char __pad[4]; + struct luw_hdr_field fields[]; }; ``` @@ -701,11 +705,12 @@ This function returns a pointer to the start of the request body. ### luw_get_http_content_len ```C -size_t luw_get_http_content_len(const luw_ctx_t *ctx); +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 @@ -720,14 +725,14 @@ split over several calls to luw_request_handler(). ### luw_get_http_total_content_sent ```C -size_t luw_get_http_total_content_sent(const luw_ctx_t *ctx); +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_ +_Version: 0.2.0_ Prior to 0.3.0 it returned a size_t ### luw_http_is_tls @@ -867,6 +872,93 @@ int luw_request_handler(u8 *addr) } ``` +### 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 diff --git a/API-Rust.md b/API-Rust.md index 14e0f16..66e65d5 100644 --- a/API-Rust.md +++ b/API-Rust.md @@ -76,6 +76,8 @@ and there isn't a real need to create wrappers specifically for them. * [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) @@ -667,11 +669,12 @@ _Version: 0.2.0_ ### uwr_get_http_content_len ```Rust -pub fn uwr_get_http_content_len(ctx: *const luw_ctx_t) -> usize; +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 @@ -686,14 +689,14 @@ 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) -> usize; +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_ +_Version: 0.2.0_ Prior to 0.3.0 it returned a usize ### uwr_http_is_tls @@ -836,6 +839,70 @@ pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 { } ``` +### 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 = unsafe { &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, unsafe { &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 diff --git a/README.md b/README.md index 286551a..76dec73 100644 --- a/README.md +++ b/README.md @@ -264,7 +264,7 @@ 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 +Create the following Unit config (editing the module paths as appropriate) ```JSON { @@ -276,7 +276,7 @@ Create the following Unit config "settings": { "http": { - "max_body_size": 1073741824 + "max_body_size": 8589934592 } }, @@ -297,6 +297,14 @@ Create the following Unit config "pass": "applications/luw-upload-reflector" } }, + { + "match": { + "uri": "/large-upload*" + }, + "action": { + "pass": "applications/large-upload" + } + }, { "match": { "uri": "/rust-echo*" @@ -315,7 +323,15 @@ Create the following Unit config }, { "match": { - "uri": "/hello-world*" + "uri": "/rust-large-upload*" + }, + "action": { + "pass": "applications/rust-large-upload" + } + }, + { + "match": { + "uri": "/rust-hello-world*" }, "action": { "pass": "applications/rust-hello-world" @@ -342,6 +358,21 @@ Create the following Unit config "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", @@ -360,6 +391,21 @@ Create the following Unit config "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", diff --git a/examples/c/Makefile b/examples/c/Makefile index 1b10269..0b0fc31 100644 --- a/examples/c/Makefile +++ b/examples/c/Makefile @@ -12,7 +12,9 @@ luw_deps = $(LUW_SRCDIR)/libunit-wasm.a \ examples: examples-luw -examples-luw: luw-echo-request.wasm luw-upload-reflector.wasm +examples-luw: luw-echo-request.wasm \ + luw-upload-reflector.wasm \ + large-upload.wasm examples-raw: echo-request-raw.wasm upload-reflector-raw.wasm @@ -36,5 +38,9 @@ upload-reflector-raw.wasm: upload-reflector-raw.c unit-wasm-raw.o $(PP_CCLNK) $(SDIR)/$@ $(v)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< unit-wasm-raw.o +large-upload.wasm: large-upload.c $(luw_deps) + $(PP_CCLNK) $(SDIR)/$@ + $(v)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS) + clean: rm -f *.wasm *.o *.gch diff --git a/examples/c/large-upload.c b/examples/c/large-upload.c new file mode 100644 index 0000000..9d89298 --- /dev/null +++ b/examples/c/large-upload.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* examples/c/large-upload.c - Example of handling request payload larger + * larger than the shared memory + * + * Copyright (C) Andrew Clayton + * Copyright (C) F5, Inc. + */ + +#define _XOPEN_SOURCE 500 + +#define _FILE_OFFSET_BITS 64 + +#include +#include +#include +#include + +#include "unit/unit-wasm.h" + +static luw_ctx_t ctx; +static u8 *request_buf; +static unsigned long long total_bytes_wrote; +static int fd; + +__luw_export_name("luw_module_end_handler") +void luw_module_end_handler(void) +{ + free(request_buf); +} + +__luw_export_name("luw_module_init_handler") +void luw_module_init_handler(void) +{ + request_buf = malloc(luw_mem_get_init_size()); +} + +__luw_export_name("luw_response_end_handler") +void luw_response_end_handler(void) +{ + close(fd); + total_bytes_wrote = 0; +} + +__luw_export_name("luw_request_handler") +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; +} diff --git a/examples/c/luw-upload-reflector.c b/examples/c/luw-upload-reflector.c index 5abce9f..f32b603 100644 --- a/examples/c/luw-upload-reflector.c +++ b/examples/c/luw-upload-reflector.c @@ -53,7 +53,7 @@ static int upload_reflector(luw_ctx_t *ctx) const char *ct = luw_http_hdr_get_value(ctx, "Content-Type"); char clen[32]; - snprintf(clen, sizeof(clen), "%lu", + snprintf(clen, sizeof(clen), "%llu", luw_get_http_content_len(ctx)); luw_http_init_headers(ctx, 2, 0); diff --git a/examples/rust/Makefile b/examples/rust/Makefile index a000c9c..3d2570d 100644 --- a/examples/rust/Makefile +++ b/examples/rust/Makefile @@ -2,7 +2,10 @@ include ../../shared.mk SDIR = examples/rust -examples: rust-echo-request rust-upload-reflector rust-hello-world +examples: rust-echo-request \ + rust-upload-reflector \ + rust-hello-world \ + rust-large-upload rust-echo-request: echo-request/Cargo.toml echo-request/src/lib.rs $(PP_GEN) $(SDIR)/echo-request/target/wasm32-wasi/ @@ -16,6 +19,10 @@ rust-hello-world: hello-world/Cargo.toml hello-world/src/lib.rs $(PP_GEN) $(SDIR)/hello-world/target/wasm32-wasi/ $(v)cd hello-world; cargo build --target=wasm32-wasi +rust-large-upload: large-upload/Cargo.toml large-upload/src/lib.rs + $(PP_GEN) $(SDIR)/large-upload/target/wasm32-wasi/ + $(v)cd large-upload; cargo build --target=wasm32-wasi + clean: rm -f */Cargo.lock rm -rf */target diff --git a/examples/rust/large-upload/Cargo.toml b/examples/rust/large-upload/Cargo.toml new file mode 100644 index 0000000..b74192e --- /dev/null +++ b/examples/rust/large-upload/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rust-large-upload" +version = "0.2.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +unit-wasm = { path = "../../../src/rust", version = "0.2.0" } + +[lib] +crate-type = ["cdylib"] diff --git a/examples/rust/large-upload/src/lib.rs b/examples/rust/large-upload/src/lib.rs new file mode 100644 index 0000000..a59bdb3 --- /dev/null +++ b/examples/rust/large-upload/src/lib.rs @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: Apache-2.0 */ + +/* + * Copyright (C) Andrew Clayton + * Copyright (C) Timo Stark + * Copyright (C) F5, Inc. + */ + +use unit_wasm::rusty::*; + +use std::fs::File; +use std::ptr::null_mut; + +static mut CTX: luw_ctx_t = UWR_CTX_INITIALIZER(); +static mut REQUEST_BUF: *mut u8 = null_mut(); +static mut TOTAL_BYTES_WROTE: u64 = 0; + +#[no_mangle] +pub extern "C" fn uwr_module_end_handler() { + unsafe { uwr_free(REQUEST_BUF); } +} + +#[no_mangle] +pub extern "C" fn uwr_module_init_handler() { + unsafe { REQUEST_BUF = uwr_malloc(uwr_mem_get_init_size()); } +} + +#[no_mangle] +pub extern "C" fn uwr_response_end_handler() { + unsafe { TOTAL_BYTES_WROTE = 0; } +} + +#[no_mangle] +pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 { + let ctx: *mut luw_ctx_t = unsafe { &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, unsafe { &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) { + uwr_http_response_end(); + } else { + unsafe { TOTAL_BYTES_WROTE = total }; + } + + return 0; +} diff --git a/examples/rust/upload-reflector/src/lib.rs b/examples/rust/upload-reflector/src/lib.rs index 753ea48..ac48b56 100644 --- a/examples/rust/upload-reflector/src/lib.rs +++ b/examples/rust/upload-reflector/src/lib.rs @@ -65,7 +65,8 @@ pub fn upload_reflector(ctx: *mut luw_ctx_t) -> i32 { uwr_http_send_response(ctx); - if unsafe { TOTAL_RESPONSE_SENT == uwr_get_http_content_len(ctx) } { + if unsafe { TOTAL_RESPONSE_SENT == uwr_get_http_content_len(ctx) as usize } + { // Tell Unit no more data to send uwr_http_response_end(); } diff --git a/src/c/include/unit/unit-wasm.h b/src/c/include/unit/unit-wasm.h index c870e30..c7625de 100644 --- a/src/c/include/unit/unit-wasm.h +++ b/src/c/include/unit/unit-wasm.h @@ -84,6 +84,15 @@ typedef enum { LUW_HTTP_GATEWAY_TIMEOUT = 504, } luw_http_status_t; +#if !defined(__DEFINED_ssize_t) +/* + * Match the typedef from wasm32-wasi/include/bits/alltypes.h + * without requiring the wasi-sysroot for building the rust + * stuff. + */ +typedef long ssize_t; +#endif + struct luw_hdr_field { u32 name_off; u32 name_len; @@ -109,10 +118,10 @@ struct luw_req { u32 server_name_off; u32 server_name_len; - u32 content_off; - u32 content_len; + u64 content_len; + u64 total_content_sent; u32 content_sent; - u32 total_content_sent; + u32 content_off; u32 request_size; @@ -120,6 +129,8 @@ struct luw_req { u32 tls; + char __pad[4]; + struct luw_hdr_field fields[]; }; @@ -220,9 +231,9 @@ extern const char *luw_get_http_local_addr(const luw_ctx_t *ctx); extern const char *luw_get_http_local_port(const luw_ctx_t *ctx); extern const char *luw_get_http_server_name(const luw_ctx_t *ctx); extern const u8 *luw_get_http_content(const luw_ctx_t *ctx); -extern size_t luw_get_http_content_len(const luw_ctx_t *ctx); +extern u64 luw_get_http_content_len(const luw_ctx_t *ctx); extern size_t luw_get_http_content_sent(const luw_ctx_t *ctx); -extern size_t luw_get_http_total_content_sent(const luw_ctx_t *ctx); +extern u64 luw_get_http_total_content_sent(const luw_ctx_t *ctx); extern bool luw_http_is_tls(const luw_ctx_t *ctx); extern void luw_http_hdr_iter(luw_ctx_t *ctx, bool (*luw_http_hdr_iter_func)(luw_ctx_t *ctx, @@ -236,6 +247,8 @@ extern size_t luw_get_response_data_size(const luw_ctx_t *ctx); extern int luw_mem_writep(luw_ctx_t *ctx, const char *fmt, ...); extern size_t luw_mem_writep_data(luw_ctx_t *ctx, const u8 *src, size_t size); extern void luw_req_buf_append(luw_ctx_t *ctx, const u8 *src); +extern void luw_req_buf_copy(luw_ctx_t *ctx, const u8 *src); +extern ssize_t luw_mem_splice_file(const u8 *src, int fd); extern size_t luw_mem_fill_buf_from_req(luw_ctx_t *ctx, size_t from); extern void luw_mem_reset(luw_ctx_t *ctx); extern void luw_http_set_response_status(luw_http_status_t status); diff --git a/src/c/libunit-wasm.c b/src/c/libunit-wasm.c index 165dcd7..1b36cf9 100644 --- a/src/c/libunit-wasm.c +++ b/src/c/libunit-wasm.c @@ -14,10 +14,16 @@ #include #include #include +#include #include #include "unit/unit-wasm.h" +#define MIN(a, b) \ + ({ __typeof__(a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + /* * Some handlers are required some are optional. * @@ -196,7 +202,7 @@ const u8 *luw_get_http_content(const luw_ctx_t *ctx) } /* Returns the size of the overall content length */ -size_t luw_get_http_content_len(const luw_ctx_t *ctx) +u64 luw_get_http_content_len(const luw_ctx_t *ctx) { return ctx->req->content_len; } @@ -208,7 +214,7 @@ size_t luw_get_http_content_sent(const luw_ctx_t *ctx) } /* Returns the size of the overall content sent so far */ -size_t luw_get_http_total_content_sent(const luw_ctx_t *ctx) +u64 luw_get_http_total_content_sent(const luw_ctx_t *ctx) { return ctx->req->total_content_sent; } @@ -304,6 +310,40 @@ void luw_req_buf_append(luw_ctx_t *ctx, const u8 *src) ctx->req->total_content_sent = req->total_content_sent; } +/* Copy data from the request to the previously setup request_buffer. */ +void luw_req_buf_copy(luw_ctx_t *ctx, const u8 *src) +{ + struct luw_req *req = (struct luw_req *)src; + + memcpy(ctx->reqp + ctx->req->content_off, src + req->content_off, + req->request_size); + ctx->req->content_sent = req->content_sent; + ctx->req->total_content_sent = req->total_content_sent; +} + +/* Copy data from the request to a given file-descriptor. */ +ssize_t luw_mem_splice_file(const u8 *src, int fd) +{ + struct luw_req *req = (struct luw_req *)src; + size_t written = 0; + size_t bytes_splice = 1024 * 128; /* It's what cp(1) uses */ + + do { + ssize_t bytes_wrote; + + bytes_splice = MIN(bytes_splice, req->content_sent - written); + + bytes_wrote = write(fd, src + req->content_off + written, + bytes_splice); + if (bytes_wrote == -1) + return -1; + + written += bytes_wrote; + } while (written < req->content_sent); + + return written; +} + /* * Convenience function to fill the response buffer with data from * the request buffer. diff --git a/src/rust/unit-wasm-sys/rusty.rs b/src/rust/unit-wasm-sys/rusty.rs index 5d1fbad..8132ef0 100644 --- a/src/rust/unit-wasm-sys/rusty.rs +++ b/src/rust/unit-wasm-sys/rusty.rs @@ -8,6 +8,8 @@ use std::ffi::c_char; use std::ffi::c_void; use std::ffi::CStr; +use std::fs::File; +use std::os::fd::{AsRawFd, RawFd}; use std::ptr::null_mut; use std::slice; use std::str; @@ -95,7 +97,7 @@ pub fn uwr_get_http_server_name(ctx: *const luw_ctx_t) -> &'static str { C2S!(luw_get_http_server_name(ctx)) } -pub fn uwr_get_http_content_len(ctx: *const luw_ctx_t) -> usize { +pub fn uwr_get_http_content_len(ctx: *const luw_ctx_t) -> u64 { unsafe { luw_get_http_content_len(ctx) } } @@ -103,7 +105,7 @@ pub fn uwr_get_http_content_sent(ctx: *const luw_ctx_t) -> usize { unsafe { luw_get_http_content_sent(ctx) } } -pub fn uwr_get_http_total_content_sent(ctx: *const luw_ctx_t) -> usize { +pub fn uwr_get_http_total_content_sent(ctx: *const luw_ctx_t) -> u64 { unsafe { luw_get_http_total_content_sent(ctx) } } @@ -115,7 +117,7 @@ pub fn uwr_get_http_content_str(ctx: *const luw_ctx_t) -> &'static str { unsafe { let slice = slice::from_raw_parts( uwr_get_http_content(ctx), - uwr_get_http_total_content_sent(ctx), + uwr_get_http_total_content_sent(ctx).try_into().unwrap(), ); str::from_utf8(slice).unwrap() } @@ -158,9 +160,15 @@ pub fn uwr_mem_write_str(ctx: *mut luw_ctx_t, src: &str) -> usize { pub fn uwr_mem_write_buf( ctx: *mut luw_ctx_t, src: *const u8, - size: usize, + size: u64, ) -> usize { - unsafe { luw_mem_writep_data(ctx, src, size) } + /* + * We're dealing with a 32bit address space, but we allow + * size to come from the output of uwr_get_http_content_len() + * which returns a u64 to allow for larger than memory uploads. + */ + let sz = size as usize; + unsafe { luw_mem_writep_data(ctx, src, sz) } } pub fn uwr_req_buf_append(ctx: *mut luw_ctx_t, src: *const u8) { @@ -169,6 +177,17 @@ pub fn uwr_req_buf_append(ctx: *mut luw_ctx_t, src: *const u8) { } } +pub fn uwr_req_buf_copy(ctx: *mut luw_ctx_t, src: *const u8) { + unsafe { + luw_req_buf_copy(ctx, src); + } +} + +pub fn uwr_mem_splice_file(src: *const u8, f: &mut File) -> isize { + let fd: RawFd = f.as_raw_fd(); + unsafe { luw_mem_splice_file(src, fd) } +} + pub fn uwr_mem_fill_buf_from_req(ctx: *mut luw_ctx_t, from: usize) -> usize { unsafe { luw_mem_fill_buf_from_req(ctx, from) } } diff --git a/unit-wasm-conf.json b/unit-wasm-conf.json index ac17693..719cd67 100644 --- a/unit-wasm-conf.json +++ b/unit-wasm-conf.json @@ -7,7 +7,7 @@ "settings": { "http": { - "max_body_size": 1073741824 + "max_body_size": 8589934592 } }, @@ -28,6 +28,14 @@ "pass": "applications/luw-upload-reflector" } }, + { + "match": { + "uri": "/large-upload*" + }, + "action": { + "pass": "applications/large-upload" + } + }, { "match": { "uri": "/rust-echo*" @@ -44,6 +52,14 @@ "pass": "applications/rust-upload-reflector" } }, + { + "match": { + "uri": "/rust-large-upload*" + }, + "action": { + "pass": "applications/rust-large-upload" + } + }, { "match": { "uri": "/rust-hello-world*" @@ -73,6 +89,21 @@ "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", @@ -91,6 +122,21 @@ "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",