]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /* This file is part of the CivetWeb web server. |
2 | * See https://github.com/civetweb/civetweb/ | |
11fdf7f2 | 3 | * (C) 2015-2017 by the CivetWeb authors, MIT license. |
7c673cae FG |
4 | */ |
5 | ||
6 | #include "duktape.h" | |
7 | ||
8 | /* TODO: the mg context should be added to duktape as well */ | |
9 | /* Alternative: redefine a new, clean API from scratch (instead of using mg), | |
10 | * or at least do not add problematic functions. */ | |
11 | /* For evaluation purposes, currently only "send" is supported. | |
12 | * All other ~50 functions will be added later. */ | |
13 | ||
14 | /* Note: This is only experimental support, so the API may still change. */ | |
15 | ||
16 | static const char *civetweb_conn_id = "\xFF" | |
17 | "civetweb_conn"; | |
18 | static const char *civetweb_ctx_id = "\xFF" | |
19 | "civetweb_ctx"; | |
20 | ||
21 | ||
22 | static void * | |
23 | mg_duk_mem_alloc(void *udata, duk_size_t size) | |
24 | { | |
11fdf7f2 | 25 | return mg_malloc_ctx(size, (struct mg_context *)udata); |
7c673cae FG |
26 | } |
27 | ||
28 | ||
29 | static void * | |
30 | mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize) | |
31 | { | |
11fdf7f2 | 32 | return mg_realloc_ctx(ptr, newsize, (struct mg_context *)udata); |
7c673cae FG |
33 | } |
34 | ||
35 | ||
36 | static void | |
37 | mg_duk_mem_free(void *udata, void *ptr) | |
38 | { | |
11fdf7f2 | 39 | (void)udata; |
7c673cae FG |
40 | mg_free(ptr); |
41 | } | |
42 | ||
43 | ||
44 | static void | |
11fdf7f2 | 45 | mg_duk_fatal_handler(duk_context *duk_ctx, duk_errcode_t code, const char *msg) |
7c673cae FG |
46 | { |
47 | /* Script is called "protected" (duk_peval_file), so script errors should | |
48 | * never yield in a call to this function. Maybe calls prior to executing | |
49 | * the script could raise a fatal error. */ | |
50 | struct mg_connection *conn; | |
51 | ||
11fdf7f2 TL |
52 | duk_push_global_stash(duk_ctx); |
53 | duk_get_prop_string(duk_ctx, -1, civetweb_conn_id); | |
54 | conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1); | |
7c673cae | 55 | |
11fdf7f2 | 56 | mg_cry(conn, "JavaScript fatal (%u): %s", (unsigned)code, msg); |
7c673cae FG |
57 | } |
58 | ||
59 | ||
60 | static duk_ret_t | |
11fdf7f2 | 61 | duk_itf_write(duk_context *duk_ctx) |
7c673cae FG |
62 | { |
63 | struct mg_connection *conn; | |
64 | duk_double_t ret; | |
65 | duk_size_t len = 0; | |
11fdf7f2 | 66 | const char *val = duk_require_lstring(duk_ctx, -1, &len); |
7c673cae FG |
67 | |
68 | /* | |
11fdf7f2 TL |
69 | duk_push_global_stash(duk_ctx); |
70 | duk_get_prop_string(duk_ctx, -1, civetweb_conn_id); | |
71 | conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1); | |
7c673cae | 72 | */ |
11fdf7f2 TL |
73 | duk_push_current_function(duk_ctx); |
74 | duk_get_prop_string(duk_ctx, -1, civetweb_conn_id); | |
75 | conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1); | |
7c673cae FG |
76 | |
77 | if (!conn) { | |
11fdf7f2 | 78 | duk_error(duk_ctx, |
7c673cae FG |
79 | DUK_ERR_INTERNAL_ERROR, |
80 | "function not available without connection object"); | |
81 | /* probably never reached, but satisfies static code analysis */ | |
82 | return DUK_RET_INTERNAL_ERROR; | |
83 | } | |
84 | ||
85 | ret = mg_write(conn, val, len); | |
86 | ||
11fdf7f2 | 87 | duk_push_number(duk_ctx, ret); |
7c673cae FG |
88 | return 1; |
89 | } | |
90 | ||
91 | ||
92 | static duk_ret_t | |
11fdf7f2 | 93 | duk_itf_read(duk_context *duk_ctx) |
7c673cae FG |
94 | { |
95 | struct mg_connection *conn; | |
96 | char buf[1024]; | |
97 | int len; | |
98 | ||
11fdf7f2 TL |
99 | duk_push_global_stash(duk_ctx); |
100 | duk_get_prop_string(duk_ctx, -1, civetweb_conn_id); | |
101 | conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1); | |
7c673cae FG |
102 | |
103 | if (!conn) { | |
11fdf7f2 | 104 | duk_error(duk_ctx, |
7c673cae FG |
105 | DUK_ERR_INTERNAL_ERROR, |
106 | "function not available without connection object"); | |
107 | /* probably never reached, but satisfies static code analysis */ | |
108 | return DUK_RET_INTERNAL_ERROR; | |
109 | } | |
110 | ||
111 | len = mg_read(conn, buf, sizeof(buf)); | |
112 | ||
11fdf7f2 | 113 | duk_push_lstring(duk_ctx, buf, len); |
7c673cae FG |
114 | return 1; |
115 | } | |
116 | ||
117 | ||
118 | static duk_ret_t | |
11fdf7f2 | 119 | duk_itf_getoption(duk_context *duk_ctx) |
7c673cae FG |
120 | { |
121 | struct mg_context *cv_ctx; | |
122 | const char *ret; | |
123 | duk_size_t len = 0; | |
11fdf7f2 | 124 | const char *val = duk_require_lstring(duk_ctx, -1, &len); |
7c673cae | 125 | |
11fdf7f2 TL |
126 | duk_push_current_function(duk_ctx); |
127 | duk_get_prop_string(duk_ctx, -1, civetweb_ctx_id); | |
128 | cv_ctx = (struct mg_context *)duk_to_pointer(duk_ctx, -1); | |
7c673cae FG |
129 | |
130 | if (!cv_ctx) { | |
11fdf7f2 | 131 | duk_error(duk_ctx, |
7c673cae FG |
132 | DUK_ERR_INTERNAL_ERROR, |
133 | "function not available without connection object"); | |
134 | /* probably never reached, but satisfies static code analysis */ | |
135 | return DUK_RET_INTERNAL_ERROR; | |
136 | } | |
137 | ||
138 | ret = mg_get_option(cv_ctx, val); | |
139 | if (ret) { | |
11fdf7f2 | 140 | duk_push_string(duk_ctx, ret); |
7c673cae | 141 | } else { |
11fdf7f2 | 142 | duk_push_null(duk_ctx); |
7c673cae FG |
143 | } |
144 | ||
145 | return 1; | |
146 | } | |
147 | ||
148 | ||
149 | static void | |
150 | mg_exec_duktape_script(struct mg_connection *conn, const char *script_name) | |
151 | { | |
152 | int i; | |
11fdf7f2 | 153 | duk_context *duk_ctx = NULL; |
7c673cae FG |
154 | |
155 | conn->must_close = 1; | |
156 | ||
157 | /* Create Duktape interpreter state */ | |
11fdf7f2 TL |
158 | duk_ctx = duk_create_heap(mg_duk_mem_alloc, |
159 | mg_duk_mem_realloc, | |
160 | mg_duk_mem_free, | |
161 | (void *)conn->ctx, | |
162 | mg_duk_fatal_handler); | |
163 | if (!duk_ctx) { | |
7c673cae FG |
164 | mg_cry(conn, "Failed to create a Duktape heap."); |
165 | goto exec_duktape_finished; | |
166 | } | |
167 | ||
168 | /* Add "conn" object */ | |
11fdf7f2 TL |
169 | duk_push_global_object(duk_ctx); |
170 | duk_push_object(duk_ctx); /* create a new table/object ("conn") */ | |
7c673cae | 171 | |
11fdf7f2 TL |
172 | duk_push_c_function(duk_ctx, duk_itf_write, 1 /* 1 = nargs */); |
173 | duk_push_pointer(duk_ctx, (void *)conn); | |
174 | duk_put_prop_string(duk_ctx, -2, civetweb_conn_id); | |
175 | duk_put_prop_string(duk_ctx, -2, "write"); /* add function conn.write */ | |
7c673cae | 176 | |
11fdf7f2 TL |
177 | duk_push_c_function(duk_ctx, duk_itf_read, 0 /* 0 = nargs */); |
178 | duk_push_pointer(duk_ctx, (void *)conn); | |
179 | duk_put_prop_string(duk_ctx, -2, civetweb_conn_id); | |
180 | duk_put_prop_string(duk_ctx, -2, "read"); /* add function conn.read */ | |
7c673cae | 181 | |
11fdf7f2 TL |
182 | duk_push_string(duk_ctx, conn->request_info.request_method); |
183 | duk_put_prop_string(duk_ctx, | |
184 | -2, | |
185 | "request_method"); /* add string conn.r... */ | |
7c673cae | 186 | |
11fdf7f2 TL |
187 | duk_push_string(duk_ctx, conn->request_info.request_uri); |
188 | duk_put_prop_string(duk_ctx, -2, "request_uri"); | |
7c673cae | 189 | |
11fdf7f2 TL |
190 | duk_push_string(duk_ctx, conn->request_info.local_uri); |
191 | duk_put_prop_string(duk_ctx, -2, "uri"); | |
7c673cae | 192 | |
11fdf7f2 TL |
193 | duk_push_string(duk_ctx, conn->request_info.http_version); |
194 | duk_put_prop_string(duk_ctx, -2, "http_version"); | |
7c673cae | 195 | |
11fdf7f2 TL |
196 | duk_push_string(duk_ctx, conn->request_info.query_string); |
197 | duk_put_prop_string(duk_ctx, -2, "query_string"); | |
7c673cae | 198 | |
11fdf7f2 TL |
199 | duk_push_string(duk_ctx, conn->request_info.remote_addr); |
200 | duk_put_prop_string(duk_ctx, -2, "remote_addr"); | |
7c673cae | 201 | |
11fdf7f2 TL |
202 | duk_push_int(duk_ctx, conn->request_info.remote_port); |
203 | duk_put_prop_string(duk_ctx, -2, "remote_port"); | |
7c673cae | 204 | |
11fdf7f2 TL |
205 | duk_push_int(duk_ctx, ntohs(conn->client.lsa.sin.sin_port)); |
206 | duk_put_prop_string(duk_ctx, -2, "server_port"); | |
7c673cae | 207 | |
11fdf7f2 | 208 | duk_push_object(duk_ctx); /* subfolder "conn.http_headers" */ |
7c673cae | 209 | for (i = 0; i < conn->request_info.num_headers; i++) { |
11fdf7f2 TL |
210 | duk_push_string(duk_ctx, conn->request_info.http_headers[i].value); |
211 | duk_put_prop_string(duk_ctx, | |
212 | -2, | |
213 | conn->request_info.http_headers[i].name); | |
7c673cae | 214 | } |
11fdf7f2 | 215 | duk_put_prop_string(duk_ctx, -2, "http_headers"); |
7c673cae | 216 | |
11fdf7f2 | 217 | duk_put_prop_string(duk_ctx, -2, "conn"); /* call the table "conn" */ |
7c673cae FG |
218 | |
219 | /* Add "civetweb" object */ | |
11fdf7f2 TL |
220 | duk_push_global_object(duk_ctx); |
221 | duk_push_object(duk_ctx); /* create a new table/object ("conn") */ | |
7c673cae | 222 | |
11fdf7f2 TL |
223 | duk_push_string(duk_ctx, CIVETWEB_VERSION); |
224 | duk_put_prop_string(duk_ctx, -2, "version"); | |
7c673cae | 225 | |
11fdf7f2 TL |
226 | duk_push_string(duk_ctx, script_name); |
227 | duk_put_prop_string(duk_ctx, -2, "script_name"); | |
7c673cae FG |
228 | |
229 | if (conn->ctx != NULL) { | |
11fdf7f2 TL |
230 | duk_push_c_function(duk_ctx, duk_itf_getoption, 1 /* 1 = nargs */); |
231 | duk_push_pointer(duk_ctx, (void *)(conn->ctx)); | |
232 | duk_put_prop_string(duk_ctx, -2, civetweb_ctx_id); | |
233 | duk_put_prop_string(duk_ctx, | |
234 | -2, | |
235 | "getoption"); /* add function conn.write */ | |
7c673cae FG |
236 | |
237 | if (conn->ctx->systemName != NULL) { | |
11fdf7f2 TL |
238 | duk_push_string(duk_ctx, conn->ctx->systemName); |
239 | duk_put_prop_string(duk_ctx, -2, "system"); | |
7c673cae FG |
240 | } |
241 | } | |
242 | ||
11fdf7f2 TL |
243 | duk_put_prop_string(duk_ctx, |
244 | -2, | |
245 | "civetweb"); /* call the table "civetweb" */ | |
7c673cae | 246 | |
11fdf7f2 TL |
247 | duk_push_global_stash(duk_ctx); |
248 | duk_push_pointer(duk_ctx, (void *)conn); | |
249 | duk_put_prop_string(duk_ctx, -2, civetweb_conn_id); | |
7c673cae | 250 | |
11fdf7f2 TL |
251 | if (duk_peval_file(duk_ctx, script_name) != 0) { |
252 | mg_cry(conn, "%s", duk_safe_to_string(duk_ctx, -1)); | |
7c673cae FG |
253 | goto exec_duktape_finished; |
254 | } | |
11fdf7f2 | 255 | duk_pop(duk_ctx); /* ignore result */ |
7c673cae FG |
256 | |
257 | exec_duktape_finished: | |
11fdf7f2 | 258 | duk_destroy_heap(duk_ctx); |
7c673cae | 259 | } |
11fdf7f2 TL |
260 | |
261 | ||
262 | /* End of mod_duktape.inl */ |