Skip to content

Commit ee64ca5

Browse files
committed
libunit-wasm: Allow uploads larger than 4GiB
Currently Wasm modules are limited to a 32bit address space (until at least the memory64 work is completed). All the counters etc in the request structure were u32's. Which matched with the 32bit memory limitation. However there is really no need to not allow >4GiB uploads that can be saved off to disk or some such. To do this we need to increase the ->content_len & ->total_content_sent members to u64's and also adjust the return types of (luw,uwr}_get_http_content_len() and {luw,uwr}_get_http_total_content_sent() similarly. However because we need the request structure to have the exact same layout on 32bit (for Wasm modules) as it does on 64bit we need to re-jig the order of some of these members and add a four-byte padding member. Thus the request structure now looks like on 32bit (as shown by pahole(1)) struct luw_req { u32 method_off; /* 0 4 */ u32 method_len; /* 4 4 */ u32 version_off; /* 8 4 */ u32 version_len; /* 12 4 */ u32 path_off; /* 16 4 */ u32 path_len; /* 20 4 */ u32 query_off; /* 24 4 */ u32 query_len; /* 28 4 */ u32 remote_off; /* 32 4 */ u32 remote_len; /* 36 4 */ u32 local_addr_off; /* 40 4 */ u32 local_addr_len; /* 44 4 */ u32 local_port_off; /* 48 4 */ u32 local_port_len; /* 52 4 */ u32 server_name_off; /* 56 4 */ u32 server_name_len; /* 60 4 */ /* --- cacheline 1 boundary (64 bytes) --- */ u64 content_len; /* 64 8 */ u64 total_content_sent; /* 72 8 */ u32 content_sent; /* 80 4 */ u32 content_off; /* 84 4 */ u32 request_size; /* 88 4 */ u32 nr_fields; /* 92 4 */ u32 tls; /* 96 4 */ char __pad[4]; /* 100 4 */ struct luw_hdr_field fields[]; /* 104 0 */ /* size: 104, cachelines: 2, members: 25 */ /* last cacheline: 40 bytes */ }; and the same structure (taken from Unit) compiled as 64bit struct nxt_wasm_request_s { uint32_t method_off; /* 0 4 */ uint32_t method_len; /* 4 4 */ uint32_t version_off; /* 8 4 */ uint32_t version_len; /* 12 4 */ uint32_t path_off; /* 16 4 */ uint32_t path_len; /* 20 4 */ uint32_t query_off; /* 24 4 */ uint32_t query_len; /* 28 4 */ uint32_t remote_off; /* 32 4 */ uint32_t remote_len; /* 36 4 */ uint32_t local_addr_off; /* 40 4 */ uint32_t local_addr_len; /* 44 4 */ uint32_t local_port_off; /* 48 4 */ uint32_t local_port_len; /* 52 4 */ uint32_t server_name_off; /* 56 4 */ uint32_t server_name_len; /* 60 4 */ /* --- cacheline 1 boundary (64 bytes) --- */ uint64_t content_len; /* 64 8 */ uint64_t total_content_sent; /* 72 8 */ uint32_t content_sent; /* 80 4 */ uint32_t content_off; /* 84 4 */ uint32_t request_size; /* 88 4 */ uint32_t nfields; /* 92 4 */ uint32_t tls; /* 96 4 */ char __pad[4]; /* 100 4 */ nxt_wasm_http_field_t fields[]; /* 104 0 */ /* size: 104, cachelines: 2, members: 25 */ /* last cacheline: 40 bytes */ }; We can see the structures have the same layout, same size and no padding. We need the __pad member as otherwise I saw gcc and clang on Alpine Linux automatically add the 'packed' attribute to the structure which made the two structures not match. Link: <https://github.com/WebAssembly/memory64> Signed-off-by: Andrew Clayton <[email protected]>
1 parent 43b8401 commit ee64ca5

File tree

4 files changed

+21
-13
lines changed

4 files changed

+21
-13
lines changed

examples/c/luw-upload-reflector.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ static int upload_reflector(luw_ctx_t *ctx)
5353
const char *ct = luw_http_hdr_get_value(ctx, "Content-Type");
5454
char clen[32];
5555

