]> git.proxmox.com Git - ceph.git/blame - ceph/src/civetweb/src/mod_duktape.inl
buildsys: switch source download to quincy
[ceph.git] / ceph / src / civetweb / src / mod_duktape.inl
CommitLineData
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
16static const char *civetweb_conn_id = "\xFF"
17 "civetweb_conn";
18static const char *civetweb_ctx_id = "\xFF"
19 "civetweb_ctx";
20
21
22static void *
23mg_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
29static void *
30mg_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
36static void
37mg_duk_mem_free(void *udata, void *ptr)
38{
11fdf7f2 39 (void)udata;
7c673cae
FG
40 mg_free(ptr);
41}
42
43
44static void
11fdf7f2 45mg_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
60static duk_ret_t
11fdf7f2 61duk_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
92static duk_ret_t
11fdf7f2 93duk_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
118static duk_ret_t
11fdf7f2 119duk_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
149static void
150mg_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
257exec_duktape_finished:
11fdf7f2 258 duk_destroy_heap(duk_ctx);
7c673cae 259}
11fdf7f2
TL
260
261
262/* End of mod_duktape.inl */