Skip to content

Commit e4a8680

Browse files
committed
examples: Add C and Rust examples of handling large uploads
The programs demonstrate handling requests with payloads larger than 4GiB which means they need to be written out to disk and so also demonstrates the use of the file-system access mechanism. Signed-off-by: Andrew Clayton <[email protected]>
1 parent c3ea7bb commit e4a8680

File tree

7 files changed

+255
-6
lines changed

7 files changed

+255
-6
lines changed

README.md

+49-3
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ repository root for more details) but will instead assume you already have a
264264
Unit with the WebAssembly language module already running, perhaps installed
265265
via a package.
266266

267-
Create the following Unit config
267+
Create the following Unit config (editing the module paths as appropriate)
268268

269269
```JSON
270270
{
@@ -276,7 +276,7 @@ Create the following Unit config
276276

277277
"settings": {
278278
"http": {
279-
"max_body_size": 1073741824
279+
"max_body_size": 8589934592
280280
}
281281
},
282282

@@ -297,6 +297,14 @@ Create the following Unit config
297297
"pass": "applications/luw-upload-reflector"
298298
}
299299
},
300+
{
301+
"match": {
302+
"uri": "/large-upload*"
303+
},
304+
"action": {
305+
"pass": "applications/large-upload"
306+
}
307+
},
300308
{
301309
"match": {
302310
"uri": "/rust-echo*"
@@ -315,7 +323,15 @@ Create the following Unit config
315323
},
316324
{
317325
"match": {
318-
"uri": "/hello-world*"
326+
"uri": "/rust-large-upload*"
327+
},
328+
"action": {
329+
"pass": "applications/rust-large-upload"
330+
}
331+
},
332+
{
333+
"match": {
334+
"uri": "/rust-hello-world*"
319335
},
320336
"action": {
321337
"pass": "applications/rust-hello-world"
@@ -342,6 +358,21 @@ Create the following Unit config
342358
"request_end_handler": "luw_request_end_handler",
343359
"response_end_handler": "luw_response_end_handler"
344360
},
361+
"large-upload": {
362+
"type": "wasm",
363+
"module": "/path/to/unit-wasm/examples/c/large-upload.wasm",
364+
"request_handler": "luw_request_handler",
365+
"malloc_handler": "luw_malloc_handler",
366+
"free_handler": "luw_free_handler",
367+
"module_init_handler": "luw_module_init_handler",
368+
"module_end_handler": "luw_module_end_handler",
369+
"response_end_handler": "luw_response_end_handler",
370+
"access": {
371+
"filesystem": [
372+
"/var/tmp"
373+
]
374+
}
375+
},
345376
"rust-echo-request": {
346377
"type": "wasm",
347378
"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
360391
"request_end_handler": "uwr_request_end_handler",
361392
"response_end_handler": "uwr_response_end_handler"
362393
},
394+
"rust-large-upload": {
395+
"type": "wasm",
396+
"module": "/path/to/src/unit-wasm/examples/rust/large-upload/target/wasm32-wasi/debug/rust_large_upload.wasm",
397+
"request_handler": "uwr_request_handler",
398+
"malloc_handler": "luw_malloc_handler",
399+
"free_handler": "luw_free_handler",
400+
"module_init_handler": "uwr_module_init_handler",
401+
"module_end_handler": "uwr_module_end_handler",
402+
"response_end_handler": "uwr_response_end_handler",
403+
"access": {
404+
"filesystem": [
405+
"/var/tmp"
406+
]
407+
}
408+
},
363409
"rust-hello-world": {
364410
"type": "wasm",
365411
"module": "/path/to/unit-wasm/examples/rust/hello-world/target/wasm32-wasi/debug/rust_hello_world.wasm",

examples/c/Makefile

+7-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ luw_deps = $(LUW_SRCDIR)/libunit-wasm.a \
1212

1313
examples: examples-luw
1414

15-
examples-luw: luw-echo-request.wasm luw-upload-reflector.wasm
15+
examples-luw: luw-echo-request.wasm \
16+
luw-upload-reflector.wasm \
17+
large-upload.wasm
1618

1719
examples-raw: echo-request-raw.wasm upload-reflector-raw.wasm
1820

@@ -36,5 +38,9 @@ upload-reflector-raw.wasm: upload-reflector-raw.c unit-wasm-raw.o
3638
$(PP_CCLNK) $(SDIR)/$@
3739
$(v)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< unit-wasm-raw.o
3840

41+
large-upload.wasm: large-upload.c $(luw_deps)
42+
$(PP_CCLNK) $(SDIR)/$@
43+
$(v)$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $< $(LIBS)
44+
3945
clean:
4046
rm -f *.wasm *.o *.gch

examples/c/large-upload.c

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/* SPDX-License-Identifier: Apache-2.0 */
2+
3+
/* examples/c/large-upload.c - Example of handling request payload larger
4+
* larger than the shared memory
5+
*
6+
* Copyright (C) Andrew Clayton
7+
* Copyright (C) F5, Inc.
8+
*/
9+
10+
#define _XOPEN_SOURCE 500
11+
12+
#define _FILE_OFFSET_BITS 64
13+
14+
#include <stdio.h>
15+
#include <stdlib.h>
16+
#include <fcntl.h>
17+
#include <unistd.h>
18+
19+
#include "unit/unit-wasm.h"
20+
21+
static luw_ctx_t ctx;
22+
static u8 *request_buf;
23+
static unsigned long long total_bytes_wrote;
24+
static int fd;
25+
26+
__luw_export_name("luw_module_end_handler")
27+
void luw_module_end_handler(void)
28+
{
29+
free(request_buf);
30+
}
31+
32+
__luw_export_name("luw_module_init_handler")
33+
void luw_module_init_handler(void)
34+
{
35+
request_buf = malloc(luw_mem_get_init_size());
36+
}
37+
38+
__luw_export_name("luw_response_end_handler")
39+
void luw_response_end_handler(void)
40+
{
41+
close(fd);
42+
total_bytes_wrote = 0;
43+
}
44+
45+
__luw_export_name("luw_request_handler")
46+
int luw_request_handler(u8 *addr)
47+
{
48+
ssize_t bytes_wrote;
49+
50+
if (total_bytes_wrote == 0) {
51+
luw_init_ctx(&ctx, addr, 0);
52+
luw_set_req_buf(&ctx, &request_buf, LUW_SRB_NONE);
53+
54+
fd = open("/var/tmp/large-file.dat", O_CREAT|O_TRUNC|O_WRONLY,
55+
0666);
56+
}
57+
58+
bytes_wrote = luw_mem_splice_file(addr, fd);
59+
if (bytes_wrote == -1)
60+
return -1;
61+
62+
total_bytes_wrote += bytes_wrote;
63+
if (total_bytes_wrote == luw_get_http_content_len(&ctx))
64+
luw_http_response_end();
65+
66+
return 0;
67+
}

examples/rust/Makefile

+8-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ include ../../shared.mk
22

33
SDIR = examples/rust
44

5-
examples: rust-echo-request rust-upload-reflector rust-hello-world
5+
examples: rust-echo-request \
6+
rust-upload-reflector \
7+
rust-hello-world \
8+
rust-large-upload
69

710
rust-echo-request: echo-request/Cargo.toml echo-request/src/lib.rs
811
$(PP_GEN) $(SDIR)/echo-request/target/wasm32-wasi/
@@ -16,6 +19,10 @@ rust-hello-world: hello-world/Cargo.toml hello-world/src/lib.rs
1619
$(PP_GEN) $(SDIR)/hello-world/target/wasm32-wasi/
1720
$(v)cd hello-world; cargo build --target=wasm32-wasi
1821

22+
rust-large-upload: large-upload/Cargo.toml large-upload/src/lib.rs
23+
$(PP_GEN) $(SDIR)/large-upload/target/wasm32-wasi/
24+
$(v)cd large-upload; cargo build --target=wasm32-wasi
25+
1926
clean:
2027
rm -f */Cargo.lock
2128
rm -rf */target

examples/rust/large-upload/Cargo.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "rust-large-upload"
3+
version = "0.2.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
unit-wasm = { path = "../../../src/rust", version = "0.2.0" }
10+
11+
[lib]
12+
crate-type = ["cdylib"]

examples/rust/large-upload/src/lib.rs

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* SPDX-License-Identifier: Apache-2.0 */
2+
3+
/*
4+
* Copyright (C) Andrew Clayton
5+
* Copyright (C) Timo Stark
6+
* Copyright (C) F5, Inc.
7+
*/
8+
9+
use unit_wasm::rusty::*;
10+
11+
use std::fs::File;
12+
use std::ptr::null_mut;
13+
14+
static mut CTX: luw_ctx_t = UWR_CTX_INITIALIZER();
15+
static mut REQUEST_BUF: *mut u8 = null_mut();
16+
static mut TOTAL_BYTES_WROTE: u64 = 0;
17+
18+
#[no_mangle]
19+
pub extern "C" fn uwr_module_end_handler() {
20+
unsafe { uwr_free(REQUEST_BUF); }
21+
}
22+
23+
#[no_mangle]
24+
pub extern "C" fn uwr_module_init_handler() {
25+
unsafe { REQUEST_BUF = uwr_malloc(uwr_mem_get_init_size()); }
26+
}
27+
28+
#[no_mangle]
29+
pub extern "C" fn uwr_response_end_handler() {
30+
unsafe { TOTAL_BYTES_WROTE = 0; }
31+
}
32+
33+
#[no_mangle]
34+
pub extern "C" fn uwr_request_handler(addr: *mut u8) -> i32 {
35+
let ctx: *mut luw_ctx_t = unsafe { &mut CTX };
36+
let mut f;
37+
let bytes_wrote: isize;
38+
let mut total = unsafe { TOTAL_BYTES_WROTE };
39+
40+
if total == 0 {
41+
uwr_init_ctx(ctx, addr, 0);
42+
uwr_set_req_buf(ctx, unsafe { &mut REQUEST_BUF }, LUW_SRB_NONE);
43+
44+
f = File::create("/var/tmp/large-file.dat").unwrap();
45+
} else {
46+
f = File::options()
47+
.append(true)
48+
.open("/var/tmp/large-file.dat")
49+
.unwrap();
50+
}
51+
52+
bytes_wrote = uwr_mem_splice_file(addr, &mut f);
53+
if bytes_wrote == -1 {
54+
return -1;
55+
}
56+
57+
total += bytes_wrote as u64;
58+
if total == uwr_get_http_content_len(ctx) {
59+
uwr_http_response_end();
60+
} else {
61+
unsafe { TOTAL_BYTES_WROTE = total };
62+
}
63+
64+
return 0;
65+
}

unit-wasm-conf.json

+47-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
"settings": {
99
"http": {
10-
"max_body_size": 1073741824
10+
"max_body_size": 8589934592
1111
}
1212
},
1313

@@ -28,6 +28,14 @@
2828
"pass": "applications/luw-upload-reflector"
2929
}
3030
},
31+
{
32+
"match": {
33+
"uri": "/large-upload*"
34+
},
35+
"action": {
36+
"pass": "applications/large-upload"
37+
}
38+
},
3139
{
3240
"match": {
3341
"uri": "/rust-echo*"
@@ -44,6 +52,14 @@
4452
"pass": "applications/rust-upload-reflector"
4553
}
4654
},
55+
{
56+
"match": {
57+
"uri": "/rust-large-upload*"
58+
},
59+
"action": {
60+
"pass": "applications/rust-large-upload"
61+
}
62+
},
4763
{
4864
"match": {
4965
"uri": "/rust-hello-world*"
@@ -73,6 +89,21 @@
7389
"request_end_handler": "luw_request_end_handler",
7490
"response_end_handler": "luw_response_end_handler"
7591
},
92+
"large-upload": {
93+
"type": "wasm",
94+
"module": "/path/to/unit-wasm/examples/c/large-upload.wasm",
95+
"request_handler": "luw_request_handler",
96+
"malloc_handler": "luw_malloc_handler",
97+
"free_handler": "luw_free_handler",
98+
"module_init_handler": "luw_module_init_handler",
99+
"module_end_handler": "luw_module_end_handler",
100+
"response_end_handler": "luw_response_end_handler",
101+
"access": {
102+
"filesystem": [
103+
"/var/tmp"
104+
]
105+
}
106+
},
76107
"rust-echo-request": {
77108
"type": "wasm",
78109
"module": "/path/to/unit-wasm/examples/rust/echo-request/target/wasm32-wasi/debug/rust_echo_request.wasm",
@@ -91,6 +122,21 @@
91122
"request_end_handler": "uwr_request_end_handler",
92123
"response_end_handler": "uwr_response_end_handler"
93124
},
125+
"rust-large-upload": {
126+
"type": "wasm",
127+
"module": "/path/to/src/unit-wasm/examples/rust/large-upload/target/wasm32-wasi/debug/rust_large_upload.wasm",
128+
"request_handler": "uwr_request_handler",
129+
"malloc_handler": "luw_malloc_handler",
130+
"free_handler": "luw_free_handler",
131+
"module_init_handler": "uwr_module_init_handler",
132+
"module_end_handler": "uwr_module_end_handler",
133+
"response_end_handler": "uwr_response_end_handler",
134+
"access": {
135+
"filesystem": [
136+
"/var/tmp"
137+
]
138+
}
139+
},
94140
"rust-hello-world": {
95141
"type": "wasm",
96142
"module": "/path/to/unit-wasm/examples/rust/hello-world/target/wasm32-wasi/debug/rust_hello_world.wasm",

0 commit comments

Comments
 (0)