56-
snprintf(clen, sizeof(clen), "%lu",
56+
snprintf(clen, sizeof(clen), "%llu",
5757
luw_get_http_content_len(ctx));
5858

5959
luw_http_init_headers(ctx, 2, 0);

src/c/include/unit/unit-wasm.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,19 @@ struct luw_req {
109109
u32 server_name_off;
110110
u32 server_name_len;
111111

112-
u32 content_off;
113-
u32 content_len;
112+
u64 content_len;
113+
u64 total_content_sent;
114114
u32 content_sent;
115-
u32 total_content_sent;
115+
u32 content_off;
116116

117117
u32 request_size;
118118

119119
u32 nr_fields;
120120

121121
u32 tls;
122122

123+
char __pad[4];
124+
123125
struct luw_hdr_field fields[];
124126
};
125127

@@ -220,9 +222,9 @@ extern const char *luw_get_http_local_addr(const luw_ctx_t *ctx);
220222
extern const char *luw_get_http_local_port(const luw_ctx_t *ctx);
221223
extern const char *luw_get_http_server_name(const luw_ctx_t *ctx);
222224
extern const u8 *luw_get_http_content(const luw_ctx_t *ctx);
223-
extern size_t luw_get_http_content_len(const luw_ctx_t *ctx);
225+
extern u64 luw_get_http_content_len(const luw_ctx_t *ctx);
224226
extern size_t luw_get_http_content_sent(const luw_ctx_t *ctx);
225-
extern size_t luw_get_http_total_content_sent(const luw_ctx_t *ctx);
227+
extern u64 luw_get_http_total_content_sent(const luw_ctx_t *ctx);
226228
extern bool luw_http_is_tls(const luw_ctx_t *ctx);
227229
extern void luw_http_hdr_iter(luw_ctx_t *ctx,
228230
bool (*luw_http_hdr_iter_func)(luw_ctx_t *ctx,

src/c/libunit-wasm.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ const u8 *luw_get_http_content(const luw_ctx_t *ctx)
196196
}
197197

198198
/* Returns the size of the overall content length */
199-
size_t luw_get_http_content_len(const luw_ctx_t *ctx)
199+
u64 luw_get_http_content_len(const luw_ctx_t *ctx)
200200
{
201201
return ctx->req->content_len;
202202
}
@@ -208,7 +208,7 @@ size_t luw_get_http_content_sent(const luw_ctx_t *ctx)
208208
}
209209

210210
/* Returns the size of the overall content sent so far */
211-
size_t luw_get_http_total_content_sent(const luw_ctx_t *ctx)
211+
u64 luw_get_http_total_content_sent(const luw_ctx_t *ctx)
212212
{
213213
return ctx->req->total_content_sent;
214214
}

src/rust/unit-wasm-sys/rusty.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,15 +95,15 @@ pub fn uwr_get_http_server_name(ctx: *const luw_ctx_t) -> &'static str {
9595
C2S!(luw_get_http_server_name(ctx))
9696
}
9797

98-
pub fn uwr_get_http_content_len(ctx: *const luw_ctx_t) -> usize {
98+
pub fn uwr_get_http_content_len(ctx: *const luw_ctx_t) -> u64 {
9999
unsafe { luw_get_http_content_len(ctx) }
100100
}
101101

102102
pub fn uwr_get_http_content_sent(ctx: *const luw_ctx_t) -> usize {
103103
unsafe { luw_get_http_content_sent(ctx) }
104104
}
105105

106-
pub fn uwr_get_http_total_content_sent(ctx: *const luw_ctx_t) -> usize {
106+
pub fn uwr_get_http_total_content_sent(ctx: *const luw_ctx_t) -> u64 {
107107
unsafe { luw_get_http_total_content_sent(ctx) }
108108
}
109109

@@ -115,7 +115,7 @@ pub fn uwr_get_http_content_str(ctx: *const luw_ctx_t) -> &'static str {
115115
unsafe {
116116
let slice = slice::from_raw_parts(
117117
uwr_get_http_content(ctx),
118-
uwr_get_http_total_content_sent(ctx),
118+
uwr_get_http_total_content_sent(ctx).try_into().unwrap(),
119119
);
120120
str::from_utf8(slice).unwrap()
121121
}
@@ -158,9 +158,15 @@ pub fn uwr_mem_write_str(ctx: *mut luw_ctx_t, src: &str) -> usize {
158158
pub fn uwr_mem_write_buf(
159159
ctx: *mut luw_ctx_t,
160160
src: *const u8,
161-
size: usize,
161+
size: u64,
162162
) -> usize {
163-
unsafe { luw_mem_writep_data(ctx, src, size) }
163+
/*
164+
* We're dealing with a 32bit address space, but we allow
165+
* size to come from the output of uwr_get_http_content_len()
166+
* which returns a u64 to allow for larger than memory uploads.
167+
*/
168+
let sz = size as usize;
169+
unsafe { luw_mem_writep_data(ctx, src, sz) }
164170
}
165171

166172
pub fn uwr_req_buf_append(ctx: *mut luw_ctx_t, src: *const u8) {

0 commit comments

Comments
 (0)