1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
|
/* SPDX-License-Identifier: Apache-2.0 */
/*
* Copyright (C) Andrew Clayton
* Copyright (C) F5, Inc.
*/
/*
* upload-reflector-raw.c - Raw example of writing a WASM module for use with
* Unit
*
* Download the wasi-sysroot tarball from https://github.com/WebAssembly/wasi-sdk/releases
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "unit-wasm-raw.h"
static size_t total_response_sent;
static u8 *request_buf;
__attribute__((import_module("env"), import_name("nxt_wasm_get_init_mem_size")))
u32 nxt_wasm_get_init_mem_size(void);
__attribute__((import_module("env"), import_name("nxt_wasm_response_end")))
void nxt_wasm_response_end(void);
__attribute__((import_module("env"), import_name("nxt_wasm_send_response")))
void nxt_wasm_send_response(u32 offset);
__attribute__((export_name("wasm_response_end_handler")))
void wasm_response_end_handler(void)
{
total_response_sent = 0;
}
__attribute__((export_name("wasm_request_end_handler")))
void wasm_request_end_handler(void)
{
if (!request_buf)
return;
free(request_buf);
request_buf = NULL;
}
__attribute__((export_name("wasm_free_handler")))
void wasm_free_handler(u32 addr)
{
free((void *)addr);
}
__attribute__((export_name("wasm_malloc_handler")))
u32 wasm_malloc_handler(size_t size)
{
return (u32)malloc(size);
}
static int upload_reflector(u8 *addr)
{
size_t mem_size = nxt_wasm_get_init_mem_size();
size_t rsize = sizeof(struct resp);
size_t write_bytes;
struct req *req;
struct resp *resp;
printf("==[WASM RESP]== %s:\n", __func__);
resp = (struct resp *)addr;
req = (struct req *)request_buf;
printf("==[WASM RESP]== resp@%p\n", resp);
printf("==[WASM RESP]== req@%p\n", req);
printf("==[WASM RESP]== req->content_len : %u\n", req->content_len);
resp = (struct resp *)addr;
/* Send headers */
if (total_response_sent == 0) {
const char *field;
struct hdr_field *f;
struct hdr_field *f_end;
char ct[256];
/* Try to set the Content-Type */
f_end = req->fields + req->nr_fields;
for (f = req->fields; f < f_end; f++) {
field = (const char *)(u8 *)req + f->name_offs;
if (strncasecmp(field, "Content-Type", 12) == 0) {
snprintf(ct, sizeof(ct), "%.*s", f->value_len,
(u8 *)req + f->value_offs);
break;
}
field = NULL;
}
if (!field)
sprintf(ct, "application/octet-stream");
send_headers(addr, ct, req->content_len);
}
write_bytes = req->content_sent;
if (write_bytes > mem_size - rsize)
write_bytes = mem_size - rsize;
printf("==[WASM RESP]== write_bytes : %lu\n", write_bytes);
printf("==[WASM RESP]== req->content_len : %u\n", req->content_len);
printf("==[WASM RESP]== total_response_sent : %lu\n",
total_response_sent);
printf("==[WASM RESP]== Copying (%lu) bytes of data from [%p+%lx] to "
"[%p]\n", write_bytes, req,
req->content_offs + total_response_sent, resp->data);
memcpy(resp->data,
(u8 *)req + req->content_offs + total_response_sent,
write_bytes);
total_response_sent += write_bytes;
resp->size = write_bytes;
printf("==[WASM RESP]== resp->size : %u\n", resp->size);
nxt_wasm_send_response(0);
if (total_response_sent == req->content_len) {
printf("==[WASM RESP]== All data sent. Cleaning up...\n");
total_response_sent = 0;
free(request_buf);
request_buf = NULL;
/* Tell Unit no more data to send */
nxt_wasm_response_end();
}
return 0;
}
__attribute__((export_name("wasm_request_handler")))
int wasm_request_handler(u8 *addr)
{
struct req *req = (struct req *)addr;
struct req *rb = (struct req *)request_buf;
printf("==[WASM REQ]== %s:\n", __func__);
/*
* This function _may_ be called multiple times during a single
* request if there is a large amount of data to transfer.
*
* Some useful request meta data:
*
* req->content_len contains the overall size of the POST/PUT
* data.
* req->content_sent shows how much of the body content has been
* in _this_ request.
* req->total_content_sent shows how much of it has been sent in
* total.
* req->content_offs is the offset in the passed in memory where
* the body content starts.
*
* For new requests req->request_size shows the total size of
* _this_ request, incl the req structure itself.
* For continuation requests, req->request_size is just the amount
* of new content, i.e req->content_sent
*
* When req->content_len == req->total_content_sent, that's the end
* of that request.
*/
if (!request_buf) {
/*
* 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.
*/
printf("==[WASM REQ]== malloc(%u)\n",
req->content_offs + req->content_len);
request_buf = malloc(req->content_offs + req->content_len);
/*
* Regardless of how much memory we allocated above, here
* we only want to copy the amount of data we actually
* received in this request.
*/
printf("==[WASM REQ]== req->request_size : %u\n",
req->request_size);
memcpy(request_buf, addr, req->request_size);
rb = (struct req *)request_buf;
printf("==[WASM REQ]== rb@%p\n", rb);
printf("==[WASM REQ]== request_buf@%p\n", request_buf);
printf("==[WASM REQ]== rb->content_offs : %u\n",
rb->content_offs);
printf("==[WASM REQ]== rb->content_len : %u\n",
rb->content_len);
printf("==[WASM REQ]== rb->content_sent : %u\n",
rb->content_sent);
printf("==[WASM REQ]== rb->request_size : %u\n",
rb->request_size);
} else {
memcpy(request_buf + rb->request_size, addr + req->content_offs,
req->request_size);
printf("==[WASM REQ +]== req->content_offs : %u\n",
req->content_offs);
printf("==[WASM REQ +]== req->content_sent : %u\n",
req->content_sent);
printf("==[WASM REQ +]== req->request_size : %u\n",
req->request_size);
rb->content_sent = req->content_sent;
rb->total_content_sent = req->total_content_sent;
}
upload_reflector(addr);
return 0;
}
|