mod_duktape.inl 6.8 KB

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