sq_mongoose.cpp 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <stdarg.h>
  5. #include <time.h>
  6. #include "squirrel.h"
  7. #include "sqstdblobimpl.h"
  8. #include "squtils.h"
  9. SQ_OPT_STRING_STRLEN();
  10. #ifdef USE_SQ_SQLITE3
  11. #include "lsqlite3.h"
  12. #endif
  13. #if defined(USE_AXTLS) || defined(USE_OPENSSL)
  14. #ifdef __cplusplus
  15. extern "C" {
  16. #endif
  17. void * SSL_CTX_new(void *);
  18. #ifdef __cplusplus
  19. }
  20. #endif
  21. #endif
  22. #define USE_MG_MD5 1
  23. #include "mongoose.h"
  24. //#include "civetweb.h"
  25. #define PRINT_FILE_LINE printf("%s %d\n", __FILE__,__LINE__);
  26. #ifdef UNUSED
  27. #elif defined(__GNUC__)
  28. # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
  29. #elif defined(__LCLINT__)
  30. # define UNUSED(x) /*@unused@*/ x
  31. #else
  32. # define UNUSED(x) x
  33. #endif
  34. #define MARK() do { \
  35. printf("%s:%d (%s)\n", __FILE__, __LINE__, __FUNCTION__); \
  36. } while (0)
  37. typedef struct SQ_Mg_Context SQ_Mg_Context;
  38. typedef struct SQ_MG_Callback SQ_MG_Callback;
  39. struct SQ_MG_Callback {
  40. size_t size;
  41. char buf[1];
  42. };
  43. static SQ_MG_Callback *SQ_MG_Callback_malloc(size_t x){
  44. SQ_MG_Callback *p = (SQ_MG_Callback *)sq_malloc(sizeof(SQ_MG_Callback)+x);
  45. if(p) p->size = x;
  46. return p;
  47. }
  48. static void SQ_MG_Callback_free(SQ_MG_Callback *p){
  49. if(p) sq_free(p, sizeof(SQ_MG_Callback)+p->size);
  50. }
  51. struct SQ_Mg_Context {
  52. HSQUIRRELVM v;
  53. struct mg_context *ctx;
  54. SQ_MG_Callback *master_plugin;
  55. SQ_MG_Callback *master_plugin_exit;
  56. SQ_MG_Callback *user_callback;
  57. SQ_MG_Callback *user_callback_setup;
  58. SQ_MG_Callback *user_callback_exit;
  59. };
  60. static const SQChar sq_mg_context_TAG[] = "sq_mg_conn_class";
  61. #define GET_mg_context_INSTANCE() \
  62. SQ_Mg_Context *self; \
  63. if((_rc_ = sq_getinstanceup(v,1,(SQUserPointer*)&self,(void*)sq_mg_context_TAG)) < 0) return _rc_;
  64. static const SQChar sq_mg_user_callback[] = "mg_user_callback";
  65. static const SQChar sq_http_request_TAG[] = "HttpRequest";
  66. #define GET_http_request_INSTANCE() \
  67. struct mg_connection *conn; \
  68. if((_rc_ = sq_getinstanceup(v,1,(SQUserPointer*)&conn,(void*)sq_http_request_TAG)) < 0) return _rc_;
  69. static SQRESULT sq_http_request_releasehook(SQUserPointer p, SQInteger size, void */*ep*/)
  70. {
  71. return 1;
  72. }
  73. static SQRESULT sq_http_request_constructor(HSQUIRRELVM v)
  74. {
  75. //SQ_FUNC_VARS_NO_TOP(v);
  76. struct mg_connection *conn = 0;
  77. sq_setinstanceup(v, 1, conn);
  78. sq_setreleasehook(v,1, sq_http_request_releasehook);
  79. return 1;
  80. }
  81. static SQRESULT
  82. sq_http_request_print(HSQUIRRELVM v)
  83. {
  84. SQ_FUNC_VARS(v);
  85. GET_http_request_INSTANCE();
  86. SQInteger i, write_count = 0;
  87. for (i = 2; i <= _top_; ++i) {
  88. sq_tostring(v, i);
  89. SQ_GET_STRING(v, -1, value);
  90. write_count += mg_write(conn, value, value_size);
  91. sq_poptop(v);
  92. }
  93. sq_pushinteger(v, write_count);
  94. return 1;
  95. }
  96. #ifdef USE_SQ_LSQLITE3
  97. static SQRESULT
  98. sq_http_request_vm_print(HSQUIRRELVM v)
  99. {
  100. GET_http_request_INSTANCE();
  101. lsqlite3_sdb_vm *svm = (lsqlite3_sdb_vm *)luaL_checkudata(v, 1,
  102. lsqlite3_sqlite_vm_meta);
  103. SQInteger idx = luaL_checkint(v,2);
  104. SQInteger len = sqlite3_column_bytes(svm->vm, idx);
  105. if(len) sq_pushinteger(v, mg_write(conn, sqlite3_column_text(svm->vm, idx), len));
  106. else sq_pushinteger(v, 0);
  107. return 1;
  108. }
  109. #endif
  110. static SQRESULT
  111. sq_http_request_write(HSQUIRRELVM v)
  112. {
  113. SQ_FUNC_VARS(v);
  114. GET_http_request_INSTANCE();
  115. SQ_GET_STRING(v, 2, buf);
  116. SQ_OPT_INTEGER(v, 3, write_size, buf_size);
  117. sq_pushinteger(v, mg_write(conn, buf, write_size));
  118. return 1;
  119. }
  120. static SQRESULT
  121. sq_http_request_read(HSQUIRRELVM v)
  122. {
  123. SQ_FUNC_VARS(v);
  124. GET_http_request_INSTANCE();
  125. SQ_OPT_INTEGER(v, 2, n, 1024*2000);
  126. if(n <= 0) return sq_throwerror(v, _SC("invalid size to read (%d)"), n);
  127. size_t rlen; /* how much to read */
  128. size_t nr; /* number of chars actually read */
  129. rlen = 8192; /* try to read that much each time */
  130. SQBlob *blob = NULL;
  131. if(_top_ > 2) {
  132. if(SQ_FAILED(sq_getinstanceup(v,3,(SQUserPointer*)&blob,(SQUserPointer)SQBlob::SQBlob_TAG)))
  133. return sq_throwerror(v,_SC("expect a blob as second parameter"));
  134. if(!blob || !blob->IsValid())
  135. return sq_throwerror(v,_SC("the blob is invalid"));
  136. } else {
  137. sq_new(blob, SQBlob);
  138. blob->Reserve(rlen);
  139. }
  140. if (((ssize_t)rlen) > n) rlen = n; /* cannot read more than asked */
  141. char *p = sq_getscratchpad(v,rlen);
  142. do {
  143. //there is a bug in axtls that can return a number bigger than the actual bytes transfered
  144. nr = mg_read(conn, p, rlen);
  145. blob->Write(p, nr);
  146. n -= nr; /* still have to read `n' chars */
  147. } while (n > 0 && nr == rlen); /* until end of count or eof */
  148. if(_top_ <= 2) {
  149. sq_pushstring(v, (const SQChar *)blob->GetBuf(), blob->Len()); /* close buffer */
  150. if(blob) sq_delete(blob, SQBlob);
  151. return 1;
  152. }
  153. return 0;
  154. }
  155. static SQRESULT
  156. sq_http_request_send_file(HSQUIRRELVM v)
  157. {
  158. SQ_FUNC_VARS_NO_TOP(v);
  159. GET_http_request_INSTANCE();
  160. SQ_GET_STRING(v, 2, file_path);
  161. mg_send_file(conn, file_path);
  162. return 0;
  163. }
  164. static SQRESULT
  165. sq_http_request_write_blob(HSQUIRRELVM v)
  166. {
  167. SQ_FUNC_VARS_NO_TOP(v);
  168. GET_http_request_INSTANCE();
  169. SQBlob *blob = NULL;
  170. { if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&blob,(SQUserPointer)SQBlob::SQBlob_TAG)))
  171. return sq_throwerror(v,_SC("invalid type tag")); }
  172. if(!blob || !blob->IsValid())
  173. return sq_throwerror(v,_SC("the blob is invalid"));
  174. sq_pushinteger(v, mg_write(conn, (const SQChar*)blob->GetBuf(), blob->Len()));
  175. return 1;
  176. }
  177. static SQRESULT
  178. sq_http_request_get_header(HSQUIRRELVM v)
  179. {
  180. SQ_FUNC_VARS_NO_TOP(v);
  181. GET_http_request_INSTANCE();
  182. SQ_GET_STRING(v, 2, name);
  183. sq_pushstring(v, mg_get_header(conn, name), -1);
  184. return 1;
  185. }
  186. static SQRESULT
  187. sq_http_request_get_cookie(HSQUIRRELVM v)
  188. {
  189. SQ_FUNC_VARS_NO_TOP(v);
  190. GET_http_request_INSTANCE();
  191. SQ_GET_STRING(v, 2, cookie_name);
  192. const char *start;
  193. int len = mg_find_cookie(conn, cookie_name, &start);
  194. if(len > 0) sq_pushstring(v, start, len-1);
  195. else sq_pushnull(v);
  196. return 1;
  197. }
  198. static SQRESULT
  199. sq_http_request_get_var(HSQUIRRELVM v)
  200. {
  201. SQ_FUNC_VARS_NO_TOP(v);
  202. GET_http_request_INSTANCE();
  203. SQ_GET_STRING(v, 2, data);
  204. SQ_GET_STRING(v, 3, name);
  205. const char *start;
  206. size_t buffer_len;
  207. int var_len = mg_find_var(data, data_size, name, &start);
  208. if(var_len > 0){
  209. buffer_len = var_len+1;
  210. char *buffer = sq_getscratchpad(v,buffer_len);
  211. if(buffer){
  212. var_len = mg_url_decode(start, var_len, buffer, buffer_len, 1);
  213. sq_pushstring(v, buffer, var_len);
  214. return 1;
  215. }
  216. }
  217. sq_pushnull(v);
  218. return 1;
  219. }
  220. static SQRESULT
  221. sq_http_request_get_conn_buf(HSQUIRRELVM v)
  222. {
  223. SQ_FUNC_VARS_NO_TOP(v);
  224. GET_http_request_INSTANCE();
  225. int buf_size;
  226. const char *buf = mg_get_conn_buf(conn, &buf_size);
  227. sq_pushstring(v, buf, buf_size);
  228. return 1;
  229. }
  230. #ifndef _WIN32_WCE
  231. static SQRESULT
  232. sq_http_request_handle_cgi_request(HSQUIRRELVM v)
  233. {
  234. SQ_FUNC_VARS_NO_TOP(v);
  235. GET_http_request_INSTANCE();
  236. SQ_GET_STRING(v, 2, prog);
  237. mg_handle_cgi_request(conn, prog);
  238. return 0;
  239. }
  240. #endif
  241. static SQRESULT
  242. sq_http_request_get_option(HSQUIRRELVM v)
  243. {
  244. SQ_FUNC_VARS_NO_TOP(v);
  245. GET_http_request_INSTANCE();
  246. SQ_GET_STRING(v, 2, name);
  247. SQ_Mg_Context *sq_mg_ctx = (SQ_Mg_Context *) mg_get_user_data(conn);
  248. sq_pushstring(v, mg_get_option(sq_mg_ctx->ctx, name), -1);
  249. return 1;
  250. }
  251. //Digest authentication functions
  252. #define MAX_USER_LEN 20
  253. #define MAX_NONCE_LEN 36 //extra bytes for zero terminator
  254. #define MAX_SESSIONS 25
  255. #define SESSION_TTL 3600
  256. #define SESSION_REQUEST_TTL 120
  257. enum e_session_state {e_session_invalid, e_session_sent_request, e_session_authorized};
  258. struct st_session_t
  259. {
  260. int state;
  261. char nonce[MAX_NONCE_LEN];
  262. char user[MAX_USER_LEN]; // Authenticated user
  263. long last_nc;
  264. time_t last_access; // last_access time
  265. long remote_ip; // Client's IP address
  266. };
  267. static struct st_session_t sessions[MAX_SESSIONS]; // Current sessions
  268. // Protects messages, sessions, last_message_id
  269. static mg_thread_mutex_t session_rwlock;
  270. //should be called only after locking session_rwlock
  271. static struct st_session_t *my_get_session_only_after_lock(const char *nonce){
  272. int i;
  273. for(i=0; i < MAX_SESSIONS; ++i){
  274. //printf("%s : %s\n", sessions[i].nonce, ah->nonce);
  275. if(strcmp(sessions[i].nonce, nonce) == 0){
  276. return &sessions[i];
  277. }
  278. }
  279. return 0;
  280. }
  281. // Check the user's password, return 1 if OK
  282. static SQBool my_check_password(const struct mg_request_info *request_info, const char *my_tmp_password)
  283. {
  284. md5_buf_t ha2, expected_response;
  285. struct mg_auth_header *ah = request_info->ah;
  286. // Some of the parameters may be NULL
  287. if (request_info->request_method == NULL ||
  288. //strcmp(ri->request_method, "PUT") == 0 ||
  289. //strcmp(ri->request_method, "DELETE") == 0 ||
  290. ah == NULL ||
  291. ah->nonce == NULL || ah->nc == NULL ||
  292. ah->cnonce == NULL || ah->qop == NULL || ah->uri == NULL ||
  293. ah->response == NULL)
  294. {
  295. return SQFalse;
  296. }
  297. // NOTE(lsm): due to a bug in MSIE, we do not compare the URI
  298. // TODO(lsm): check for authentication timeout
  299. if (// strcmp(ah->uri, conn->request_info.uri) != 0 ||
  300. strlen(ah->response) != 32
  301. )
  302. {
  303. return SQFalse;
  304. }
  305. mg_md5(ha2, request_info->request_method, ":", ah->uri, NULL);
  306. mg_md5(expected_response, my_tmp_password /*ah->ha1*/, ":", ah->nonce, ":", ah->nc,
  307. ":", ah->cnonce, ":", ah->qop, ":", ha2, NULL);
  308. SQBool result = mg_strcasecmp(ah->response, expected_response) == 0;
  309. //printf("%s : %s : %s\n", my_tmp_password, ah->response, expected_response);
  310. if(result) //lets check timeout and other issues
  311. {
  312. struct st_session_t *session_found = 0;
  313. result = SQFalse;
  314. mg_thread_mutex_lock(&session_rwlock);
  315. session_found = my_get_session_only_after_lock(ah->nonce);
  316. if(session_found)
  317. {
  318. do
  319. {
  320. //mobile ip is a pain for security
  321. if( /*(ses.remote_ip != request_info->remote_ip) ||*/
  322. ((time(NULL) - session_found->last_access) > SESSION_TTL)
  323. ) break;
  324. if(session_found->state == e_session_sent_request)
  325. {
  326. session_found->state = e_session_authorized;
  327. snprintf(session_found->user, sizeof(session_found->user), "%s", ah->user);
  328. }
  329. else if(strcmp(session_found->user, ah->user) != 0) break;
  330. long recived_nc = strtol(ah->nc, 0, 16);
  331. time_t received_time = time(NULL);
  332. /*
  333. //printf("%d : %lu : %lu : %lu : %lu\n", request_info->remote_port, ses.last_nc, recived_nc, ses.last_access, received_time);
  334. if((ses.last_nc+1) != recived_nc){
  335. //lets see if we can manage out of order sent by some browsers
  336. if((received_time - ses.last_access) > 2) break;
  337. //inside a window of 2 seconds we tolerate nc out of order
  338. if(ses.last_nc > recived_nc) recived_nc = ses.last_nc;
  339. }
  340. */
  341. session_found->last_access = received_time;
  342. session_found->last_nc = recived_nc;
  343. result = SQTrue;
  344. } while(0);
  345. if(!result){
  346. session_found->state = e_session_invalid;
  347. session_found->nonce[0] = '\0';
  348. }
  349. }
  350. else {
  351. //dbg_msg("Session not found ! : %s : %s\n", ah->nonce, request_info->uri);
  352. }
  353. mg_thread_mutex_unlock(&session_rwlock);
  354. }
  355. return result;
  356. }
  357. static SQRESULT
  358. sq_http_request_check_password(HSQUIRRELVM v)
  359. {
  360. SQ_FUNC_VARS_NO_TOP(v);
  361. GET_http_request_INSTANCE();
  362. SQ_GET_STRING(v, 2, my_tmp_password);
  363. const struct mg_request_info *request_info = mg_get_request_info(conn);
  364. sq_pushbool(v, my_check_password(request_info, my_tmp_password));
  365. return 1;
  366. }
  367. // Close user session return 1 if closed
  368. static SQBool my_close_session(const struct mg_request_info *request_info)
  369. {
  370. SQBool result = SQFalse;
  371. struct st_session_t *session_found = 0;
  372. struct mg_auth_header *ah = request_info->ah;
  373. // Some of the parameters may be NULL
  374. if (request_info->request_method == NULL ||
  375. //strcmp(ri->request_method, "PUT") == 0 ||
  376. //strcmp(ri->request_method, "DELETE") == 0 ||
  377. ah == NULL ||
  378. ah->nonce == NULL || ah->nc == NULL ||
  379. ah->cnonce == NULL || ah->qop == NULL || ah->uri == NULL ||
  380. ah->response == NULL)
  381. {
  382. return 0;
  383. }
  384. mg_thread_mutex_lock(&session_rwlock);
  385. session_found = my_get_session_only_after_lock(ah->nonce);
  386. if(session_found) {
  387. session_found->state = e_session_invalid;
  388. session_found->nonce[0] = '\0';
  389. result = SQTrue;
  390. }
  391. mg_thread_mutex_unlock(&session_rwlock);
  392. return result;
  393. }
  394. static SQRESULT
  395. sq_http_request_close_session(HSQUIRRELVM v)
  396. {
  397. SQ_FUNC_VARS_NO_TOP(v);
  398. GET_http_request_INSTANCE();
  399. const struct mg_request_info *request_info = mg_get_request_info(conn);
  400. sq_pushbool(v, my_close_session(request_info));
  401. return 1;
  402. }
  403. typedef char buf_1024_t[1024];
  404. static const char *my_encode_nonce(buf_1024_t buf, md5_buf_t md5_buf, unsigned long ip)
  405. {
  406. snprintf(buf, sizeof(buf_1024_t), "%lu:%d:%d:%lu", (unsigned long) time(NULL), rand(), rand(), ip);
  407. mg_md5(md5_buf, buf, NULL);
  408. return md5_buf;
  409. }
  410. static void my_send_authorization_request(struct mg_connection *conn,
  411. const struct mg_request_info *request_info,
  412. const char *authentication_domain,
  413. const char *nonce)
  414. {
  415. md5_buf_t md5_buf;
  416. buf_1024_t buf;
  417. int i;
  418. if (nonce == NULL)
  419. {
  420. nonce = my_encode_nonce(buf, md5_buf, (unsigned long) request_info->remote_ip);
  421. }
  422. struct st_session_t *available_session = NULL;
  423. mg_thread_mutex_lock(&session_rwlock);
  424. time_t now = time(NULL);
  425. for(int j=0; j<3; ++j)
  426. {
  427. for(i=0; i < MAX_SESSIONS; ++i){
  428. if(sessions[i].state == e_session_invalid){
  429. break;
  430. }
  431. if(sessions[i].state == e_session_sent_request){
  432. if((now - sessions[i].last_access) > SESSION_REQUEST_TTL){
  433. //if session request bigger than 2 minutes reuse it
  434. break;
  435. }
  436. }
  437. //on the second intent we will reuse idle authorized sessions
  438. if( (j > 0) && sessions[i].state == e_session_authorized){
  439. if((now - sessions[i].last_access) > (SESSION_REQUEST_TTL*5)){
  440. //if session request bigger than 10 minutes reuse it
  441. break;
  442. }
  443. }
  444. }
  445. if(i < MAX_SESSIONS){
  446. available_session = &sessions[i];
  447. available_session->state = e_session_sent_request;
  448. available_session->last_access = now;
  449. available_session->last_nc = 0;
  450. available_session->remote_ip = request_info->remote_ip;
  451. snprintf(available_session->nonce, sizeof(available_session->nonce),
  452. "%s", nonce);
  453. break;
  454. }
  455. else
  456. {
  457. nonce = my_encode_nonce(buf, md5_buf, (unsigned long) request_info->remote_ip);
  458. }
  459. }
  460. mg_thread_mutex_unlock(&session_rwlock);
  461. if(available_session) {
  462. //warning android ics/jelly bean expect realm to follow digest
  463. //otherwise it will not connect
  464. i = snprintf(buf, sizeof(buf),
  465. "HTTP/1.1 401 Unauthorized\r\n"
  466. "WWW-Authenticate: Digest realm=\"%s\", qop=\"auth\", nonce=\"%s\"\r\n"
  467. "Content-Length: 0\r\n\r\n",
  468. authentication_domain, nonce);
  469. } else {
  470. i = snprintf(buf, sizeof(buf),
  471. "HTTP/1.1 503 Service Temporary Unavailable\r\n"
  472. "Content-Length: 0\r\n\r\n");
  473. }
  474. //printf("%s", buf);
  475. mg_write(conn, buf, i);
  476. }
  477. static SQRESULT
  478. sq_http_request_send_authorization_request(HSQUIRRELVM v)
  479. {
  480. SQ_FUNC_VARS_NO_TOP(v);
  481. GET_http_request_INSTANCE();
  482. SQ_GET_STRING(v, 2, authentication_domain);
  483. const struct mg_request_info *request_info = mg_get_request_info(conn);
  484. my_send_authorization_request(conn, request_info, authentication_domain, NULL);
  485. return 0;
  486. }
  487. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_http_request_##name,nparams,tycheck}
  488. static SQRegFunction mg_http_request_methods[] =
  489. {
  490. _DECL_FUNC(constructor, 1, _SC("x")),
  491. _DECL_FUNC(print, -2, _SC("x n|s")),
  492. _DECL_FUNC(read, -2, _SC("xix")),
  493. _DECL_FUNC(write, 3, _SC("xsi")),
  494. _DECL_FUNC(write_blob, -2, _SC("xxi")),
  495. _DECL_FUNC(get_var, 3, _SC("xs")),
  496. _DECL_FUNC(get_cookie, 2, _SC("xs")),
  497. _DECL_FUNC(get_header, 2, _SC("xs")),
  498. _DECL_FUNC(send_file, 2, _SC("xs")),
  499. #ifndef _WIN32_WCE
  500. _DECL_FUNC(handle_cgi_request, 2, _SC("xs")),
  501. #endif
  502. _DECL_FUNC(get_option, 2, _SC("xs")),
  503. _DECL_FUNC(check_password, 2, _SC("xs")),
  504. _DECL_FUNC(close_session, 1, _SC("x")),
  505. _DECL_FUNC(send_authorization_request, 2, _SC("xs")),
  506. _DECL_FUNC(get_conn_buf, 1, _SC("x")),
  507. {0,0}
  508. };
  509. #undef _DECL_FUNC
  510. /***********/
  511. // helper function to extract a single mg_config value from a Lua table
  512. static void
  513. fetchfield(HSQUIRRELVM v, int idx, const char *key, char **value, const char *d)
  514. {
  515. const char *s;
  516. sq_pushstring(v, key, -1);
  517. if(sq_rawget(v, idx) == SQ_OK){
  518. if(sq_gettype(v, -1) != OT_NULL){
  519. sq_tostring(v, -1);
  520. sq_getstring(v, -1, &s);
  521. *value = mg_strdup(s);
  522. sq_pop(v, 2); //retrieved value and converted value
  523. return;
  524. }
  525. }
  526. *value = NULL;
  527. }
  528. // initializes an options string array from a Lua table
  529. static SQRESULT
  530. fetchoptions(HSQUIRRELVM v, int idx, const char **options)
  531. {
  532. struct {
  533. const char *key;
  534. const char *value;
  535. } OPTIONS[] = {
  536. { "cgi_extensions", ".cgi,.pl,.php" },
  537. { "cgi_environment", NULL },
  538. { "put_delete_passwords_file", NULL },
  539. { "cgi_interpreter", NULL },
  540. { "protect_uri", NULL },
  541. { "authentication_domain", "mydomain.com" },
  542. { "ssi_extensions", ".shtml,.shtm" },
  543. { "access_log_file", NULL },
  544. { "ssl_chain_file", NULL },
  545. { "enable_directory_listing", "yes" },
  546. { "error_log_file", NULL },
  547. { "global_passwords_file", NULL },
  548. { "index_files", "index.html,index.htm,index.cgi" },
  549. { "enable_keep_alive", "no" },
  550. { "enable_tcp_nodelay", "no" },
  551. { "access_control_list", NULL },
  552. { "max_request_size", "16384" },
  553. { "extra_mime_types", NULL },
  554. { "listening_ports", "8080" },
  555. { "document_root", "." },
  556. { "ssl_certificate", NULL },
  557. { "num_threads", "10" },
  558. { "request_timeout_ms", "30000" },
  559. { "run_as_user", NULL },
  560. { NULL, NULL }
  561. };
  562. char *value;
  563. int i, j;
  564. if(sq_gettype(v, idx) != OT_TABLE) return sq_throwerror(v, "a table is needed to retrieve options");
  565. for (i = 0, j = 0; OPTIONS[i].key; ++i) {
  566. fetchfield(v, idx, OPTIONS[i].key, &value, OPTIONS[i].value);
  567. if (NULL != value) {
  568. options[j++] = mg_strdup(OPTIONS[i].key);
  569. options[j++] = value;
  570. }
  571. }
  572. options[j] = NULL;
  573. return 0;
  574. }
  575. /***********/
  576. static const char sq_mongoose_TAG[] = "Mongoose";
  577. static SQBool show_errors_on_stdout = SQFalse;
  578. static void sq_mongoose_release_references(SQ_Mg_Context *self){
  579. SQ_MG_Callback_free(self->master_plugin);
  580. SQ_MG_Callback_free(self->master_plugin_exit);
  581. SQ_MG_Callback_free(self->user_callback);
  582. SQ_MG_Callback_free(self->user_callback_setup);
  583. SQ_MG_Callback_free(self->user_callback_exit);
  584. }
  585. static SQRESULT sq_mongoose_releasehook(SQUserPointer p, SQInteger size, void */*ep*/)
  586. {
  587. SQ_Mg_Context *self = (SQ_Mg_Context *)p;
  588. if(self){
  589. if(self->ctx){
  590. mg_stop(self->ctx);
  591. sq_mongoose_release_references(self);
  592. self->ctx = 0;
  593. }
  594. sq_free(self, sizeof(SQ_Mg_Context));
  595. }
  596. return 0;
  597. }
  598. static SQRESULT sq_mongoose_constructor(HSQUIRRELVM v)
  599. {
  600. //SQ_FUNC_VARS_NO_TOP(v);
  601. SQ_Mg_Context *sq_mg_ctx = (SQ_Mg_Context *)sq_malloc(sizeof(SQ_Mg_Context));
  602. memset(sq_mg_ctx, 0, sizeof(SQ_Mg_Context));
  603. sq_setinstanceup(v, 1, sq_mg_ctx);
  604. sq_setreleasehook(v,1, sq_mongoose_releasehook);
  605. return 1;
  606. }
  607. #define GET_mongoose_INSTANCE() \
  608. SQ_Mg_Context *self; \
  609. if((_rc_ = sq_getinstanceup(v,1,(SQUserPointer*)&self,(void*)sq_mongoose_TAG)) < 0) return _rc_;
  610. static SQRESULT
  611. sq_mongoose_show_errors_on_stdout(HSQUIRRELVM v)
  612. {
  613. SQ_FUNC_VARS_NO_TOP(v);
  614. SQ_GET_BOOL(v, 2, onOff);
  615. show_errors_on_stdout = onOff;
  616. return 0;
  617. }
  618. static SQRESULT
  619. sq_mongoose_modify_passwords_file(HSQUIRRELVM v)
  620. {
  621. SQ_FUNC_VARS_NO_TOP(v);
  622. SQ_GET_STRING(v, 2, passwords_file_name);
  623. SQ_GET_STRING(v, 3, domain);
  624. SQ_GET_STRING(v, 4, user);
  625. SQ_GET_STRING(v, 5, password);
  626. sq_pushinteger(v, mg_modify_passwords_file(passwords_file_name,
  627. domain, user, password));
  628. return 1;
  629. }
  630. static SQRESULT
  631. sq_mongoose_version(HSQUIRRELVM v)
  632. {
  633. sq_pushstring(v, mg_version(), -1);
  634. return 1;
  635. }
  636. SQInteger blob_write(SQUserPointer file,SQUserPointer p,SQInteger size);
  637. // creates a reference dispatching callbacks to squirrel functions
  638. static SQRESULT
  639. fetchcallback(HSQUIRRELVM v, const char *key, SQ_MG_Callback **sq_cb)
  640. {
  641. if(!sq_cb) return sq_throwerror(v, "inavlid SQ_MG_Callback parameter value (NULL)");
  642. if(sq_gettype(v, -1) != OT_TABLE) return sq_throwerror(v, "table expected to fetch callbacks");
  643. sq_pushstring(v, key, -1);
  644. sq_rawget(v, -2);
  645. if (sq_gettype(v, -1) == OT_CLOSURE){
  646. SQBlob b(0,8192);
  647. if(SQ_SUCCEEDED(sq_writeclosure(v,blob_write,&b))) {
  648. *sq_cb = SQ_MG_Callback_malloc(b.Len());
  649. if(*sq_cb) memcpy((*sq_cb)->buf, b.GetBuf(), b.Len());
  650. sq_poptop(v);
  651. }
  652. }
  653. else
  654. {
  655. sq_pop(v, 1);
  656. return sq_throwerror(v, "closure expected for callbacks");
  657. }
  658. return SQ_OK;
  659. }
  660. static void *
  661. user_callback_proxy(enum mg_event event,
  662. struct mg_connection *conn,
  663. const struct mg_request_info *ri);
  664. // creates a new server using a configuration table
  665. static SQRESULT
  666. sq_mongoose_start(HSQUIRRELVM v)
  667. {
  668. SQ_FUNC_VARS_NO_TOP(v);
  669. GET_mongoose_INSTANCE();
  670. _rc_ = 1; //assumes succeed
  671. const char *options[64];
  672. SQInteger i;
  673. if(self->ctx) return sq_throwerror(v, _SC("mongoose already running or stoped incorrectly"));
  674. // store the Squirrel vm for use in callback proxies
  675. self->v = v;
  676. // prepare the mg_config structure from the squirrel table argument
  677. memset(options, 0, sizeof (options));
  678. fetchoptions(v, 2, options);
  679. fetchcallback(v, "master_plugin", &self->master_plugin);
  680. fetchcallback(v, "master_plugin_exit", &self->master_plugin_exit);
  681. fetchcallback(v, "user_callback", &self->user_callback);
  682. fetchcallback(v, "user_callback_setup", &self->user_callback_setup);
  683. fetchcallback(v, "user_callback_exit", &self->user_callback_exit);
  684. self->ctx = mg_start(user_callback_proxy, self, options);
  685. // free the options string list memory
  686. for (i = 0; options[i]; ++i)
  687. free((void *) options[i]);
  688. // throw an error if the server did not start
  689. if (self->ctx == NULL) {
  690. sq_mongoose_release_references(self);
  691. _rc_ = sq_throwerror(v, "could not start mongoose");
  692. }
  693. // return the context so it can be stopped later
  694. return _rc_;
  695. }
  696. static SQRESULT
  697. sq_mongoose_stop(HSQUIRRELVM v)
  698. {
  699. SQ_FUNC_VARS_NO_TOP(v);
  700. GET_mongoose_INSTANCE();
  701. if(self->ctx){
  702. mg_stop(self->ctx);
  703. sq_mongoose_release_references(self);
  704. self->ctx = 0;
  705. }
  706. return 0;
  707. }
  708. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_mongoose_##name,nparams,tycheck}
  709. static SQRegFunction sq_mongoose_methods[] =
  710. {
  711. _DECL_FUNC(constructor, 1, _SC("x")),
  712. _DECL_FUNC(start, -1, _SC("x")),
  713. _DECL_FUNC(stop, 1, _SC("x")),
  714. _DECL_FUNC(modify_passwords_file, 1, _SC("x")),
  715. _DECL_FUNC(version, 1, _SC("x")),
  716. _DECL_FUNC(show_errors_on_stdout, 2, _SC("xb")),
  717. {0,0}
  718. };
  719. #undef _DECL_FUNC
  720. static SQRESULT
  721. sq_mg_url_decode_base(HSQUIRRELVM v, SQInteger is_form_url_encoded)
  722. {
  723. SQ_FUNC_VARS_NO_TOP(v);
  724. SQ_GET_STRING(v, 2, src);
  725. int dst_len = src_size +1;
  726. char *dst = sq_getscratchpad(v,dst_len);
  727. dst_len = mg_url_decode(src, src_size, dst, dst_len, is_form_url_encoded);
  728. sq_pushstring(v, dst, dst_len);
  729. return 1;
  730. }
  731. static SQRESULT
  732. sq_mg_url_decode(HSQUIRRELVM v)
  733. {
  734. return sq_mg_url_decode_base(v, 1);
  735. }
  736. static SQRESULT
  737. sq_mg_uri_decode(HSQUIRRELVM v)
  738. {
  739. return sq_mg_url_decode_base(v, 0);
  740. }
  741. static SQRESULT
  742. sq_mg_url_encode(HSQUIRRELVM v)
  743. {
  744. SQ_FUNC_VARS_NO_TOP(v);
  745. SQ_GET_STRING(v, 2, src);
  746. char *dst = mg_url_encode(src);
  747. sq_pushstring(v, dst, -1);
  748. free(dst);
  749. return 1;
  750. }
  751. static SQRESULT
  752. sq_mg_get_builtin_mime_type(HSQUIRRELVM v)
  753. {
  754. SQ_FUNC_VARS_NO_TOP(v);
  755. SQ_GET_STRING(v, 2, src);
  756. const char *dst = mg_get_builtin_mime_type(src);
  757. sq_pushstring(v, dst, -1);
  758. return 1;
  759. }
  760. static SQRESULT
  761. sq_mg_md5(HSQUIRRELVM v)
  762. {
  763. SQ_FUNC_VARS(v);
  764. char buf[32 + 1];
  765. unsigned char hash[16];
  766. MD5_CTX ctx;
  767. MD5Init(&ctx);
  768. for (int i = 2; i <= _top_; ++i) {
  769. SQ_GET_STRING(v, i, p);
  770. MD5Update(&ctx, (const unsigned char *) p, p_size);
  771. }
  772. MD5Final(hash, &ctx);
  773. mg_bin2str(buf, hash, sizeof(hash));
  774. sq_pushstring(v, buf, -1);
  775. return 1;
  776. }
  777. static SQRESULT
  778. sq_mg_debug_print(HSQUIRRELVM v)
  779. {
  780. SQ_FUNC_VARS(v);
  781. SQInteger i, write_count = 0;
  782. for (i = 2; i <= _top_; ++i) {
  783. sq_tostring(v, i);
  784. SQ_GET_STRING(v, -1, value);
  785. write_count += fwrite(value, 1, value_size, stderr);
  786. sq_poptop(v);
  787. }
  788. sq_pushinteger(v, write_count);
  789. return 1;
  790. }
  791. #ifdef JNI_ENABLE_LOG
  792. #include <android/log.h>
  793. /*
  794. ** A callback for the android_log() SQIntegererface.
  795. */
  796. static void jniLog(int iErrCode, const char *zMsg){
  797. __android_log_print(ANDROID_LOG_ERROR,"jniLuaServerLog","(%d) %s\n", iErrCode, zMsg);
  798. }
  799. static SQRESULT sq_mg_jniLog(HSQUIRRELVM v)
  800. {
  801. SQ_FUNC_VARS_NO_TOP(v);
  802. SQ_GET_INTEGER(v, 2, code);
  803. SQ_GET_STRING(v, 3, error_message);
  804. jniLog(code, error_message);
  805. return 0;
  806. }
  807. #endif
  808. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_mg_##name,nparams,tycheck, SQTrue}
  809. static SQRegFunction sq_mg_methods[] =
  810. {
  811. _DECL_FUNC(url_decode, 2, _SC(".s")),
  812. _DECL_FUNC(uri_decode, 2, _SC(".s")),
  813. _DECL_FUNC(url_encode, 2, _SC(".s")),
  814. _DECL_FUNC(get_builtin_mime_type, 2, _SC(".s")),
  815. _DECL_FUNC(md5, -2, _SC(".s")),
  816. #ifdef JNI_ENABLE_LOG
  817. _DECL_FUNC(jniLog, -2, _SC(".s")),
  818. #endif
  819. _DECL_FUNC(debug_print, -2, _SC(".s")),
  820. {0,0}
  821. };
  822. #undef _DECL_FUNC
  823. static void reg_string(HSQUIRRELVM v, const char *name, const char *val) {
  824. sq_pushstring(v, name, -1);
  825. if(val) sq_pushstring(v, val, -1);
  826. else sq_pushnull(v);
  827. sq_rawset(v, -3);
  828. }
  829. static void reg_integer(HSQUIRRELVM v, const char *name, int val) {
  830. sq_pushstring(v, name, -1);
  831. sq_pushinteger(v, val);
  832. sq_rawset(v, -3);
  833. }
  834. // pushes request info on the Lua stack as a table
  835. static void
  836. push_request(HSQUIRRELVM v, const struct mg_request_info *ri)
  837. {
  838. int i;
  839. sq_pushliteral(v, _SC("info"));
  840. sq_get(v, -2);
  841. #define NEWSLOT_STR(ks) reg_string(v, #ks, ri->ks);
  842. NEWSLOT_STR(request_method);
  843. NEWSLOT_STR(uri);
  844. NEWSLOT_STR(http_version);
  845. NEWSLOT_STR(query_string);
  846. NEWSLOT_STR(remote_user);
  847. NEWSLOT_STR(log_message);
  848. #define NEWSLOT_INT(ks) reg_integer(v, #ks, ri->ks);
  849. NEWSLOT_INT(remote_ip);
  850. NEWSLOT_INT(remote_port);
  851. NEWSLOT_INT(status_code);
  852. NEWSLOT_INT(is_ssl);
  853. #undef NEWSLOT_STR
  854. #undef NEWSLOT_INT
  855. sq_pushliteral(v, "http_headers");
  856. sq_newtable(v);
  857. for (i = 0; i < ri->num_headers; ++i) {
  858. reg_string(v, ri->http_headers[i].name, ri->http_headers[i].value);
  859. }
  860. sq_newslot(v, -3, SQFalse);
  861. sq_poptop(v); //remove data table
  862. }
  863. #if 0
  864. static SQRESULT
  865. sq_mg_pcall_master_plugin(HSQUIRRELVM v)
  866. {
  867. SQ_FUNC_VARS_NO_TOP(v);
  868. GET_MG_CONNECION();
  869. SQ_GET_STRING(v, 2, func_name);
  870. const SQChar *error_message = _SC("No master plugin installed !");
  871. HSQUIRRELVM master_plugin = (HSQUIRRELVM) mg_lock_master_plugin(conn);
  872. if(master_plugin){
  873. int master_plugin_saved_top = sq_gettop(master_plugin);
  874. //sq_pushcfunction(master_plugin, traceback); /* push traceback function */
  875. //int error_func = sq_gettop(master_plugin);
  876. sq_pushstring(master_plugin, func_name, func_name_size);
  877. sq_getonroottable(master_plugin);
  878. if(sq_gettype(master_plugin, -1) == OT_CLOSURE){
  879. sq_pushroottable(master_plugin);
  880. int arg_top = sq_gettop (v);
  881. /* Push arguments to dst stack */
  882. int idx = 4;
  883. copy_values_between_vms (master_plugin, v, arg_top-idx, idx);
  884. if (sq_pcall (master_plugin, arg_top-idx+1, SQTrue, SQTrue) == SQ_OK) {
  885. /* run OK? */
  886. int ret_top = sq_gettop (master_plugin);
  887. /* Push status = OK */
  888. sq_pushbool (v, SQTrue);
  889. /* Return values to src */
  890. //copy_values_between_vms (v, master_plugin, master_plugin_saved_top+2, ret_top);
  891. /* pops debug.traceback and result from dst state */
  892. //sq_settop(master_plugin, master_plugin_saved_top);
  893. /*unlock master plugin*/
  894. mg_unlock_master_plugin(conn);
  895. /* Return true (success) plus return values */
  896. return 1;
  897. }
  898. error_message = sq_tostring (master_plugin, -1);
  899. } else error_message = "Attempt to call an invalid function on master plugin !";
  900. /* pops debug.traceback and result from dst state */
  901. sq_settop(master_plugin, master_plugin_saved_top);
  902. /*unlock master plugin*/
  903. mg_unlock_master_plugin(conn);
  904. }
  905. return sq_throwerror(v, error_message);
  906. }
  907. #endif
  908. static void write_error_message(struct mg_connection *conn,
  909. const char * error_msg, SQInteger error_len){
  910. #define PRE_TAG_OPEN "<pre>"
  911. #define PRE_TAG_CLOSE "</pre>"
  912. mg_write(conn, PRE_TAG_OPEN, sizeof(PRE_TAG_OPEN));
  913. if(error_len < 0) error_len = strlen(error_msg);
  914. mg_write(conn, error_msg, error_len);
  915. mg_write(conn, PRE_TAG_CLOSE, sizeof(PRE_TAG_CLOSE));
  916. }
  917. #ifdef __cplusplus
  918. extern "C" {
  919. #endif
  920. SQUIRREL_API SQRESULT sqext_register_SQLite3(HSQUIRRELVM v);
  921. SQRESULT sqext_register_MySQL(HSQUIRRELVM v);
  922. SQRESULT sqext_register_PostgreSQL(HSQUIRRELVM v);
  923. SQUIRREL_API SQRESULT sqext_register_base64(HSQUIRRELVM v);
  924. SQUIRREL_API SQRESULT sqext_register_mix(HSQUIRRELVM v);
  925. SQUIRREL_API SQRESULT sqstd_register_bloblib(HSQUIRRELVM v);
  926. SQUIRREL_API SQRESULT sqstd_register_iolib(HSQUIRRELVM v);
  927. SQUIRREL_API SQInteger sqstd_register_systemlib(HSQUIRRELVM v);
  928. SQUIRREL_API SQRESULT sqstd_register_mathlib(HSQUIRRELVM v);
  929. SQUIRREL_API SQRESULT sqstd_register_stringlib(HSQUIRRELVM v);
  930. SQUIRREL_API SQRESULT sqext_register_Sq_Fpdf(HSQUIRRELVM v);
  931. SQUIRREL_API SQRESULT sqext_register_sqfs(HSQUIRRELVM v);
  932. SQUIRREL_API void sqstd_seterrorhandlers(HSQUIRRELVM v);
  933. SQUIRREL_API void sqstd_printcallstack(HSQUIRRELVM v);
  934. SQUIRREL_API SQRESULT sqext_register_sq_socket(HSQUIRRELVM v);
  935. SQUIRREL_API SQRESULT sqext_register_sq_slave_vm(HSQUIRRELVM v);
  936. SQUIRREL_API SQRESULT sqext_register_axtls (HSQUIRRELVM v);
  937. SQUIRREL_API SQRESULT sqext_register_openssl (HSQUIRRELVM v);
  938. SQRESULT sqext_register_decimal(HSQUIRRELVM v);
  939. SQRESULT sqext_register_sq_zlib(HSQUIRRELVM v);
  940. SQRESULT sqext_register_sq_blosc(HSQUIRRELVM v);
  941. SQRESULT sqext_register_pcre2(HSQUIRRELVM v);
  942. SQRESULT sqext_register_markdown(HSQUIRRELVM v);
  943. #ifdef __cplusplus
  944. } /*extern "C"*/
  945. #endif
  946. static sq_modules_preload_st modules_preload[] = {
  947. {"blob", sqstd_register_bloblib},
  948. {"io", sqstd_register_iolib},
  949. {"math", sqstd_register_mathlib},
  950. {"sys", sqstd_register_systemlib},
  951. {"string", sqstd_register_stringlib},
  952. {"base64", sqext_register_base64},
  953. #ifndef NO_SQ_PDF
  954. {"fpdf", sqext_register_Sq_Fpdf},
  955. #endif
  956. {"sqlite3", sqext_register_SQLite3},
  957. {"zlib", sqext_register_sq_zlib},
  958. {"markdown", sqext_register_markdown},
  959. #if defined(SQ_USE_PCRE2) || defined(SQ_USE_PCRE2_STATIC)
  960. {"pcre2", sqext_register_pcre2},
  961. #endif
  962. #ifdef SQ_USE_CBLOSC
  963. {"blosc", sqext_register_sq_blosc},
  964. #endif // SQ_USE_CBLOSC
  965. #ifdef WITH_MYSQL
  966. {"mysql", sqext_register_MySQL},
  967. #endif
  968. #ifdef WITH_POSTGRESQL
  969. {"postgresql", sqext_register_PostgreSQL},
  970. #endif
  971. {"sqfs", sqext_register_sqfs},
  972. {"mix", sqext_register_mix},
  973. {"socket", sqext_register_sq_socket},
  974. {"slave_vm", sqext_register_sq_slave_vm},
  975. #ifdef USE_AXTLS
  976. {"axtls", sqext_register_axtls},
  977. #endif
  978. #ifdef USE_OPENSSL
  979. {"openssl", sqext_register_openssl},
  980. #endif
  981. {NULL, NULL}
  982. };
  983. void sq_printfunc(HSQUIRRELVM v,const SQChar *s,...)
  984. {
  985. va_list vl;
  986. va_start(vl, s);
  987. #ifdef JNI_ENABLE_LOG
  988. char buf[2048];
  989. vsnprintf(buf, sizeof(buf), s, vl);
  990. jniLog(-1, buf);
  991. #else
  992. vfprintf(stdout, s, vl);
  993. #endif
  994. va_end(vl);
  995. }
  996. void sq_errorfunc(HSQUIRRELVM v,const SQChar *s,...)
  997. {
  998. va_list vl;
  999. va_start(vl, s);
  1000. #ifdef JNI_ENABLE_LOG
  1001. char buf[2048];
  1002. vsnprintf(buf, sizeof(buf), s, vl);
  1003. jniLog(-2, buf);
  1004. #else
  1005. vfprintf(stderr, s, vl);
  1006. #endif
  1007. va_end(vl);
  1008. }
  1009. #define INT_CONST(v,num) sq_pushstring(v,_SC(#num),-1);sq_pushinteger(v,num);sq_newslot(v,-3,SQTrue);
  1010. static HSQUIRRELVM my_new_squirrel(struct mg_context *ctx) {
  1011. HSQUIRRELVM v = sq_open(1024);
  1012. if(!v) return 0;
  1013. sqstd_seterrorhandlers(v); //registers the default error handlers
  1014. sq_setprintfunc(v, sq_printfunc, sq_errorfunc); //sets the print function
  1015. sq_pushroottable(v);
  1016. sq_modules_preload_st *mp = modules_preload;
  1017. sq_preload_modules(v, mp);
  1018. while(mp->module_load_func){
  1019. mp->module_load_func(v);
  1020. ++mp;
  1021. }
  1022. sq_pushstring(v,sq_http_request_TAG, -1);
  1023. sq_newclass(v,SQFalse);
  1024. sq_settypetag(v,-1,(void*)sq_http_request_TAG);
  1025. sq_insert_reg_funcs(v, mg_http_request_methods);
  1026. sq_pushstring(v, _SC("info"), -1);
  1027. sq_newtable(v);
  1028. sq_newslot(v,-3,SQFalse);
  1029. sq_newslot(v,-3,SQFalse);
  1030. sq_insert_reg_funcs(v, sq_mg_methods);
  1031. sq_pushliteral(v, "APP_ROOT_FOLDER");
  1032. sq_pushstring(v, mg_get_option(ctx, "document_root"), -1);
  1033. sq_newslot(v, -3, SQFalse);
  1034. sq_poptop(v); //remove roottable
  1035. return v;
  1036. }
  1037. SQInteger blob_read(SQUserPointer file,SQUserPointer p,SQInteger size);
  1038. SQInteger loadstring(HSQUIRRELVM v, const char * bcode, SQInteger bcode_size)
  1039. {
  1040. SQBlob b(0, bcode_size);
  1041. b.Write(bcode, bcode_size);
  1042. b.Seek(0, SQ_SEEK_SET);
  1043. SQInteger rc = sq_readclosure(v, blob_read, &b);
  1044. return rc < 0 ? rc : 1;
  1045. }
  1046. // dispatches a callback to a Lua function if one is registered
  1047. static void *
  1048. user_callback_proxy(enum mg_event event,
  1049. struct mg_connection *conn,
  1050. const struct mg_request_info *ri)
  1051. {
  1052. HSQUIRRELVM v;
  1053. int e;
  1054. switch(event){
  1055. case MG_NEW_MASTER_PLUGIN: {
  1056. SQ_Mg_Context *sq_mg_ctx = (SQ_Mg_Context *) conn;
  1057. SQ_MG_Callback *cb = sq_mg_ctx->master_plugin;
  1058. v = my_new_squirrel((struct mg_context *)ri);
  1059. if(!v) return 0;
  1060. if(cb){
  1061. if (loadstring(v, cb->buf, cb->size) == 1) {
  1062. sq_pushroottable(v);
  1063. if(sq_call(v, 1, SQFalse, SQTrue) != SQ_OK){
  1064. sq_errorfunc(v, "sq_call failed %d\n%s", __LINE__, sq_getlasterror_str(v));
  1065. }
  1066. sq_poptop(v); //remove function from stack
  1067. }
  1068. }
  1069. return v;
  1070. }
  1071. break;
  1072. case MG_FREE_MASTER_PLUGIN:
  1073. v = (HSQUIRRELVM)conn;
  1074. if(v) {
  1075. SQ_Mg_Context *sq_mg_ctx = (SQ_Mg_Context *) ri;
  1076. SQ_MG_Callback *cb = sq_mg_ctx->master_plugin_exit;
  1077. if(cb){
  1078. if (loadstring(v, cb->buf, cb->size) == 1) {
  1079. sq_pushroottable(v);
  1080. if(sq_call(v, 1, SQFalse, SQFalse) != SQ_OK){
  1081. sq_errorfunc(v, "sq_call failed %d\n%s", __LINE__, sq_getlasterror_str(v));
  1082. }
  1083. sq_poptop(v); //remove function from stack
  1084. }
  1085. else sq_errorfunc(v, "sq_call failed %d\n%s", __LINE__, sq_getlasterror_str(v));
  1086. }
  1087. sq_close(v);
  1088. }
  1089. return 0;
  1090. break;
  1091. case MG_NEW_PLUGIN:{
  1092. SQ_Mg_Context *sq_mg_ctx = (SQ_Mg_Context *) mg_get_user_data(conn);
  1093. if(!sq_mg_ctx) return 0;
  1094. SQ_MG_Callback *cb = sq_mg_ctx->user_callback;
  1095. if (cb) {
  1096. v = my_new_squirrel((struct mg_context *)ri);
  1097. if(!v) return 0;
  1098. SQInteger top = sq_gettop(v);
  1099. SQ_MG_Callback *cb_setup = sq_mg_ctx->user_callback_setup;
  1100. if(cb_setup){
  1101. if (loadstring(v, cb_setup->buf, cb_setup->size) == 1) {
  1102. sq_pushroottable(v);
  1103. if(sq_call(v, 1, SQFalse, SQFalse) != SQ_OK){
  1104. sq_errorfunc(v, "sq_call failed %d\n%s", __LINE__, sq_getlasterror_str(v));
  1105. }
  1106. sq_poptop(v); //remove function from stack
  1107. }
  1108. else sq_errorfunc(v, "sq_call failed %d\n%s", __LINE__, sq_getlasterror_str(v));
  1109. }
  1110. sq_pushroottable(v);
  1111. sq_pushstring(v, sq_mg_user_callback, -1);
  1112. if (loadstring(v, cb->buf, cb->size) == 1) {
  1113. sq_newslot(v, -3, SQFalse);
  1114. }
  1115. else sq_errorfunc(v, "sq_call failed %d\n%s", __LINE__, sq_getlasterror_str(v));
  1116. sq_settop(v, top); //remove everithing left on stack while working here
  1117. return v;
  1118. }
  1119. }
  1120. return 0;
  1121. case MG_FREE_PLUGIN:
  1122. v = (HSQUIRRELVM)mg_get_plugin(conn);
  1123. if(v){
  1124. SQ_Mg_Context *sq_mg_ctx = (SQ_Mg_Context *) ri;
  1125. if(sq_mg_ctx){
  1126. SQ_MG_Callback *cb = sq_mg_ctx->user_callback_exit;
  1127. if(cb){
  1128. if (loadstring(v, cb->buf, cb->size) == 1) {
  1129. sq_pushroottable(v);
  1130. if(sq_call(v, 1, SQFalse, SQFalse) != SQ_OK){
  1131. sq_errorfunc(v, "sq_call failed %d\n%s", __LINE__, sq_getlasterror_str(v));
  1132. }
  1133. sq_poptop(v); //remove function from stack
  1134. }
  1135. else sq_errorfunc(v, "sq_call failed %d\n%s", __LINE__, sq_getlasterror_str(v));
  1136. }
  1137. }
  1138. sq_close(v);
  1139. }
  1140. return NULL;
  1141. case MG_INIT_SSL:
  1142. #if defined(USE_AXTLS) || defined(USE_OPENSSL)
  1143. //lua_pushstring(L, "MG_INIT_SSL");
  1144. *((void**)conn) = SSL_CTX_new(0);
  1145. #endif
  1146. return 0;
  1147. case MG_NEW_REQUEST:
  1148. case MG_HTTP_ERROR:
  1149. case MG_EVENT_LOG:{
  1150. v = (HSQUIRRELVM) mg_get_plugin(conn);
  1151. if (v) {
  1152. SQInteger saved_top = sq_gettop(v);
  1153. //SQ_Mg_Context *sq_mg_ctx = (SQ_Mg_Context *) mg_get_user_data(conn);
  1154. sq_pushstring(v, sq_mg_user_callback, -1);
  1155. if(sq_getonroottable(v) != SQ_OK) {
  1156. write_error_message(conn, "failed to find mg_user_callback", -1);
  1157. return NULL;
  1158. }
  1159. sq_pushroottable(v);
  1160. #define CASE(n) case n: sq_pushstring(v, #n, -1);break
  1161. switch(event){
  1162. CASE(MG_INIT_SSL);
  1163. CASE(MG_HTTP_ERROR);
  1164. CASE(MG_EVENT_LOG);
  1165. CASE(MG_NEW_REQUEST);
  1166. default:
  1167. sq_pushnull(v);
  1168. }
  1169. sq_pushstring(v, sq_http_request_TAG, -1);
  1170. if(sq_getonroottable(v) == SQ_OK){
  1171. sq_pushroottable(v);
  1172. if(sq_call(v, 1, SQTrue, SQFalse) == SQ_OK){
  1173. sq_remove(v, -2); //remove class
  1174. sq_setinstanceup(v, -1, conn);
  1175. }
  1176. }
  1177. push_request(v, ri);
  1178. if(sq_call(v, 3, SQTrue, SQTrue) != SQ_OK) {
  1179. write_error_message(conn, sq_getlasterror_str(v), -1);
  1180. e = 0;
  1181. } else {
  1182. SQBool bval;
  1183. if(sq_getbool(v, -1, &bval) == SQ_OK) e = bval == SQTrue ? 1 : 0;
  1184. else e = 0;
  1185. }
  1186. sq_settop(v, saved_top);
  1187. return (void *) e;
  1188. }
  1189. }
  1190. default:
  1191. return NULL;
  1192. }
  1193. return NULL;
  1194. }
  1195. #ifdef __cplusplus
  1196. extern "C" {
  1197. #endif
  1198. SQRESULT sqext_register_mongoose(HSQUIRRELVM v)
  1199. {
  1200. sq_insert_reg_funcs(v, sq_mg_methods);
  1201. sq_pushstring(v,sq_mongoose_TAG, -1);
  1202. sq_newclass(v,SQFalse);
  1203. sq_settypetag(v,-1,(void*)sq_mongoose_TAG);
  1204. sq_insert_reg_funcs(v, sq_mongoose_methods);
  1205. sq_newslot(v,-3,SQTrue);
  1206. return 1;
  1207. }
  1208. #ifdef __cplusplus
  1209. }
  1210. #endif