Tests about a simple python3 fastcgi runner using libfcgi and the Python-C API.
python
c
wsgi
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

python_ioin.c 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. #include "python_ioin.h"
  2. /**@file python_ioin.c
  3. * @ingroup lib_ioin
  4. */
  5. /**@brief If given object in_stream is NULL set error indicator
  6. * @return 0 if no error else -1 or -2
  7. */
  8. static int _check_nullin(PyObject *self);
  9. /**@brief Request a new buffer size.
  10. *
  11. * @param PyObject* self The IoIn instance
  12. * @param int nreq number of bytes required in buffer
  13. * @return 0 on error else buffer size
  14. */
  15. static int pyfcgi_ioin__reqbuf(PyObject *self, int nreq);
  16. /**@brief Concat two bytes/unicode given IoIn configuration flag
  17. */
  18. static PyObject* IoIn__Concat(PyObject *self, PyObject *left, PyObject *right);
  19. PyMethodDef IoIn_methods[] = {
  20. {"close", (PyCFunction)pyfcgi_ioin_close, METH_FASTCALL, NULL},
  21. {"fileno", (PyCFunction)pyfcgi_ioin_fileno, METH_FASTCALL, NULL},
  22. {"flush", (PyCFunction)pyfcgi_ioin_flush, METH_FASTCALL, NULL},
  23. {"isatty", (PyCFunction)pyfcgi_ioin_isatty, METH_FASTCALL, NULL},
  24. {"readable", (PyCFunction)pyfcgi_ioin_readable, METH_FASTCALL, NULL},
  25. {"readline", (PyCFunction)pyfcgi_ioin_readline, METH_FASTCALL, NULL},
  26. {"readlines", (PyCFunction)pyfcgi_ioin_readlines, METH_FASTCALL, NULL},
  27. {"seek", (PyCFunction)pyfcgi_ioin_seek, METH_FASTCALL, NULL},
  28. {"seekable", (PyCFunction)pyfcgi_ioin_seekable, METH_FASTCALL, NULL},
  29. {"tell", (PyCFunction)pyfcgi_ioin_tell, METH_FASTCALL, NULL},
  30. {"truncate", (PyCFunction)pyfcgi_ioin_truncate, METH_FASTCALL, NULL},
  31. {"writable", (PyCFunction)pyfcgi_ioin_writable, METH_FASTCALL, NULL},
  32. {"writelines", (PyCFunction)pyfcgi_ioin_writelines, METH_FASTCALL, NULL},
  33. {"read", (PyCFunction)pyfcgi_ioin_read, METH_FASTCALL, NULL},
  34. {"readall", (PyCFunction)pyfcgi_ioin_readall, METH_FASTCALL, NULL},
  35. {"readinto", (PyCFunction)pyfcgi_ioin_readinto, METH_FASTCALL, NULL},
  36. {"write", (PyCFunction)pyfcgi_ioin_write, METH_FASTCALL, NULL},
  37. {NULL} //Sentinel
  38. };
  39. PyMemberDef IoIn_members[] = {
  40. {"closed", T_OBJECT, offsetof(IoIn, closed), READONLY, "True if the stream is closed"},
  41. {NULL}
  42. };
  43. PyTypeObject IoInType = {
  44. PyVarObject_HEAD_INIT(NULL, 0)
  45. "libpyfcgi.IoIn", /* tp_name */
  46. sizeof(IoIn), /* tp_basicsize */
  47. 0, /* tp_itemsize */
  48. (destructor)pyfcgi_ioin_del, /* tp_dealloc */
  49. 0, /* tp_print */
  50. 0, /* tp_getattr */
  51. 0, /* tp_setattr */
  52. 0, /* tp_reserved */
  53. 0, /* tp_repr */
  54. 0, /* tp_as_number */
  55. 0, /* tp_as_sequence */
  56. 0, /* tp_as_mapping */
  57. 0, /* tp_hash */
  58. 0, /* tp_call */
  59. 0, /* tp_str */
  60. 0, /* tp_getattro */
  61. 0, /* tp_setattro */
  62. 0, /* tp_as_buffer */
  63. Py_TPFLAGS_DEFAULT |
  64. Py_TPFLAGS_BASETYPE, /* tp_flags */
  65. "RawIo interface to FCGI input stream", /* tp_doc */
  66. 0, /* tp_traverse */
  67. 0, /* tp_clear */
  68. 0, /* tp_richcompare */
  69. 0, /* tp_weaklistoffset */
  70. 0, /* tp_iter */
  71. 0, /* tp_iternext */
  72. IoIn_methods, /* tp_methods */
  73. IoIn_members, /* tp_members */
  74. 0, /* tp_getset */
  75. 0, /* tp_base */
  76. 0, /* tp_dict */
  77. 0, /* tp_descr_get */
  78. 0, /* tp_descr_set */
  79. 0, /* tp_dictoffset */
  80. pyfcgi_ioin_init, /* tp_init */
  81. 0, /* tp_alloc */
  82. 0, /* tp_new */
  83. };
  84. int pyfcgi_ioin_init(PyObject *self, PyObject *args, PyObject *kwds)
  85. {
  86. IoIn *ioin = (void*)self;
  87. ioin->in_stream = NULL;
  88. ioin->buff = NULL;
  89. ioin->buff_sz = 0;
  90. ioin->eof=0;
  91. ioin->bin=1;
  92. return 0;
  93. }
  94. void pyfcgi_ioin_del(IoIn *self)
  95. {
  96. IoIn *ioin = self;
  97. if(ioin->buff) { free(ioin->buff); }
  98. Py_TYPE(self)->tp_free((PyObject*)self);
  99. }
  100. PyObject* pyfcgi_ioin_close(PyObject *self, PyObject **argv, Py_ssize_t argc)
  101. {
  102. if(_check_nullin(self)) { Py_RETURN_NONE; }
  103. if(argc)
  104. {
  105. PyErr_Format(PyExc_ValueError,
  106. "libpyfcgi.IoIn.close() not expecting any argument but %zd given",
  107. argc);
  108. Py_RETURN_NONE;
  109. }
  110. if(FCGX_FClose(*((IoIn*)self)->in_stream) < 0)
  111. {
  112. PyErr_Format(PyExc_OSError,
  113. "%A unable to close", self);
  114. }
  115. ((IoIn*)self)->closed = Py_True;
  116. Py_RETURN_NONE;
  117. }
  118. PyObject* pyfcgi_ioin_fileno(PyObject *self, PyObject **argv, Py_ssize_t argc)
  119. {
  120. PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn has no fileno");
  121. Py_RETURN_NONE;
  122. }
  123. PyObject* pyfcgi_ioin_flush(PyObject *self, PyObject **argv, Py_ssize_t argc)
  124. {
  125. if(_check_nullin(self)) { Py_RETURN_NONE; }
  126. if(argc)
  127. {
  128. PyErr_Format(PyExc_ValueError,
  129. "libpyfcgi.IoIn.close() not expecting any argument but %zd given",
  130. argc);
  131. Py_RETURN_NONE;
  132. }
  133. if(FCGX_FFlush(*((IoIn*)self)->in_stream) < 0)
  134. {
  135. PyErr_Format(PyExc_OSError,
  136. "%A unable to flush", self);
  137. }
  138. Py_RETURN_NONE;
  139. }
  140. PyObject* pyfcgi_ioin_isatty(PyObject *self, PyObject **argv, Py_ssize_t argc)
  141. {
  142. return Py_False;
  143. }
  144. PyObject* pyfcgi_ioin_readable(PyObject *self, PyObject **argv, Py_ssize_t argc)
  145. {
  146. return Py_True;
  147. }
  148. PyObject* pyfcgi_ioin_readline(PyObject *self, PyObject **argv, Py_ssize_t argc)
  149. {
  150. int read_n;
  151. long arg;
  152. char *ret;
  153. if(_check_nullin(self)) { Py_RETURN_NONE; }
  154. if(argc > 1)
  155. {
  156. PyErr_Format(PyExc_ValueError,
  157. "libpyfcgi.IoIn.close() expecting 0 or 1 argument but %zd given",
  158. argc);
  159. Py_RETURN_NONE;
  160. }
  161. if(!argc || !argv[0])
  162. {
  163. read_n = pyfcgi_ioin__reqbuf(self, 0);
  164. }
  165. else
  166. {
  167. arg = PyLong_AsLong(argv[0]);
  168. if(PyErr_Occurred())
  169. {
  170. Py_RETURN_NONE;
  171. }
  172. read_n = pyfcgi_ioin__reqbuf(self, (arg>INT_MAX)?INT_MAX:arg);
  173. }
  174. ret = ((IoIn*)self)->buff;
  175. if(!FCGX_GetLine(ret, read_n, *((IoIn*)self)->in_stream))
  176. {
  177. ((IoIn*)self)->eof = 1;
  178. ret = "";
  179. }
  180. //dprintf(2, "readline : '%s'\n", ret);
  181. return IoIn__FromString(self, ret);
  182. }
  183. PyObject* pyfcgi_ioin_readlines(PyObject *self, PyObject **argv, Py_ssize_t argc)
  184. {
  185. size_t hint, left;
  186. int read_n, toread;
  187. size_t sz;
  188. PyObject *res, *cur_str, *read_str, *tmp;
  189. char *buff;
  190. if(_check_nullin(self)) { Py_RETURN_NONE; }
  191. if(argc > 1)
  192. {
  193. PyErr_Format(PyExc_ValueError,
  194. "libpyfcgi.IoIn.close() expecting 0 or 1 argument but %zd given",
  195. argc);
  196. Py_RETURN_NONE;
  197. }
  198. if(!argc || !argv[0])
  199. {
  200. hint = 0;
  201. left = 0;
  202. }
  203. else
  204. {
  205. hint = PyLong_AsSize_t(argv[0]);
  206. if(PyErr_Occurred())
  207. {
  208. Py_RETURN_NONE;
  209. }
  210. left = hint;
  211. }
  212. res = PyList_New(0);
  213. if(!res)
  214. {
  215. Py_RETURN_NONE;
  216. }
  217. Py_INCREF(res);
  218. read_n = pyfcgi_ioin__reqbuf(self, 0);
  219. buff = ((IoIn*)self)->buff;
  220. cur_str = NULL;
  221. while((hint && left) || !hint)
  222. {
  223. toread = (hint&&((size_t)read_n > left))?(int)left:read_n;
  224. if(!FCGX_GetLine(buff, toread,
  225. *((IoIn*)self)->in_stream))
  226. {
  227. ((IoIn*)self)->eof = 1;
  228. break;
  229. }
  230. sz = strlen(buff);
  231. left -= sz;
  232. read_str = IoIn__FromBuff(self);
  233. if(!read_str)
  234. {
  235. Py_RETURN_NONE;
  236. }
  237. Py_INCREF(read_str);
  238. if(cur_str)
  239. {
  240. tmp = IoIn__Concat(self, cur_str, read_str);
  241. Py_INCREF(tmp);
  242. cur_str = tmp;
  243. }
  244. else
  245. {
  246. cur_str = read_str;
  247. }
  248. if(buff[sz-1] == '\n')
  249. {
  250. //dprintf(2, "readlines : '%s'\n", PyUnicode_AsUTF8(cur_str));
  251. if(PyList_Append(res, cur_str))
  252. {
  253. Py_DECREF(cur_str);
  254. Py_RETURN_NONE;
  255. }
  256. Py_DECREF(cur_str);
  257. cur_str = NULL;
  258. }
  259. }
  260. if(cur_str)
  261. {
  262. //dprintf(2, "readlines(post) : '%s'\n", PyUnicode_AsUTF8(cur_str));
  263. if(PyList_Append(res, cur_str))
  264. {
  265. Py_DECREF(cur_str);
  266. Py_RETURN_NONE;
  267. }
  268. Py_DECREF(cur_str);
  269. }
  270. Py_DECREF(res);
  271. return res;
  272. }
  273. PyObject* pyfcgi_ioin_read(PyObject *self, PyObject **argv, Py_ssize_t argc)
  274. {
  275. size_t left, max;
  276. long l;
  277. int read_n, toread, sz;
  278. PyObject *res, *read_str;
  279. char *buff;
  280. if(_check_nullin(self)) { Py_RETURN_NONE; }
  281. if(argc > 1)
  282. {
  283. PyErr_Format(PyExc_ValueError,
  284. "libpyfcgi.IoIn.read() expecting at most 1 argument but %zd given",
  285. argc);
  286. Py_RETURN_NONE;
  287. }
  288. if(((IoIn*)self)->eof)
  289. {
  290. return IoIn__FromString(self, "");
  291. }
  292. max = 0;
  293. if(argc)
  294. {
  295. l = PyLong_AsLong(argv[0]);
  296. if(PyErr_Occurred() || l > 0)
  297. {
  298. PyErr_Clear();
  299. max = PyLong_AsSize_t(argv[0]);
  300. if(PyErr_Occurred())
  301. {
  302. Py_RETURN_NONE;
  303. }
  304. }
  305. }
  306. left = max;
  307. read_n = pyfcgi_ioin__reqbuf(self, 0);
  308. buff = ((IoIn*)self)->buff;
  309. if(!(res = IoIn__FromString(self, "")))
  310. {
  311. Py_RETURN_NONE;
  312. }
  313. Py_INCREF(res);
  314. while((max && left) || !max)
  315. {
  316. toread = (max&&((size_t)read_n > left))?(int)left:read_n;
  317. sz = FCGX_GetStr(buff, toread, *((IoIn*)self)->in_stream);
  318. if(sz)
  319. {
  320. if(sz == toread) { buff[sz] = '\0'; }
  321. left -= sz;
  322. if(!(read_str = IoIn__FromBuff(self)))
  323. {
  324. Py_RETURN_NONE;
  325. }
  326. Py_INCREF(read_str);
  327. if(!(res = IoIn__Concat(self, res, read_str)))
  328. {
  329. Py_RETURN_NONE;
  330. }
  331. Py_INCREF(res);
  332. }
  333. if( sz < toread)
  334. {
  335. ((IoIn*)self)->eof = 1;
  336. break;
  337. }
  338. }
  339. //dprintf(2, "read : %s\n", PyBytes_AsString(res));
  340. Py_DECREF(res);
  341. return res;
  342. }
  343. PyObject* pyfcgi_ioin_readall(PyObject *self, PyObject **argv, Py_ssize_t argc)
  344. {
  345. if(_check_nullin(self)) { Py_RETURN_NONE; }
  346. if(argc)
  347. {
  348. PyErr_Format(PyExc_ValueError,
  349. "libpyfcgi.IoIn.readall() not expecting any argument but %zd given",
  350. argc);
  351. Py_RETURN_NONE;
  352. }
  353. dprintf(2, "readall calling read : ");
  354. return pyfcgi_ioin_read(self, NULL, 0);
  355. }
  356. PyObject* pyfcgi_ioin_readinto(PyObject *self, PyObject **argv, Py_ssize_t argc)
  357. {
  358. PyObject *b;
  359. Py_ssize_t max, left, read_n;
  360. char *buff, *buff_ptr;
  361. int toread, ret;
  362. if(_check_nullin(self)) { Py_RETURN_NONE; }
  363. if(argc != 1)
  364. {
  365. PyErr_Format(PyExc_ValueError,
  366. "libpyfcgi.IoIn.readinto() expecting 1 argument but %zd given",
  367. argc);
  368. Py_RETURN_NONE;
  369. }
  370. b = argv[0];
  371. if(!PyByteArray_Check(b))
  372. {
  373. PyErr_Format(PyExc_ValueError,
  374. "libpyfcgi.IoIn.readinto() expected bytearray as argument but %A given",
  375. b);
  376. Py_RETURN_NONE;
  377. }
  378. left = max = PyByteArray_Size(b);
  379. buff = PyByteArray_AsString(b);
  380. buff_ptr = buff;
  381. read_n = pyfcgi_ioin__reqbuf(self, 0);
  382. while(left)
  383. {
  384. toread = left>read_n?read_n:left;
  385. if((ret = FCGX_GetStr(buff_ptr, toread,
  386. *((IoIn*)self)->in_stream)) < toread)
  387. {
  388. ((IoIn*)self)->eof = 1;
  389. break;
  390. }
  391. buff_ptr += ret;
  392. left -= ret;
  393. }
  394. //dprintf(2, "readinto chr buff : '%s'\n", buff);
  395. //dprintf(2, "readinto bytes repr : '%s'\n", PyByteArray_AsString(b));
  396. return b;
  397. }
  398. PyObject* pyfcgi_ioin_truncate(PyObject *self, PyObject **argv, Py_ssize_t argc)
  399. {
  400. PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn cannot be truncated");
  401. Py_RETURN_NONE;
  402. }
  403. PyObject* pyfcgi_ioin_SeekError(PyObject *self, PyObject **argv, Py_ssize_t argc)
  404. {
  405. PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn is not seekable");
  406. Py_RETURN_NONE;
  407. }
  408. PyObject* pyfcgi_ioin_WriteError(PyObject *self, PyObject **argv, Py_ssize_t argc)
  409. {
  410. PyErr_SetString(PyExc_OSError, "libpyfcgi.IoIn is not writable");
  411. Py_RETURN_NONE;
  412. }
  413. PyObject* pyfcgi_ioin_seekable(PyObject *self, PyObject **argv, Py_ssize_t argc)
  414. {
  415. return Py_False;
  416. }
  417. PyObject* pyfcgi_ioin_writable(PyObject *self, PyObject **argv, Py_ssize_t argc)
  418. {
  419. return Py_False;
  420. }
  421. static int _check_nullin(PyObject *self)
  422. {
  423. if(!((IoIn*)self)->in_stream)
  424. {
  425. PyErr_SetString(PyExc_RuntimeError,
  426. "pyfcgi.IoIn called in wrong context : FGCI input not set");
  427. return -1;
  428. }
  429. else if(!(*(((IoIn*)self)->in_stream)))
  430. {
  431. PyErr_SetString(PyExc_RuntimeError,
  432. "pyfcgi.IoIn called in wrong context : FGCI input is NULL");
  433. return -2;
  434. }
  435. return 0;
  436. }
  437. static int pyfcgi_ioin__reqbuf(PyObject *self, int nreq)
  438. {
  439. IoIn *ioin;
  440. void *tmp;
  441. int err;
  442. ioin = (IoIn*)self;
  443. if(ioin->buff_sz > nreq && ioin->buff)
  444. {
  445. return ioin->buff_sz;
  446. }
  447. ioin->buff_sz = ((nreq>>12)+1)<<12;
  448. if(ioin->buff_sz < nreq) { ioin->buff_sz = nreq; }
  449. if(!(tmp = realloc(ioin->buff, ioin->buff_sz)))
  450. {
  451. err = errno;
  452. PyErr_Format(PyExc_OSError,
  453. "%A error reallocating internal buffer : %s",
  454. self, strerror(err));
  455. errno = err;
  456. return 0;
  457. }
  458. ioin->buff = tmp;
  459. return ioin->buff_sz;
  460. }
  461. /**@brief Concat two bytes/unicode given IoIn configuration flag
  462. * @warn Py_DECREF both arguments
  463. */
  464. static PyObject* IoIn__Concat(PyObject *self, PyObject *left, PyObject *right)
  465. {
  466. if(((IoIn*)self)->bin)
  467. {
  468. PyBytes_Concat(&left, right);
  469. Py_DECREF(right);
  470. return left;
  471. }
  472. PyObject *res;
  473. res = PyUnicode_Concat(left, right);
  474. Py_DECREF(left);
  475. Py_DECREF(right);
  476. return res;
  477. }