123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- /* This file is part of the CivetWeb web server.
- * See https://github.com/civetweb/civetweb/
- * (C) 2015-2017 by the CivetWeb authors, MIT license.
- */
- #include "duktape.h"
- /* TODO: the mg context should be added to duktape as well */
- /* Alternative: redefine a new, clean API from scratch (instead of using mg),
- * or at least do not add problematic functions. */
- /* For evaluation purposes, currently only "send" is supported.
- * All other ~50 functions will be added later. */
- /* Note: This is only experimental support, so the API may still change. */
- 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(size);
- }
- static void *
- mg_duk_mem_realloc(void *udata, void *ptr, duk_size_t newsize)
- {
- return mg_realloc(ptr, newsize);
- }
- static void
- mg_duk_mem_free(void *udata, void *ptr)
- {
- mg_free(ptr);
- }
- static void
- mg_duk_fatal_handler(duk_context *ctx, duk_errcode_t code, const char *msg)
- {
- /* Script is called "protected" (duk_peval_file), so script errors should
- * never yield in a call to this function. Maybe calls prior to executing
- * the script could raise a fatal error. */
- struct mg_connection *conn;
- duk_push_global_stash(ctx);
- duk_get_prop_string(ctx, -1, civetweb_conn_id);
- conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
- mg_cry(conn, "%s", msg);
- }
- static duk_ret_t
- duk_itf_write(duk_context *ctx)
- {
- struct mg_connection *conn;
- duk_double_t ret;
- duk_size_t len = 0;
- const char *val = duk_require_lstring(ctx, -1, &len);
- /*
- duk_push_global_stash(ctx);
- duk_get_prop_string(ctx, -1, civetweb_conn_id);
- conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
- */
- duk_push_current_function(ctx);
- duk_get_prop_string(ctx, -1, civetweb_conn_id);
- conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
- if (!conn) {
- duk_error(ctx,
- DUK_ERR_INTERNAL_ERROR,
- "function not available without connection object");
- /* probably never reached, but satisfies static code analysis */
- return DUK_RET_INTERNAL_ERROR;
- }
- ret = mg_write(conn, val, len);
- duk_push_number(ctx, ret);
- return 1;
- }
- static duk_ret_t
- duk_itf_read(duk_context *ctx)
- {
- struct mg_connection *conn;
- char buf[1024];
- int len;
- duk_push_global_stash(ctx);
- duk_get_prop_string(ctx, -1, civetweb_conn_id);
- conn = (struct mg_connection *)duk_to_pointer(ctx, -1);
- if (!conn) {
- duk_error(ctx,
- DUK_ERR_INTERNAL_ERROR,
- "function not available without connection object");
- /* probably never reached, but satisfies static code analysis */
- return DUK_RET_INTERNAL_ERROR;
- }
- len = mg_read(conn, buf, sizeof(buf));
- duk_push_lstring(ctx, buf, len);
- return 1;
- }
- static duk_ret_t
- duk_itf_getoption(duk_context *ctx)
- {
- struct mg_context *cv_ctx;
- const char *ret;
- duk_size_t len = 0;
- const char *val = duk_require_lstring(ctx, -1, &len);
- duk_push_current_function(ctx);
- duk_get_prop_string(ctx, -1, civetweb_ctx_id);
- cv_ctx = (struct mg_context *)duk_to_pointer(ctx, -1);
- if (!cv_ctx) {
- duk_error(ctx,
- DUK_ERR_INTERNAL_ERROR,
- "function not available without connection object");
- /* probably never reached, but satisfies static code analysis */
- return DUK_RET_INTERNAL_ERROR;
- }
- ret = mg_get_option(cv_ctx, val);
- if (ret) {
- duk_push_string(ctx, ret);
- } else {
- duk_push_null(ctx);
- }
- return 1;
- }
- static void
- mg_exec_duktape_script(struct mg_connection *conn, const char *script_name)
- {
- int i;
- duk_context *ctx = NULL;
- conn->must_close = 1;
- /* Create Duktape interpreter state */
- ctx = duk_create_heap(mg_duk_mem_alloc,
- mg_duk_mem_realloc,
- mg_duk_mem_free,
- NULL,
- mg_duk_fatal_handler);
- if (!ctx) {
- mg_cry(conn, "Failed to create a Duktape heap.");
- goto exec_duktape_finished;
- }
- /* Add "conn" object */
- duk_push_global_object(ctx);
- duk_push_object(ctx); /* create a new table/object ("conn") */
- duk_push_c_function(ctx, duk_itf_write, 1 /* 1 = nargs */);
- duk_push_pointer(ctx, (void *)conn);
- duk_put_prop_string(ctx, -2, civetweb_conn_id);
- duk_put_prop_string(ctx, -2, "write"); /* add function conn.write */
- duk_push_c_function(ctx, duk_itf_read, 0 /* 0 = nargs */);
- duk_push_pointer(ctx, (void *)conn);
- duk_put_prop_string(ctx, -2, civetweb_conn_id);
- duk_put_prop_string(ctx, -2, "read"); /* add function conn.read */
- duk_push_string(ctx, conn->request_info.request_method);
- duk_put_prop_string(ctx, -2, "request_method"); /* add string conn.r... */
- duk_push_string(ctx, conn->request_info.request_uri);
- duk_put_prop_string(ctx, -2, "request_uri");
- duk_push_string(ctx, conn->request_info.local_uri);
- duk_put_prop_string(ctx, -2, "uri");
- duk_push_string(ctx, conn->request_info.http_version);
- duk_put_prop_string(ctx, -2, "http_version");
- duk_push_string(ctx, conn->request_info.query_string);
- duk_put_prop_string(ctx, -2, "query_string");
- duk_push_string(ctx, conn->request_info.remote_addr);
- duk_put_prop_string(ctx, -2, "remote_addr");
- duk_push_int(ctx, conn->request_info.remote_port);
- duk_put_prop_string(ctx, -2, "remote_port");
- duk_push_int(ctx, ntohs(conn->client.lsa.sin.sin_port));
- duk_put_prop_string(ctx, -2, "server_port");
- duk_push_object(ctx); /* subfolder "conn.http_headers" */
- for (i = 0; i < conn->request_info.num_headers; i++) {
- duk_push_string(ctx, conn->request_info.http_headers[i].value);
- duk_put_prop_string(ctx, -2, conn->request_info.http_headers[i].name);
- }
- duk_put_prop_string(ctx, -2, "http_headers");
- duk_put_prop_string(ctx, -2, "conn"); /* call the table "conn" */
- /* Add "civetweb" object */
- duk_push_global_object(ctx);
- duk_push_object(ctx); /* create a new table/object ("conn") */
- duk_push_string(ctx, CIVETWEB_VERSION);
- duk_put_prop_string(ctx, -2, "version");
- duk_push_string(ctx, script_name);
- duk_put_prop_string(ctx, -2, "script_name");
- if (conn->ctx != NULL) {
- duk_push_c_function(ctx, duk_itf_getoption, 1 /* 1 = nargs */);
- duk_push_pointer(ctx, (void *)(conn->ctx));
- duk_put_prop_string(ctx, -2, civetweb_ctx_id);
- duk_put_prop_string(ctx, -2, "getoption"); /* add function conn.write */
- if (conn->ctx->systemName != NULL) {
- duk_push_string(ctx, conn->ctx->systemName);
- duk_put_prop_string(ctx, -2, "system");
- }
- }
- duk_put_prop_string(ctx, -2, "civetweb"); /* call the table "civetweb" */
- duk_push_global_stash(ctx);
- duk_push_pointer(ctx, (void *)conn);
- duk_put_prop_string(ctx, -2, civetweb_conn_id);
- if (duk_peval_file(ctx, script_name) != 0) {
- mg_cry(conn, "%s", duk_safe_to_string(ctx, -1));
- goto exec_duktape_finished;
- }
- duk_pop(ctx); /* ignore result */
- exec_duktape_finished:
- duk_destroy_heap(ctx);
- }
|