sq_fastcgi.cpp 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  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. SQ_OPT_STRING_STRLEN();
  9. /* Lua System: Internet Server Application: FastCGI */
  10. #define FCGI_VERSION 1
  11. #define FCGI_HEADER_LEN 8
  12. #define FCGI_END_REQUEST_LEN 8
  13. #define FCGI_RESPONDER 1
  14. #define FCGI_KEEP_CONN 1
  15. #define FCGI_BEGIN_REQUEST 1
  16. #define FCGI_ABORT_REQUEST 2
  17. #define FCGI_END_REQUEST 3
  18. #define FCGI_PARAMS 4
  19. #define FCGI_STDIN 5
  20. #define FCGI_STDOUT 6
  21. #define FCGI_STDERR 7
  22. #define FCGI_DATA 8
  23. #define FCGI_GET_VALUES 9
  24. #define FCGI_GET_VALUES_RESULT 10
  25. #define FCGI_UNKNOWN_TYPE 11
  26. #define FCGI_REQUEST_COMPLETE 0
  27. #define FCGI_CANT_MPX_CONN 1
  28. #define FCGI_OVERLOADED 2
  29. #define FCGI_UNKNOWN_ROLE 3
  30. #define FCGI_NULL_REQUEST_ID ~0U
  31. #define FCGI_MAX_CONTENT_LEN 0xFFFF
  32. static const char *
  33. fcgi_decode_begin_request (HSQUIRRELVM v, const unsigned char *cp,
  34. const size_t size)
  35. {
  36. int role, keep_conn;
  37. if (size != 8) return "bad content";
  38. role = (*cp++ << 8);
  39. role |= *cp++;
  40. keep_conn = *cp & FCGI_KEEP_CONN;
  41. if (role != FCGI_RESPONDER) return "bad role";
  42. sq_pushbool(v, keep_conn);
  43. sq_setfield(v, -2, "keep_conn");
  44. return NULL;
  45. }
  46. static const char *
  47. fcgi_decode_params (HSQUIRRELVM v, const unsigned char *cp, const size_t size)
  48. {
  49. const unsigned char *endp = cp + size;
  50. while (cp < endp)
  51. {
  52. unsigned int name_len, value_len;
  53. name_len = *cp++;
  54. if (name_len & 0x80)
  55. {
  56. if (cp + 3 >= endp) return "bad content";
  57. name_len ^= 0x80;
  58. name_len = (name_len << 8) | *cp++;
  59. name_len = (name_len << 8) | *cp++;
  60. name_len = (name_len << 8) | *cp++;
  61. }
  62. if (cp >= endp) return "bad content";
  63. value_len = *cp++;
  64. if (value_len & 0x80)
  65. {
  66. if (cp + 3 >= endp) return "bad content";
  67. value_len ^= 0x80;
  68. value_len = (value_len << 8) | *cp++;
  69. value_len = (value_len << 8) | *cp++;
  70. value_len = (value_len << 8) | *cp++;
  71. }
  72. if (cp + name_len + value_len > endp)
  73. return "bad content";
  74. sq_pushstring(v, (const char *) cp, name_len);
  75. cp += name_len;
  76. sq_pushstring(v, (const char *) cp, value_len);
  77. cp += value_len;
  78. sq_rawset(v, -3);
  79. }
  80. return NULL;
  81. }
  82. static const char *
  83. fcgi_decode_stdin (HSQUIRRELVM v, const unsigned char *cp, const size_t size)
  84. {
  85. int concat = 1;
  86. sq_getfield(v, -1, "stdin");
  87. if (sq_isnil(v, -1))
  88. {
  89. sq_pop(v, 1);
  90. concat = 0;
  91. }
  92. sq_pushstring(v, (const char *) cp, size);
  93. if (concat) sq_concat(v, 2);
  94. sq_setfield(L, -2, "stdin");
  95. return NULL;
  96. }
  97. /*
  98. * Arguments: ..., channel (table)
  99. */
  100. static int
  101. fcgi_decode_record (HSQUIRRELVM v, const unsigned char *cp, const size_t size,
  102. unsigned int *ready_request_id)
  103. {
  104. unsigned int version, type, request_id, content_len, padding_len, len;
  105. int is_ready = 0;
  106. const char *err = NULL;
  107. version = *cp++;
  108. type = *cp++;
  109. request_id = (*cp++ << 8);
  110. request_id |= *cp++;
  111. content_len = (*cp++ << 8);
  112. content_len |= *cp++;
  113. padding_len = *cp++;
  114. cp++; /* reserved */
  115. len = FCGI_HEADER_LEN + content_len + padding_len;
  116. if (len > size) return 0;
  117. sq_rawgeti(v, -1, request_id);
  118. if (!sq_istable(v, -1))
  119. {
  120. sq_pop(v, 1);
  121. sq_newtable(v);
  122. sq_pushvalue(v, -1);
  123. sq_rawseti(v, -3, request_id);
  124. sq_pushinteger(v, request_id);
  125. sq_setfield(v, -2, "id");
  126. sq_getfield(v, -2, "request_meta"); /* metatable from channel */
  127. sq_setmetatable(v, -2);
  128. sq_pushvalue(v, -2); /* channel */
  129. sq_setfield(v, -2, "channel");
  130. }
  131. if (version != FCGI_VERSION)
  132. err = "bad version";
  133. else
  134. {
  135. switch (type)
  136. {
  137. case FCGI_BEGIN_REQUEST:
  138. err = fcgi_decode_begin_request(v, cp, content_len);
  139. break;
  140. case FCGI_ABORT_REQUEST:
  141. break;
  142. case FCGI_PARAMS:
  143. if (content_len)
  144. err = fcgi_decode_params(v, cp, content_len);
  145. break;
  146. case FCGI_STDIN:
  147. if (content_len)
  148. err = fcgi_decode_stdin(v, cp, content_len);
  149. else
  150. is_ready = 1;
  151. break;
  152. default:
  153. err = "bad type";
  154. }
  155. }
  156. if (err)
  157. {
  158. sq_pushstring(v, err, -1);
  159. sq_setfield(v, -2, "error");
  160. /*
  161. lua_pushinteger(L, version);
  162. lua_setfield(L, -2, "version");
  163. lua_pushinteger(L, type);
  164. lua_setfield(L, -2, "type");
  165. lua_pushlstring(L, cp, content_len);
  166. lua_setfield(L, -2, "content");
  167. */
  168. is_ready = 1;
  169. }
  170. if (is_ready)
  171. {
  172. if (*ready_request_id != FCGI_NULL_REQUEST_ID)
  173. sq_pushinteger(v, *ready_request_id);
  174. else
  175. sq_pushnil(v);
  176. sq_setfield(v, -2, "next_ready");
  177. *ready_request_id = request_id;
  178. }
  179. sq_pop(v, 1);
  180. return len;
  181. }
  182. /*
  183. * Arguments: {string | membuf_udata}, channel (table)
  184. * Returns: [request_id (number)]
  185. */
  186. static SQRESULT sq_fastcgi_decode (HSQUIRRELVM v)
  187. {
  188. SQ_FUNC_VARS(v);
  189. struct sys_buffer sb;
  190. const char *cp;
  191. unsigned int ready_request_id = FCGI_NULL_REQUEST_ID;
  192. if (!sys_buffer_read_init(v, 1, &sb))
  193. return 0;
  194. sq_checktype(v, 2, LUA_TTABLE);
  195. cp = sb.ptr.r;
  196. while (sb.size >= FCGI_HEADER_LEN)
  197. {
  198. const int len = fcgi_decode_record(v,
  199. (const unsigned char *) cp, sb.size, &ready_request_id);
  200. if (!len) break;
  201. cp += len;
  202. sb.size -= len;
  203. }
  204. sys_buffer_read_next(&sb, cp - sb.ptr.r);
  205. if (ready_request_id != FCGI_NULL_REQUEST_ID)
  206. {
  207. sq_pushinteger(v, ready_request_id);
  208. return 1;
  209. }
  210. return 0;
  211. }
  212. /*
  213. * Arguments: membuf_udata, request_id (number), prev_offset (number), string
  214. * Returns: offset (number)
  215. */
  216. static SQRESULT sq_fastcgi_encode (HSQUIRRELVM v)
  217. {
  218. SQ_FUNC_VARS(v);
  219. SQBlob *blob = NULL;
  220. SQObjectType ptype = sq_gettype(v, 2);
  221. if(ptype == OT_INSTANCE){
  222. if(SQ_FAILED(sq_getinstanceup(v,2,(SQUserPointer*)&blob,(SQUserPointer)SQBlob::SQBlob_TAG)))
  223. return sq_throwerror(v,_SC("invalid type tag"));
  224. if(!blob || !blob->IsValid())
  225. return sq_throwerror(v,_SC("the blob is invalid"));
  226. }
  227. SQ_GET_INTEGER(v, 3, request_id);
  228. SQ_GET_INTEGER(v, 4, prev_offset);
  229. SQ_GET_STRING(v, 5, s);
  230. unsigned char *cp;
  231. unsigned char *lenp;
  232. SQInteger prev_len = 0, prev_padding_len = 0;
  233. SQInteger data_len, padding_len;
  234. if (s_size > FCGI_MAX_CONTENT_LEN) {
  235. return sq_throwerror(v,_SC("too long"));
  236. }
  237. sys_buffer_write_init(v, 1, &sb, NULL, 0);
  238. if (prev_offset)
  239. {
  240. cp = (unsigned char *) sb.ptr.w - prev_offset;
  241. if (cp[-1] == (unsigned char) request_id
  242. && cp[-2] == (unsigned char) (request_id >> 8))
  243. {
  244. prev_len = (cp[0] << 8) | cp[1];
  245. prev_padding_len = cp[2];
  246. }
  247. else
  248. {
  249. prev_offset = 0;
  250. }
  251. }
  252. if (!len)
  253. {
  254. data_len = 2 * FCGI_HEADER_LEN + FCGI_END_REQUEST_LEN;
  255. prev_offset = 0;
  256. }
  257. else
  258. {
  259. data_len = len;
  260. if (!prev_offset || (prev_len + len) > FCGI_MAX_CONTENT_LEN)
  261. {
  262. data_len += FCGI_HEADER_LEN;
  263. prev_offset = 0;
  264. }
  265. else
  266. {
  267. data_len -= prev_padding_len;
  268. }
  269. }
  270. if (data_len <= 0)
  271. {
  272. padding_len = prev_padding_len - len; /* fits to previous padding */
  273. data_len = 0;
  274. }
  275. else
  276. {
  277. padding_len = 8 - data_len % 8;
  278. if (padding_len == 8) padding_len = 0;
  279. data_len += padding_len;
  280. if (!sys_buffer_write_next(v, &sb, NULL, data_len))
  281. return 0;
  282. }
  283. /* buffer may be re-allocated */
  284. cp = (unsigned char *) sb.ptr.w;
  285. if (prev_offset)
  286. {
  287. lenp = cp - prev_offset;
  288. cp -= prev_padding_len;
  289. memcpy(cp, s, len); /* concat to previous record */
  290. cp += len;
  291. len += prev_len;
  292. }
  293. else
  294. {
  295. *cp++ = FCGI_VERSION;
  296. *cp++ = FCGI_STDOUT;
  297. *cp++ = (unsigned char) (request_id >> 8);
  298. *cp++ = (unsigned char) request_id;
  299. lenp = cp++; /* content_len */
  300. cp++;
  301. cp++; /* padding_len */
  302. *cp++ = 0; /* reserved */
  303. if (len)
  304. {
  305. memcpy(cp, s, len);
  306. cp += len;
  307. }
  308. else
  309. {
  310. *cp++ = FCGI_VERSION;
  311. *cp++ = FCGI_END_REQUEST;
  312. *cp++ = (unsigned char) (request_id >> 8);
  313. *cp++ = (unsigned char) request_id;
  314. *cp++ = 0; /* content_len */
  315. *cp++ = FCGI_END_REQUEST_LEN;
  316. *cp++ = 0; /* padding_len */
  317. *cp++ = 0; /* reserved */
  318. memset(cp, 0, FCGI_END_REQUEST_LEN);
  319. }
  320. }
  321. lenp[0] = (unsigned char) (len >> 8);
  322. lenp[1] = (unsigned char) len;
  323. lenp[2] = (unsigned char) padding_len;
  324. if (padding_len)
  325. {
  326. memset(cp, 0, padding_len);
  327. cp += padding_len;
  328. }
  329. sys_buffer_write_done(v, &sb, NULL, data_len);
  330. sq_pushinteger(v, cp - lenp);
  331. return 1;
  332. }
  333. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_fastcgi_##name,nparams,tycheck}
  334. static SQRegFunction sq_fastcgi_methods[] =
  335. {
  336. _DECL_FUNC(encode, -1, _SC("x")),
  337. _DECL_FUNC(decode, 1, _SC("x")),
  338. {0,0}
  339. };
  340. #undef _DECL_FUNC
  341. #ifdef __cplusplus
  342. extern "C" {
  343. #endif
  344. SQRESULT sqext_register_fastcgi(HSQUIRRELVM v)
  345. {
  346. //add a namespace sqfastcgi
  347. sq_pushstring(v, sq_fastcgi_TAG,-1);
  348. sq_newclass(v, SQFalse);
  349. sq_insert_reg_funcs(v, sq_fastcgi_methods);
  350. sq_newslot(v,-3,SQTrue); //add sqfastcgi table to the root table
  351. return SQ_OK;
  352. }
  353. #ifdef __cplusplus
  354. }
  355. #endif