You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

774 lines
24 KiB

  1. #include "fastcgi_stream.h"
  2. #include <lighttpd/plugin_core.h>
  3. #include <lighttpd/stream_http_response.h>
  4. /**********************************************************************************/
  5. /* fastcgi types */
  6. #define FCGI_VERSION_1 1
  7. #define FCGI_HEADER_LEN 8
  8. enum FCGI_Type {
  9. FCGI_BEGIN_REQUEST = 1, /* web server -> backend */
  10. FCGI_ABORT_REQUEST = 2, /* web server -> backend */
  11. FCGI_END_REQUEST = 3, /* backend -> web server (status) */
  12. FCGI_PARAMS = 4, /* web server -> backend (stream name-value pairs) */
  13. FCGI_STDIN = 5, /* web server -> backend (stream request body) */
  14. FCGI_STDOUT = 6, /* backend -> web server (stream response body) */
  15. FCGI_STDERR = 7, /* backend -> web server (stream error messages) */
  16. FCGI_DATA = 8, /* web server -> backend (stream additional data) */
  17. FCGI_GET_VALUES = 9, /* web server -> backend (request names-value pairs with empty values) */
  18. FCGI_GET_VALUES_RESULT = 10,/* backend -> web server (response name-value pairs) */
  19. FCGI_UNKNOWN_TYPE = 11
  20. };
  21. #define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
  22. enum FCGI_Flags {
  23. FCGI_KEEP_CONN = 1
  24. };
  25. enum FCGI_Role {
  26. FCGI_RESPONDER = 1,
  27. FCGI_AUTHORIZER = 2,
  28. FCGI_FILTER = 3
  29. };
  30. enum FCGI_ProtocolStatus {
  31. FCGI_REQUEST_COMPLETE = 0,
  32. FCGI_CANT_MPX_CONN = 1,
  33. FCGI_OVERLOADED = 2,
  34. FCGI_UNKNOWN_ROLE = 3
  35. };
  36. /**********************************************************************************/
  37. typedef struct liFastCGIBackendContext liFastCGIBackendContext;
  38. typedef struct liFastCGIBackendConnection_p liFastCGIBackendConnection_p;
  39. typedef struct liFastCGIBackendPool_p liFastCGIBackendPool_p;
  40. struct liFastCGIBackendContext {
  41. gint refcount;
  42. liFastCGIBackendPool_p *pool;
  43. liBackendConnection *subcon;
  44. gboolean is_active; /* if is_active == FALSE iostream->io_watcher must not have a ref on the loop */
  45. liWorker *wrk;
  46. liIOStream *iostream;
  47. liStream fcgi_out, fcgi_in;
  48. /* for now: no multiplexing, at most one connection */
  49. liFastCGIBackendConnection_p *currentcon;
  50. gboolean stdin_closed, stdout_closed, stderr_closed, request_done;
  51. /* current record */
  52. guint8 version;
  53. guint8 type;
  54. guint16 requestID;
  55. guint16 contentLength;
  56. guint8 paddingLength;
  57. gint remainingContent, remainingPadding;
  58. };
  59. struct liFastCGIBackendConnection_p {
  60. liFastCGIBackendConnection public;
  61. liFastCGIBackendContext *ctx;
  62. liVRequest *vr;
  63. };
  64. struct liFastCGIBackendPool_p {
  65. liFastCGIBackendPool public;
  66. const liFastCGIBackendCallbacks *callbacks;
  67. liBackendConfig config;
  68. };
  69. /* debug */
  70. #if 0
  71. #define STRINGIFY(x) #x
  72. #define _STRINGIFY(x) STRINGIFY(x)
  73. #define fcgi_debug(...) fprintf(stderr, "fastcgi-stream.c:" _STRINGIFY(__LINE__) ": " __VA_ARGS__)
  74. #define FCGI_DEBUG
  75. static const gchar* fcgi_type_string(enum FCGI_Type type) {
  76. switch (type) {
  77. case FCGI_BEGIN_REQUEST:
  78. return "begin_request";
  79. case FCGI_ABORT_REQUEST:
  80. return "abort_request";
  81. case FCGI_END_REQUEST:
  82. return "end_request";
  83. case FCGI_PARAMS:
  84. return "params";
  85. case FCGI_STDIN:
  86. return "stdin";
  87. case FCGI_STDOUT:
  88. return "stdout";
  89. case FCGI_STDERR:
  90. return "stderr";
  91. case FCGI_DATA:
  92. return "data";
  93. case FCGI_GET_VALUES:
  94. return "get_values";
  95. case FCGI_GET_VALUES_RESULT:
  96. return "get_values_result";
  97. default:
  98. return "unknown_type";
  99. }
  100. }
  101. #else
  102. #define fcgi_debug(...) do { } while (0)
  103. #endif
  104. static void fastcgi_stream_out(liStream *stream, liStreamEvent event);
  105. static void fastcgi_stream_in(liStream *stream, liStreamEvent event);
  106. static void backend_detach_thread(liBackendPool *bpool, liWorker *wrk, liBackendConnection *bcon) {
  107. liFastCGIBackendContext *ctx = bcon->data;
  108. UNUSED(bpool);
  109. LI_FORCE_ASSERT(wrk == ctx->wrk);
  110. ctx->wrk = NULL;
  111. li_stream_disconnect(&ctx->fcgi_out);
  112. li_stream_disconnect_dest(&ctx->fcgi_in);
  113. LI_FORCE_ASSERT(2 == ctx->fcgi_in.refcount);
  114. LI_FORCE_ASSERT(2 == ctx->fcgi_out.refcount);
  115. li_iostream_detach(ctx->iostream);
  116. li_stream_detach(&ctx->fcgi_out);
  117. li_stream_detach(&ctx->fcgi_in);
  118. }
  119. static void backend_attach_thread(liBackendPool *bpool, liWorker *wrk, liBackendConnection *bcon) {
  120. liFastCGIBackendContext *ctx = bcon->data;
  121. UNUSED(bpool);
  122. ctx->wrk = wrk;
  123. li_iostream_attach(ctx->iostream, wrk);
  124. li_stream_attach(&ctx->fcgi_out, &wrk->loop);
  125. li_stream_attach(&ctx->fcgi_in, &wrk->loop);
  126. }
  127. static void backend_new(liBackendPool *bpool, liWorker *wrk, liBackendConnection *bcon) {
  128. liFastCGIBackendPool_p *pool = LI_CONTAINER_OF(bpool->config, liFastCGIBackendPool_p, config);
  129. liFastCGIBackendContext *ctx = g_slice_new0(liFastCGIBackendContext);
  130. fcgi_debug("backend_new\n");
  131. ctx->refcount = 3; /* backend_close, fcgi_out, fcgi_in */
  132. ctx->pool = pool;
  133. ctx->wrk = wrk;
  134. ctx->iostream = li_iostream_new(wrk, li_event_io_fd(&bcon->watcher), li_stream_simple_socket_io_cb, NULL);
  135. li_event_set_keep_loop_alive(&ctx->iostream->io_watcher, FALSE);
  136. li_stream_init(&ctx->fcgi_out, &wrk->loop, fastcgi_stream_out);
  137. li_stream_init(&ctx->fcgi_in, &wrk->loop, fastcgi_stream_in);
  138. li_stream_connect(&ctx->iostream->stream_in, &ctx->fcgi_in);
  139. li_stream_connect(&ctx->fcgi_out, &ctx->iostream->stream_out);
  140. ctx->subcon = bcon;
  141. bcon->data = ctx;
  142. }
  143. static void backend_ctx_unref(liFastCGIBackendContext *ctx) {
  144. LI_FORCE_ASSERT(g_atomic_int_get(&ctx->refcount) > 0);
  145. if (g_atomic_int_dec_and_test(&ctx->refcount)) {
  146. g_slice_free(liFastCGIBackendContext, ctx);
  147. }
  148. }
  149. static void backend_close(liBackendPool *bpool, liWorker *wrk, liBackendConnection *bcon) {
  150. liFastCGIBackendContext *ctx = bcon->data;
  151. UNUSED(bpool);
  152. LI_FORCE_ASSERT(NULL != ctx->pool);
  153. LI_FORCE_ASSERT(wrk == ctx->wrk);
  154. ctx->pool = NULL;
  155. LI_FORCE_ASSERT(NULL == ctx->currentcon);
  156. fcgi_debug("backend_close\n");
  157. if (NULL != ctx->iostream) {
  158. int fd;
  159. li_stream_simple_socket_close(ctx->iostream, FALSE);
  160. fd = li_iostream_reset(ctx->iostream);
  161. LI_FORCE_ASSERT(-1 == fd);
  162. ctx->iostream = NULL;
  163. }
  164. li_stream_reset(&ctx->fcgi_in);
  165. li_stream_reset(&ctx->fcgi_out);
  166. li_stream_release(&ctx->fcgi_in);
  167. li_stream_release(&ctx->fcgi_out);
  168. backend_ctx_unref(ctx);
  169. li_event_io_set_fd(&bcon->watcher, -1);
  170. }
  171. static void backend_free(liBackendPool *bpool) {
  172. liFastCGIBackendPool_p *pool = LI_CONTAINER_OF(bpool->config, liFastCGIBackendPool_p, config);
  173. li_sockaddr_clear(&pool->config.sock_addr);
  174. g_slice_free(liFastCGIBackendPool_p, pool);
  175. }
  176. static liBackendCallbacks backend_cbs = {
  177. backend_detach_thread,
  178. backend_attach_thread,
  179. backend_new,
  180. backend_close,
  181. backend_free
  182. };
  183. static void fastcgi_check_put(liFastCGIBackendContext *ctx) {
  184. /* wait for li_fastcgi_backend_put() */
  185. if (NULL != ctx->currentcon) return;
  186. /* already inactive */
  187. if (!ctx->is_active) return;
  188. /* wait for vrequest streams to disconnect */
  189. if (NULL != ctx->fcgi_in.dest || NULL != ctx->fcgi_out.source) return;
  190. li_stream_disconnect(&ctx->fcgi_out);
  191. li_stream_disconnect_dest(&ctx->fcgi_in);
  192. ctx->is_active = FALSE;
  193. li_stream_set_cqlimit(NULL, &ctx->fcgi_in, NULL);
  194. li_stream_set_cqlimit(&ctx->fcgi_out, NULL, NULL);
  195. if (NULL != ctx->iostream) {
  196. li_event_io_set_fd(&ctx->subcon->watcher, li_event_io_fd(&ctx->iostream->io_watcher));
  197. li_event_set_keep_loop_alive(&ctx->iostream->io_watcher, FALSE);
  198. LI_FORCE_ASSERT(NULL == ctx->iostream->stream_in.out->limit);
  199. LI_FORCE_ASSERT(NULL == ctx->iostream->stream_out.out->limit);
  200. } else {
  201. li_event_io_set_fd(&ctx->subcon->watcher, -1);
  202. }
  203. LI_FORCE_ASSERT(NULL == ctx->fcgi_in.out->limit);
  204. LI_FORCE_ASSERT(NULL == ctx->fcgi_out.out->limit);
  205. fcgi_debug("li_backend_put\n");
  206. li_backend_put(ctx->wrk, ctx->pool->public.subpool, ctx->subcon, TRUE); /* disable keep-alive for now */
  207. }
  208. /* destroys ctx */
  209. static void fastcgi_reset(liFastCGIBackendContext *ctx) {
  210. if (NULL == ctx->pool) return;
  211. fcgi_debug("fastcgi_reset\n");
  212. if (!ctx->is_active) {
  213. li_backend_connection_closed(ctx->pool->public.subpool, ctx->subcon);
  214. } else {
  215. int fd;
  216. const liFastCGIBackendCallbacks *callbacks = ctx->pool->callbacks;
  217. liFastCGIBackendConnection_p *currentcon = ctx->currentcon;
  218. liIOStream *iostream = ctx->iostream;
  219. if (NULL == iostream) return;
  220. ctx->request_done = TRUE;
  221. ctx->iostream = NULL;
  222. li_stream_simple_socket_close(iostream, TRUE);
  223. fd = li_iostream_reset(iostream);
  224. LI_FORCE_ASSERT(-1 == fd);
  225. li_stream_disconnect(&ctx->fcgi_out);
  226. li_stream_disconnect_dest(&ctx->fcgi_in);
  227. if (NULL != currentcon) {
  228. callbacks->reset_cb(currentcon->vr, &ctx->pool->public, &currentcon->public);
  229. }
  230. }
  231. }
  232. /**********************************************************************************/
  233. /* fastcgi stream send helper */
  234. static const gchar __padding[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  235. static void append_padding(GByteArray *a, guint8 padlen) {
  236. g_byte_array_append(a, (guint8*) __padding, padlen);
  237. }
  238. static void l_byte_array_append_c(GByteArray *a, char c) {
  239. g_byte_array_append(a, (guint8*) &c, 1);
  240. }
  241. /* returns padding length */
  242. static guint8 stream_build_fcgi_record(GByteArray *buf, guint8 type, guint16 requestid, guint16 datalen) {
  243. guint16 w;
  244. guint8 padlen = (8 - (datalen & 0x7)) % 8; /* padding must be < 8 */
  245. g_byte_array_set_size(buf, FCGI_HEADER_LEN);
  246. g_byte_array_set_size(buf, 0);
  247. l_byte_array_append_c(buf, FCGI_VERSION_1);
  248. l_byte_array_append_c(buf, type);
  249. w = htons(requestid);
  250. g_byte_array_append(buf, (const guint8*) &w, sizeof(w));
  251. w = htons(datalen);
  252. g_byte_array_append(buf, (const guint8*) &w, sizeof(w));
  253. l_byte_array_append_c(buf, padlen);
  254. l_byte_array_append_c(buf, 0);
  255. return padlen;
  256. }
  257. /* returns padding length */
  258. static guint8 stream_send_fcgi_record(liChunkQueue *out, guint8 type, guint16 requestid, guint16 datalen) {
  259. GByteArray *record = g_byte_array_sized_new(FCGI_HEADER_LEN);
  260. guint8 padlen = stream_build_fcgi_record(record, type, requestid, datalen);
  261. li_chunkqueue_append_bytearr(out, record);
  262. return padlen;
  263. }
  264. static void stream_send_data(liChunkQueue *out, guint8 type, guint16 requestid, const gchar *data, size_t datalen) {
  265. while (datalen > 0) {
  266. guint16 tosend = (datalen > G_MAXUINT16) ? G_MAXUINT16 : datalen;
  267. guint8 padlen = stream_send_fcgi_record(out, type, requestid, tosend);
  268. GByteArray *tmpa = g_byte_array_sized_new(tosend + padlen);
  269. g_byte_array_append(tmpa, (const guint8*) data, tosend);
  270. append_padding(tmpa, padlen);
  271. li_chunkqueue_append_bytearr(out, tmpa);
  272. data += tosend;
  273. datalen -= tosend;
  274. }
  275. }
  276. /* kills the data */
  277. static void stream_send_bytearr(liChunkQueue *out, guint8 type, guint16 requestid, GByteArray *data) {
  278. if (data->len > G_MAXUINT16) {
  279. stream_send_data(out, type, requestid, (const gchar*) data->data, data->len);
  280. g_byte_array_free(data, TRUE);
  281. } else {
  282. guint8 padlen = stream_send_fcgi_record(out, type, requestid, data->len);
  283. append_padding(data, padlen);
  284. li_chunkqueue_append_bytearr(out, data);
  285. }
  286. }
  287. static void stream_send_chunks(liChunkQueue *out, guint8 type, guint16 requestid, liChunkQueue *in) {
  288. while (in->length > 0) {
  289. guint16 tosend = (in->length > G_MAXUINT16) ? G_MAXUINT16 : in->length;
  290. guint8 padlen = stream_send_fcgi_record(out, type, requestid, tosend);
  291. li_chunkqueue_steal_len(out, in, tosend);
  292. li_chunkqueue_append_mem(out, __padding, padlen);
  293. }
  294. }
  295. static void stream_send_begin(liChunkQueue *out, guint16 requestid) {
  296. GByteArray *buf = g_byte_array_sized_new(16);
  297. guint16 w;
  298. LI_FORCE_ASSERT(1 == requestid);
  299. stream_build_fcgi_record(buf, FCGI_BEGIN_REQUEST, requestid, 8);
  300. w = htons(FCGI_RESPONDER);
  301. g_byte_array_append(buf, (const guint8*) &w, sizeof(w));
  302. l_byte_array_append_c(buf, 0 /* FCGI_KEEP_CONN */); /* disabled keep-alive for now */
  303. append_padding(buf, 5);
  304. li_chunkqueue_append_bytearr(out, buf);
  305. }
  306. /* end fastcgi stream send helpers */
  307. /**********************************************************************************/
  308. /**********************************************************************************/
  309. /* fastcgi environment build helpers */
  310. static gboolean _append_ba_len(GByteArray *a, size_t len) {
  311. if (len > G_MAXINT32) return FALSE;
  312. if (len > 127) {
  313. guint32 i = htonl(len | (1 << 31));
  314. g_byte_array_append(a, (const guint8*) &i, sizeof(i));
  315. } else {
  316. l_byte_array_append_c(a, (guint8) len);
  317. }
  318. return TRUE;
  319. }
  320. static gboolean append_key_value_pair(GByteArray *a, const gchar *key, size_t keylen, const gchar *val, size_t valuelen) {
  321. if (!_append_ba_len(a, keylen) || !_append_ba_len(a, valuelen)) return FALSE;
  322. g_byte_array_append(a, (const guint8*) key, keylen);
  323. g_byte_array_append(a, (const guint8*) val, valuelen);
  324. return TRUE;
  325. }
  326. static void cgi_add_cb(gpointer param, const gchar *key, size_t keylen, const gchar *val, size_t valuelen) {
  327. GByteArray *a = (GByteArray*) param;
  328. append_key_value_pair(a, key, keylen, val, valuelen);
  329. }
  330. static void fastcgi_send_env(liVRequest *vr, liChunkQueue *out, int requestid) {
  331. GByteArray *buf = g_byte_array_sized_new(0);
  332. liEnvironmentDup *envdup;
  333. envdup = li_environment_make_dup(&vr->env);
  334. li_environment_dup2cgi(vr, envdup, cgi_add_cb, buf);
  335. if (buf->len > 0) stream_send_bytearr(out, FCGI_PARAMS, requestid, buf);
  336. stream_send_fcgi_record(out, FCGI_PARAMS, requestid, 0);
  337. }
  338. /* end fastcgi environment build helpers */
  339. /**********************************************************************************/
  340. /* request body -> fastcgi */
  341. static void fastcgi_stream_out(liStream *stream, liStreamEvent event) {
  342. liFastCGIBackendContext *ctx = LI_CONTAINER_OF(stream, liFastCGIBackendContext, fcgi_out);
  343. fcgi_debug("fastcgi_stream_out event: %s\n", li_stream_event_string(event));
  344. switch (event) {
  345. case LI_STREAM_NEW_DATA:
  346. if (NULL == stream->source) return;
  347. if (NULL == stream->dest || ctx->stdin_closed) {
  348. li_chunkqueue_skip_all(stream->source->out);
  349. return;
  350. }
  351. stream_send_chunks(stream->out, FCGI_STDIN, 1, stream->source->out);
  352. if (stream->source->out->is_closed && !ctx->stdin_closed) {
  353. fcgi_debug("fcgi_out: closing stdin\n");
  354. ctx->stdin_closed = TRUE;
  355. stream_send_fcgi_record(stream->out, FCGI_STDIN, 1, 0);
  356. li_stream_disconnect(stream);
  357. }
  358. li_stream_notify(stream);
  359. break;
  360. case LI_STREAM_CONNECTED_SOURCE:
  361. /* support Connection: Upgrade by reopening stdin. not standard compliant,
  362. * but the backend asked for it :) */
  363. ctx->stdin_closed = FALSE;
  364. break;
  365. case LI_STREAM_DISCONNECTED_SOURCE:
  366. if (!ctx->stdin_closed) {
  367. fcgi_debug("fcgi_out: lost request before request body was sent to FastCGI\n");
  368. fastcgi_reset(ctx);
  369. } else {
  370. fastcgi_check_put(ctx);
  371. }
  372. break;
  373. case LI_STREAM_DISCONNECTED_DEST:
  374. if (stream->out->length > 0) {
  375. fcgi_debug("fcgi_out: lost iostream\n");
  376. li_chunkqueue_skip_all(stream->out);
  377. }
  378. break;
  379. case LI_STREAM_DESTROY:
  380. backend_ctx_unref(ctx);
  381. default:
  382. break;
  383. }
  384. }
  385. static void fastcgi_decode(liFastCGIBackendContext *ctx) {
  386. liChunkQueue *in;
  387. liWorker *wrk;
  388. LI_FORCE_ASSERT(NULL != ctx->iostream);
  389. in = ctx->iostream->stream_in.out;
  390. wrk = li_worker_from_iostream(ctx->iostream);
  391. while (NULL != ctx->iostream && 0 < in->length) {
  392. gboolean newdata = FALSE;
  393. if (0 == ctx->remainingContent && 0 == ctx->remainingPadding) {
  394. unsigned char header[FCGI_HEADER_LEN];
  395. if (in->length < FCGI_HEADER_LEN) break;
  396. /* reading memory buffers can't fail */
  397. if (!li_chunkqueue_extract_to_memory(in, FCGI_HEADER_LEN, header, NULL)) abort();
  398. li_chunkqueue_skip(in, FCGI_HEADER_LEN);
  399. ctx->version = header[0];
  400. ctx->type = header[1];
  401. ctx->requestID = (header[2] << 8) + header[3];
  402. ctx->contentLength = (header[4] << 8) + header[5];
  403. ctx->paddingLength = header[6];
  404. ctx->remainingContent = ctx->contentLength;
  405. ctx->remainingPadding = ctx->paddingLength;
  406. if (FCGI_VERSION_1 != ctx->version) {
  407. ERROR(wrk->srv, "(%s) Unknown fastcgi protocol version %i",
  408. li_sockaddr_to_string(ctx->pool->config.sock_addr, wrk->tmp_str, TRUE)->str,
  409. (gint) ctx->version);
  410. fastcgi_reset(ctx);
  411. return;
  412. }
  413. newdata = TRUE;
  414. fcgi_debug("fastcgi packet type %s (%i), payload %i\n", fcgi_type_string(ctx->type), ctx->type, (int) ctx->contentLength);
  415. }
  416. if (newdata || (ctx->remainingContent > 0 && in->length > 0)) {
  417. switch (ctx->type) {
  418. case FCGI_END_REQUEST:
  419. if (8 != ctx->contentLength) {
  420. ERROR(wrk->srv, "(%s) FastCGI end request message has unexpected length %i != 8",
  421. li_sockaddr_to_string(ctx->pool->config.sock_addr, wrk->tmp_str, TRUE)->str,
  422. (gint) ctx->contentLength);
  423. fastcgi_reset(ctx);
  424. return;
  425. }
  426. if (in->length < 8) return; /* wait for more */
  427. {
  428. unsigned char endreq[8];
  429. guint8 protocolStatus;
  430. if (!li_chunkqueue_extract_to_memory(in, 8, endreq, NULL)) abort();
  431. li_chunkqueue_skip(in, 8);
  432. ctx->remainingContent -= 8;
  433. protocolStatus = endreq[4];
  434. if (FCGI_REQUEST_COMPLETE != protocolStatus) {
  435. fcgi_debug("fcgi_out: FCGI_END_REQUEST with protocolStatus %i != FCGI_REQUEST_COMPLETE\n", (int) protocolStatus);
  436. fastcgi_reset(ctx);
  437. return;
  438. }
  439. ctx->stdin_closed = TRUE;
  440. ctx->stdout_closed = TRUE;
  441. ctx->stderr_closed = TRUE;
  442. ctx->request_done = TRUE;
  443. ctx->fcgi_in.out->is_closed = TRUE;
  444. li_stream_notify_later(&ctx->fcgi_in);
  445. if (ctx->currentcon) {
  446. guint32 appStatus = (endreq[0] << 24) | (endreq[1] << 16) | (endreq[2] << 8) | endreq[3];
  447. const liFastCGIBackendCallbacks *callbacks = ctx->pool->callbacks;
  448. fcgi_debug("fastcgi end request: %i\n", appStatus);
  449. callbacks->end_request_cb(ctx->currentcon->vr, &ctx->pool->public, &ctx->currentcon->public, appStatus);
  450. }
  451. }
  452. break;
  453. case FCGI_STDOUT:
  454. if (0 == ctx->contentLength) {
  455. fcgi_debug("fastcgi stdout eof\n");
  456. ctx->stdout_closed = TRUE;
  457. } else if (ctx->stdout_closed) {
  458. fcgi_debug("fastcgi stdout data after eof\n");
  459. fastcgi_reset(ctx);
  460. return;
  461. } else {
  462. int len = MIN(in->length, ctx->remainingContent);
  463. #ifdef FCGI_DEBUG
  464. GString *stdoutdata = g_string_new(0);
  465. li_chunkqueue_extract_to(in, len, stdoutdata, NULL);
  466. fcgi_debug("fastcgi stdout data: '%s'\n", stdoutdata->str);
  467. g_string_free(stdoutdata, TRUE);
  468. #endif
  469. li_chunkqueue_steal_len(ctx->fcgi_in.out, in, len);
  470. ctx->remainingContent -= len;
  471. }
  472. li_stream_notify_later(&ctx->fcgi_in);
  473. break;
  474. case FCGI_STDERR:
  475. if (0 == ctx->contentLength) {
  476. ctx->stderr_closed = TRUE;
  477. break;
  478. }
  479. if (ctx->stderr_closed) {
  480. fcgi_debug("fastcgi stderr data after stderr end-of-stream\n");
  481. fastcgi_reset(ctx);
  482. return;
  483. } else {
  484. gint len = ctx->remainingContent > in->length ? in->length : ctx->remainingContent;
  485. GString *errormsg = g_string_new(0);
  486. li_chunkqueue_extract_to(in, len, errormsg, NULL);
  487. li_chunkqueue_skip(in, len);
  488. ctx->remainingContent -= len;
  489. fcgi_debug("fastcgi stderr data: '%s'\n", errormsg->str);
  490. if (NULL != ctx->currentcon) {
  491. const liFastCGIBackendCallbacks *callbacks = ctx->pool->callbacks;
  492. callbacks->fastcgi_stderr_cb(ctx->currentcon->vr, &ctx->pool->public, &ctx->currentcon->public, errormsg);
  493. }
  494. g_string_free(errormsg, TRUE);
  495. }
  496. break;
  497. default:
  498. if (newdata) {
  499. WARNING(wrk->srv, "(%s) Unhandled fastcgi record type %i",
  500. li_sockaddr_to_string(ctx->pool->config.sock_addr, wrk->tmp_str, TRUE)->str,
  501. (gint) ctx->type);
  502. }
  503. {
  504. int len = li_chunkqueue_skip(in, ctx->remainingContent);
  505. ctx->remainingContent -= len;
  506. }
  507. break;
  508. }
  509. }
  510. if (NULL == ctx->iostream || 0 == in->length || ctx->remainingContent > 0) break;
  511. if (ctx->remainingPadding > 0) {
  512. int len = li_chunkqueue_skip(in, ctx->remainingPadding);
  513. ctx->remainingPadding -= len;
  514. }
  515. }
  516. if (NULL != ctx->iostream && (in->is_closed && !ctx->request_done)) {
  517. if (0 != in->length || !ctx->stdout_closed) {
  518. fcgi_debug("unexpected eof, still have partial fastcgi record header\n");
  519. fastcgi_reset(ctx);
  520. } else {
  521. ctx->stdin_closed = ctx->stdout_closed = ctx->stderr_closed = ctx->request_done = TRUE;
  522. ctx->fcgi_in.out->is_closed = TRUE;
  523. li_stream_simple_socket_close(ctx->iostream, FALSE);
  524. }
  525. }
  526. }
  527. /* fastcgi -> response body */
  528. static void fastcgi_stream_in(liStream *stream, liStreamEvent event) {
  529. liFastCGIBackendContext *ctx = LI_CONTAINER_OF(stream, liFastCGIBackendContext, fcgi_in);
  530. fcgi_debug("fastcgi_stream_in event: %s\n", li_stream_event_string(event));
  531. switch (event) {
  532. case LI_STREAM_NEW_DATA:
  533. fastcgi_decode(ctx);
  534. break;
  535. case LI_STREAM_DISCONNECTED_SOURCE:
  536. if (!ctx->request_done) {
  537. fcgi_debug("fastcgi backend closed connection before request was finished\n");
  538. fastcgi_reset(ctx);
  539. }
  540. break;
  541. case LI_STREAM_DISCONNECTED_DEST:
  542. if (!ctx->stdout_closed) {
  543. fcgi_debug("request aborted (by client?) before request was finished\n");
  544. fastcgi_reset(ctx);
  545. } else {
  546. fastcgi_check_put(ctx);
  547. }
  548. break;
  549. case LI_STREAM_DESTROY:
  550. backend_ctx_unref(ctx);
  551. default:
  552. break;
  553. }
  554. }
  555. liFastCGIBackendPool* li_fastcgi_backend_pool_new(const liFastCGIBackendConfig *config) {
  556. liFastCGIBackendPool_p *pool = g_slice_new0(liFastCGIBackendPool_p);
  557. pool->config.callbacks = &backend_cbs;
  558. pool->config.sock_addr = li_sockaddr_dup(config->sock_addr);
  559. pool->config.max_connections = config->max_connections;
  560. pool->config.idle_timeout = config->idle_timeout;
  561. pool->config.connect_timeout = config->connect_timeout;
  562. pool->config.wait_timeout = config->wait_timeout;
  563. pool->config.disable_time = config->disable_time;
  564. pool->config.max_requests = config->max_requests;
  565. pool->config.watch_for_close = FALSE;
  566. pool->callbacks = config->callbacks;
  567. pool->public.subpool = li_backend_pool_new(&pool->config);
  568. return &pool->public;
  569. }
  570. void li_fastcgi_backend_pool_free(liFastCGIBackendPool *bpool) {
  571. li_backend_pool_free(bpool->subpool);
  572. }
  573. liBackendResult li_fastcgi_backend_get(liVRequest *vr, liFastCGIBackendPool *bpool, liFastCGIBackendConnection **pbcon, liFastCGIBackendWait **pbwait) {
  574. liFastCGIBackendPool_p *pool = LI_CONTAINER_OF(bpool, liFastCGIBackendPool_p, public);
  575. liBackendConnection *subcon = NULL;
  576. liBackendWait *subwait = (liBackendWait*) *pbwait;
  577. liBackendResult res;
  578. fcgi_debug("li_fastcgi_backend_get\n");
  579. res = li_backend_get(vr, pool->public.subpool, &subcon, &subwait);
  580. *pbwait = (liFastCGIBackendWait*) subwait;
  581. if (subcon != NULL) {
  582. liFastCGIBackendConnection_p *con = g_slice_new0(liFastCGIBackendConnection_p);
  583. liFastCGIBackendContext *ctx = subcon->data;
  584. liStream *http_out;
  585. LI_FORCE_ASSERT(NULL != ctx);
  586. LI_FORCE_ASSERT(LI_BACKEND_SUCCESS == res);
  587. con->ctx = ctx;
  588. con->vr = vr;
  589. ctx->currentcon = con;
  590. ctx->is_active = TRUE;
  591. *pbcon = &con->public;
  592. fcgi_debug("li_fastcgi_backend_get: got backend\n");
  593. LI_FORCE_ASSERT(vr->wrk == li_worker_from_iostream(ctx->iostream));
  594. LI_FORCE_ASSERT(vr->wrk == li_worker_from_stream(&ctx->fcgi_in));
  595. LI_FORCE_ASSERT(vr->wrk == li_worker_from_stream(&ctx->fcgi_out));
  596. LI_FORCE_ASSERT(li_event_active(&ctx->iostream->io_watcher));
  597. li_event_set_keep_loop_alive(&ctx->iostream->io_watcher, TRUE);
  598. LI_FORCE_ASSERT(NULL == ctx->fcgi_in.dest);
  599. LI_FORCE_ASSERT(NULL == ctx->fcgi_out.source);
  600. LI_FORCE_ASSERT(NULL != ctx->iostream);
  601. LI_FORCE_ASSERT(-1 != li_event_io_fd(&ctx->iostream->io_watcher));
  602. LI_FORCE_ASSERT(ctx->iostream->stream_in.dest == &ctx->fcgi_in);
  603. LI_FORCE_ASSERT(ctx->iostream->stream_out.source == &ctx->fcgi_out);
  604. ctx->stdin_closed = ctx->stdout_closed = ctx->stderr_closed = ctx->request_done = FALSE;
  605. li_chunkqueue_reset(ctx->fcgi_in.out);
  606. stream_send_begin(ctx->fcgi_out.out, 1);
  607. fastcgi_send_env(vr, ctx->fcgi_out.out, 1);
  608. li_stream_notify_later(&ctx->fcgi_out);
  609. http_out = li_stream_http_response_handle(&ctx->fcgi_in, vr, TRUE, TRUE, FALSE);
  610. li_vrequest_handle_indirect(vr, NULL);
  611. li_vrequest_indirect_connect(vr, &ctx->fcgi_out, http_out);
  612. li_stream_release(http_out);
  613. } else {
  614. *pbcon = NULL;
  615. LI_FORCE_ASSERT(LI_BACKEND_SUCCESS != res);
  616. if (LI_BACKEND_WAIT == res) LI_FORCE_ASSERT(NULL != subwait);
  617. fcgi_debug("li_fastcgi_backend_get: still waiting\n");
  618. }
  619. return res;
  620. }
  621. void li_fastcgi_backend_wait_stop(liVRequest *vr, liFastCGIBackendPool *bpool, liFastCGIBackendWait **pbwait) {
  622. liBackendWait *subwait = (liBackendWait*) *pbwait;
  623. *pbwait = NULL;
  624. li_backend_wait_stop(vr, bpool->subpool, &subwait);
  625. }
  626. void li_fastcgi_backend_put(liFastCGIBackendConnection *bcon) {
  627. liFastCGIBackendConnection_p *con = LI_CONTAINER_OF(bcon, liFastCGIBackendConnection_p, public);
  628. liFastCGIBackendContext *ctx = con->ctx;
  629. LI_FORCE_ASSERT(NULL != ctx && con == ctx->currentcon);
  630. ctx->currentcon = NULL;
  631. con->ctx = NULL;
  632. con->vr = NULL;
  633. g_slice_free(liFastCGIBackendConnection_p, con);
  634. fastcgi_check_put(ctx);
  635. }