#include "duktape.h"
static const char *civetweb_conn_id = "\xFF"
"civetweb_conn";
static const char *civetweb_ctx_id = "\xFF"
"civetweb_ctx";
static void *
mg_duk_mem_alloc(void *udata, duk_size_t size)
{
return mg_malloc_ctx(size, (struct mg_context *)udata);
}
static void *
mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize)
{
return mg_realloc_ctx(ptr, newsize, (struct mg_context *)udata);
}
static void
mg_duk_mem_free(void *udata, void *ptr)
{
(void)udata;
mg_free(ptr);
}
static void
mg_duk_fatal_handler(duk_context *duk_ctx, duk_errcode_t code, const char *msg)
{
struct mg_connection *conn;
duk_push_global_stash(duk_ctx);
duk_get_prop_string(duk_ctx, -1, civetweb_conn_id);
conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1);
mg_cry(conn, "JavaScript fatal (%u): %s", (unsigned)code, msg);
}
static duk_ret_t
duk_itf_write(duk_context *duk_ctx)
{
struct mg_connection *conn;
duk_double_t ret;
duk_size_t len = 0;
const char *val = duk_require_lstring(duk_ctx, -1, &len);
duk_push_current_function(duk_ctx);
duk_get_prop_string(duk_ctx, -1, civetweb_conn_id);
conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1);
if (!conn) {
duk_error(duk_ctx,
DUK_ERR_INTERNAL_ERROR,
"function not available without connection object");
return DUK_RET_INTERNAL_ERROR;
}
ret = mg_write(conn, val, len);
duk_push_number(duk_ctx, ret);
return 1;
}
static duk_ret_t
duk_itf_read(duk_context *duk_ctx)
{
struct mg_connection *conn;
char buf[1024];
int len;
duk_push_global_stash(duk_ctx);
duk_get_prop_string(duk_ctx, -1, civetweb_conn_id);
conn = (struct mg_connection *)duk_to_pointer(duk_ctx, -1);
if (!conn) {
duk_error(duk_ctx,
DUK_ERR_INTERNAL_ERROR,
"function not available without connection object");
return DUK_RET_INTERNAL_ERROR;
}
len = mg_read(conn, buf, sizeof(buf));
duk_push_lstring(duk_ctx, buf, len);
return 1;
}
static duk_ret_t
duk_itf_getoption(duk_context *duk_ctx)
{
struct mg_context *cv_ctx;
const char *ret;
duk_size_t len = 0;
const char *val = duk_require_lstring(duk_ctx, -1, &len);
duk_push_current_function(duk_ctx);
duk_get_prop_string(duk_ctx, -1, civetweb_ctx_id);
cv_ctx = (struct mg_context *)duk_to_pointer(duk_ctx, -1);
if (!cv_ctx) {
duk_error(duk_ctx,
DUK_ERR_INTERNAL_ERROR,
"function not available without connection object");
return DUK_RET_INTERNAL_ERROR;
}
ret = mg_get_option(cv_ctx, val);
if (ret) {
duk_push_string(duk_ctx, ret);
} else {
duk_push_null(duk_ctx);
}
return 1;
}
static void
mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
{
int i;
duk_context *duk_ctx = NULL;
conn->must_close = 1;
duk_ctx = duk_create_heap(mg_duk_mem_alloc,
mg_duk_mem_realloc,
mg_duk_mem_free,
(void *)conn->ctx,
mg_duk_fatal_handler);
if (!duk_ctx) {
mg_cry(conn, "Failed to create a Duktape heap.");
goto exec_duktape_finished;
}
duk_push_global_object(duk_ctx);
duk_push_object(duk_ctx);
duk_push_c_function(duk_ctx, duk_itf_write, 1 );
duk_push_pointer(duk_ctx, (void *)conn);
duk_put_prop_string(duk_ctx, -2, civetweb_conn_id);
duk_put_prop_string(duk_ctx, -2, "write");
duk_push_c_function(duk_ctx, duk_itf_read, 0 );
duk_push_pointer(duk_ctx, (void *)conn);
duk_put_prop_string(duk_ctx, -2, civetweb_conn_id);
duk_put_prop_string(duk_ctx, -2, "read");
duk_push_string(duk_ctx, conn->request_info.request_method);
duk_put_prop_string(duk_ctx,
-2,
"request_method");
duk_push_string(duk_ctx, conn->request_info.request_uri);
duk_put_prop_string(duk_ctx, -2, "request_uri");
duk_push_string(duk_ctx, conn->request_info.local_uri);
duk_put_prop_string(duk_ctx, -2, "uri");
duk_push_string(duk_ctx, conn->request_info.http_version);
duk_put_prop_string(duk_ctx, -2, "http_version");
duk_push_string(duk_ctx, conn->request_info.query_string);
duk_put_prop_string(duk_ctx, -2, "query_string");
duk_push_string(duk_ctx, conn->request_info.remote_addr);
duk_put_prop_string(duk_ctx, -2, "remote_addr");
duk_push_int(duk_ctx, conn->request_info.remote_port);
duk_put_prop_string(duk_ctx, -2, "remote_port");
duk_push_int(duk_ctx, ntohs(conn->client.lsa.sin.sin_port));
duk_put_prop_string(duk_ctx, -2, "server_port");
duk_push_object(duk_ctx);
for (i = 0; i < conn->request_info.num_headers; i++) {
duk_push_string(duk_ctx, conn->request_info.http_headers[i].value);
duk_put_prop_string(duk_ctx,
-2,
conn->request_info.http_headers[i].name);
}
duk_put_prop_string(duk_ctx, -2, "http_headers");
duk_put_prop_string(duk_ctx, -2, "conn");
duk_push_global_object(duk_ctx);
duk_push_object(duk_ctx);
duk_push_string(duk_ctx, CIVETWEB_VERSION);
duk_put_prop_string(duk_ctx, -2, "version");
duk_push_string(duk_ctx, script_name);
duk_put_prop_string(duk_ctx, -2, "script_name");
if (conn->ctx != NULL) {
duk_push_c_function(duk_ctx, duk_itf_getoption, 1 );
duk_push_pointer(duk_ctx, (void *)(conn->ctx));
duk_put_prop_string(duk_ctx, -2, civetweb_ctx_id);
duk_put_prop_string(duk_ctx,
-2,
"getoption");
if (conn->ctx->systemName != NULL) {
duk_push_string(duk_ctx, conn->ctx->systemName);
duk_put_prop_string(duk_ctx, -2, "system");
}
}
duk_put_prop_string(duk_ctx,
-2,
"civetweb");
duk_push_global_stash(duk_ctx);
duk_push_pointer(duk_ctx, (void *)conn);
duk_put_prop_string(duk_ctx, -2, civetweb_conn_id);
if (duk_peval_file(duk_ctx, script_name) != 0) {
mg_cry(conn, "%s", duk_safe_to_string(duk_ctx, -1));
goto exec_duktape_finished;
}
duk_pop(duk_ctx);
exec_duktape_finished:
duk_destroy_heap(duk_ctx);
}