FastCGI application to run cgi applications https://redmine.lighttpd.net/projects/fcgi-cgi
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.
 
 
 
 
 
 

896 lines
26 KiB

  1. #ifdef HAVE_CONFIG_H
  2. #include "config.h"
  3. #endif
  4. #include "fastcgi.h"
  5. #include <arpa/inet.h>
  6. #include <errno.h>
  7. #include <sys/socket.h>
  8. #include <fcntl.h>
  9. #include <unistd.h>
  10. #include <string.h>
  11. typedef struct fastcgi_queue_link {
  12. GList queue_link;
  13. enum { FASTCGI_QUEUE_STRING, FASTCGI_QUEUE_BYTEARRAY } elem_type;
  14. } fastcgi_queue_link;
  15. /* some util functions */
  16. #define GSTR_LEN(x) ((x) ? (x)->str : ""), ((x) ? (x)->len : 0)
  17. #define GBARR_LEN(x) ((x)->data), ((x)->len)
  18. #define UNUSED(x) ((void)(x))
  19. #define ERROR(...) g_printerr("fastcgi.c:" G_STRINGIFY(__LINE__) ": " __VA_ARGS__)
  20. static void fd_init(int fd) {
  21. #ifdef _WIN32
  22. int i = 1;
  23. #endif
  24. #ifdef FD_CLOEXEC
  25. /* close fd on exec (cgi) */
  26. fcntl(fd, F_SETFD, FD_CLOEXEC);
  27. #endif
  28. #ifdef O_NONBLOCK
  29. fcntl(fd, F_SETFL, O_NONBLOCK | O_RDWR);
  30. #elif defined _WIN32
  31. ioctlsocket(fd, FIONBIO, &i);
  32. #endif
  33. }
  34. static fastcgi_queue_link* fastcgi_queue_link_new_string(GString *s) {
  35. fastcgi_queue_link *l = g_slice_new0(fastcgi_queue_link);
  36. l->queue_link.data = s;
  37. l->elem_type = FASTCGI_QUEUE_STRING;
  38. return l;
  39. }
  40. static fastcgi_queue_link* fastcgi_queue_link_new_bytearray(GByteArray *a) {
  41. fastcgi_queue_link *l = g_slice_new0(fastcgi_queue_link);
  42. l->queue_link.data = a;
  43. l->elem_type = FASTCGI_QUEUE_BYTEARRAY ;
  44. return l;
  45. }
  46. static void fastcgi_queue_link_free(fastcgi_queue *queue, fastcgi_queue_link *l) {
  47. switch (l->elem_type) {
  48. case FASTCGI_QUEUE_STRING:
  49. if (queue) queue->length -= ((GString*)l->queue_link.data)->len;
  50. g_string_free(l->queue_link.data, TRUE);
  51. break;
  52. case FASTCGI_QUEUE_BYTEARRAY:
  53. if (queue) queue->length -= ((GByteArray*)l->queue_link.data)->len;
  54. g_byte_array_free(l->queue_link.data, TRUE);
  55. break;
  56. }
  57. g_slice_free(fastcgi_queue_link, l);
  58. }
  59. static fastcgi_queue_link *fastcgi_queue_peek_head(fastcgi_queue *queue) {
  60. return (fastcgi_queue_link*) g_queue_peek_head_link(&queue->queue);
  61. }
  62. static fastcgi_queue_link *fastcgi_queue_pop_head(fastcgi_queue *queue) {
  63. return (fastcgi_queue_link*) g_queue_pop_head_link(&queue->queue);
  64. }
  65. void fastcgi_queue_clear(fastcgi_queue *queue) {
  66. fastcgi_queue_link *l;
  67. queue->offset = 0;
  68. while (NULL != (l = fastcgi_queue_pop_head(queue))) {
  69. fastcgi_queue_link_free(queue, l);
  70. }
  71. g_assert(0 == queue->length);
  72. }
  73. void fastcgi_queue_append_string(fastcgi_queue *queue, GString *buf) {
  74. fastcgi_queue_link *l;
  75. if (!buf) return;
  76. if (!buf->len) { g_string_free(buf, TRUE); return; }
  77. l = fastcgi_queue_link_new_string(buf);
  78. g_queue_push_tail_link(&queue->queue, (GList*) l);
  79. queue->length += buf->len;
  80. }
  81. void fastcgi_queue_append_bytearray(fastcgi_queue *queue, GByteArray *buf) {
  82. fastcgi_queue_link *l;
  83. if (!buf) return;
  84. if (!buf->len) { g_byte_array_free(buf, TRUE); return; }
  85. l = fastcgi_queue_link_new_bytearray(buf);
  86. g_queue_push_tail_link(&queue->queue, (GList*) l);
  87. queue->length += buf->len;
  88. }
  89. /* return values: 0 ok, -1 error, -2 con closed */
  90. gint fastcgi_queue_write(int fd, fastcgi_queue *queue, gsize max_write) {
  91. gsize rem_write = max_write;
  92. g_assert(rem_write <= G_MAXSSIZE);
  93. #ifdef TCP_CORK
  94. int corked = 0;
  95. #endif
  96. #ifdef TCP_CORK
  97. /* Linux: put a cork into the socket as we want to combine the write() calls
  98. * but only if we really have multiple chunks
  99. */
  100. if (queue->queue.length > 1) {
  101. corked = 1;
  102. setsockopt(fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
  103. }
  104. #endif
  105. while (rem_write > 0 && queue->length > 0) {
  106. fastcgi_queue_link *l = fastcgi_queue_peek_head(queue);
  107. gsize towrite, datalen;
  108. gssize res;
  109. gchar *data;
  110. switch (l->elem_type) {
  111. case FASTCGI_QUEUE_STRING:
  112. data = ((GString*) l->queue_link.data)->str;
  113. datalen = towrite = ((GString*) l->queue_link.data)->len;
  114. break;
  115. case FASTCGI_QUEUE_BYTEARRAY:
  116. data = (gchar*) ((GByteArray*) l->queue_link.data)->data;
  117. datalen = towrite = ((GByteArray*) l->queue_link.data)->len;
  118. break;
  119. default:
  120. g_error("invalid fastcgi_queue_link type\n");
  121. }
  122. towrite -= queue->offset; data += queue->offset;
  123. if (towrite > rem_write) towrite = rem_write;
  124. res = write(fd, data, towrite);
  125. if (-1 == res) {
  126. #ifdef TCP_CORK
  127. if (corked) {
  128. corked = 0;
  129. setsockopt(fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
  130. }
  131. #endif
  132. switch (errno) {
  133. case EINTR:
  134. case EAGAIN:
  135. #if EWOULDBLOCK != EAGAIN
  136. case EWOULDBLOCK:
  137. #endif
  138. return 0; /* try again later */
  139. case ECONNRESET:
  140. case EPIPE:
  141. return -2;
  142. default:
  143. ERROR("write to fd=%d failed, %s\n", fd, g_strerror(errno) );
  144. return -1;
  145. }
  146. } else {
  147. queue->offset += res;
  148. rem_write -= res;
  149. if (queue->offset == datalen) {
  150. queue->offset = 0;
  151. fastcgi_queue_link_free(queue, fastcgi_queue_pop_head(queue));
  152. }
  153. }
  154. }
  155. #ifdef TCP_CORK
  156. if (corked) {
  157. corked = 0;
  158. setsockopt(fd, IPPROTO_TCP, TCP_CORK, &corked, sizeof(corked));
  159. }
  160. #endif
  161. return 0;
  162. }
  163. static void ev_io_add_events(struct ev_loop *loop, ev_io *watcher, int events) {
  164. if ((watcher->events & events) == events) return;
  165. ev_io_stop(loop, watcher);
  166. ev_io_set(watcher, watcher->fd, watcher->events | events);
  167. ev_io_start(loop, watcher);
  168. }
  169. static void ev_io_rem_events(struct ev_loop *loop, ev_io *watcher, int events) {
  170. if (0 == (watcher->events & events)) return;
  171. ev_io_stop(loop, watcher);
  172. ev_io_set(watcher, watcher->fd, watcher->events & ~events);
  173. ev_io_start(loop, watcher);
  174. }
  175. /* end: some util functions */
  176. static const guint8 __padding[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  177. static void append_padding_str(GString *s, guint8 padlen) {
  178. g_string_append_len(s, (const gchar*) __padding, padlen);
  179. }
  180. static void append_padding_bytearray(GByteArray *a, guint8 padlen) {
  181. g_byte_array_append(a, __padding, padlen);
  182. }
  183. /* returns padding length */
  184. static guint8 stream_build_fcgi_record(GByteArray *buf, guint8 type, guint16 requestid, guint16 datalen) {
  185. guint8 padlen = (8 - (datalen & 0x7)) % 8; /* padding must be < 8 */
  186. /* alloc enough space */
  187. g_byte_array_set_size(buf, FCGI_HEADER_LEN);
  188. buf->len = 0;
  189. buf->data[buf->len++] = FCGI_VERSION_1;
  190. buf->data[buf->len++] = type;
  191. buf->data[buf->len++] = (guint8) (requestid >> 8);
  192. buf->data[buf->len++] = (guint8) (requestid);
  193. buf->data[buf->len++] = (guint8) (datalen >> 8);
  194. buf->data[buf->len++] = (guint8) (datalen);
  195. buf->data[buf->len++] = padlen;
  196. buf->data[buf->len++] = 0;
  197. return padlen;
  198. }
  199. /* returns padding length */
  200. static guint8 stream_send_fcgi_record(fastcgi_queue *out, guint8 type, guint16 requestid, guint16 datalen) {
  201. GByteArray *record = g_byte_array_sized_new(FCGI_HEADER_LEN);
  202. guint8 padlen = stream_build_fcgi_record(record, type, requestid, datalen);
  203. fastcgi_queue_append_bytearray(out, record);
  204. return padlen;
  205. }
  206. static void stream_send_data(fastcgi_queue *out, guint8 type, guint16 requestid, const guint8 *data, size_t datalen) {
  207. while (datalen > 0) {
  208. guint16 tosend = (datalen > G_MAXUINT16) ? G_MAXUINT16 : datalen;
  209. guint8 padlen = stream_send_fcgi_record(out, type, requestid, tosend);
  210. GByteArray *buf = g_byte_array_sized_new(tosend + padlen);
  211. g_byte_array_append(buf, data, tosend);
  212. append_padding_bytearray(buf, padlen);
  213. fastcgi_queue_append_bytearray(out, buf);
  214. data += tosend;
  215. datalen -= tosend;
  216. }
  217. }
  218. /* kills string */
  219. static void stream_send_string(fastcgi_queue *out, guint8 type, guint16 requestid, GString *data) {
  220. if (data->len > G_MAXUINT16) {
  221. stream_send_data(out, type, requestid, (const guint8*) GSTR_LEN(data));
  222. g_string_free(data, TRUE);
  223. } else {
  224. guint8 padlen = stream_send_fcgi_record(out, type, requestid, data->len);
  225. append_padding_str(data, padlen);
  226. fastcgi_queue_append_string(out, data);
  227. }
  228. }
  229. /* kills bytearray */
  230. static void stream_send_bytearray(fastcgi_queue *out, guint8 type, guint16 requestid, GByteArray *data) {
  231. if (data->len > G_MAXUINT16) {
  232. stream_send_data(out, type, requestid, GBARR_LEN(data));
  233. g_byte_array_free(data, TRUE);
  234. } else {
  235. guint8 padlen = stream_send_fcgi_record(out, type, requestid, data->len);
  236. append_padding_bytearray(data, padlen);
  237. fastcgi_queue_append_bytearray(out, data);
  238. }
  239. }
  240. static void stream_send_end_request(fastcgi_queue *out, guint16 requestID, gint32 appStatus, enum FCGI_ProtocolStatus status) {
  241. GByteArray *record;
  242. record = g_byte_array_sized_new(16);
  243. stream_build_fcgi_record(record, FCGI_END_REQUEST, requestID, 8);
  244. /* alloc enough space */
  245. g_byte_array_set_size(record, 16);
  246. record->len = 8;
  247. appStatus = htonl(appStatus);
  248. g_byte_array_append(record, (const guchar*) &appStatus, sizeof(appStatus));
  249. record->data[record->len++] = status;
  250. g_byte_array_append(record, __padding, 3);
  251. fastcgi_queue_append_bytearray(out, record);
  252. }
  253. static void write_queue(fastcgi_connection *fcon) {
  254. if (fcon->closing) return;
  255. if (fastcgi_queue_write(fcon->fd, &fcon->write_queue, 256*1024) < 0) {
  256. fastcgi_connection_close(fcon);
  257. return;
  258. }
  259. if (fcon->fsrv->callbacks->cb_wrote_data) {
  260. fcon->fsrv->callbacks->cb_wrote_data(fcon);
  261. }
  262. if (!fcon->closing) {
  263. if (fcon->write_queue.length > 0) {
  264. ev_io_add_events(fcon->fsrv->loop, &fcon->fd_watcher, EV_WRITE);
  265. } else {
  266. ev_io_rem_events(fcon->fsrv->loop, &fcon->fd_watcher, EV_WRITE);
  267. if (0 == fcon->requestID) {
  268. if (!(fcon->flags & FCGI_KEEP_CONN)) {
  269. fastcgi_connection_close(fcon);
  270. }
  271. }
  272. }
  273. }
  274. }
  275. static GByteArray* read_chunk(fastcgi_connection *fcon, guint maxlen) {
  276. gssize res;
  277. GByteArray *buf;
  278. int tmp_errno;
  279. buf = g_byte_array_sized_new(maxlen);
  280. g_byte_array_set_size(buf, maxlen);
  281. if (0 == maxlen) return buf;
  282. res = read(fcon->fd, buf->data, maxlen);
  283. if (res == -1) {
  284. tmp_errno = errno;
  285. g_byte_array_free(buf, TRUE);
  286. errno = tmp_errno;
  287. return NULL;
  288. } else if (res == 0) {
  289. g_byte_array_free(buf, TRUE);
  290. errno = ECONNRESET;
  291. return NULL;
  292. } else {
  293. g_byte_array_set_size(buf, res);
  294. return buf;
  295. }
  296. }
  297. /* read content + padding, but only returns content data. decrements counters */
  298. static GByteArray *read_content(fastcgi_connection *fcon) {
  299. GByteArray *buf;
  300. buf = read_chunk(fcon, fcon->content_remaining + fcon->padding_remaining);
  301. if (!buf) return NULL;
  302. if (buf->len > fcon->content_remaining) {
  303. fcon->padding_remaining -= (buf->len - fcon->content_remaining);
  304. g_byte_array_set_size(buf, fcon->content_remaining);
  305. fcon->content_remaining = 0;
  306. } else {
  307. fcon->content_remaining -= buf->len;
  308. }
  309. return buf;
  310. }
  311. static gboolean read_append_chunk(fastcgi_connection *fcon, GByteArray *buf) {
  312. gssize res;
  313. int tmp_errno;
  314. guint curlen = buf->len;
  315. const guint maxlen = fcon->content_remaining + fcon->padding_remaining;
  316. if (0 == maxlen) return TRUE;
  317. g_byte_array_set_size(buf, curlen + maxlen);
  318. res = read(fcon->fd, buf->data + curlen, maxlen);
  319. if (res == -1) {
  320. tmp_errno = errno;
  321. g_byte_array_set_size(buf, curlen);
  322. errno = tmp_errno;
  323. return FALSE;
  324. } else if (res == 0) {
  325. g_byte_array_set_size(buf, curlen);
  326. errno = ECONNRESET;
  327. return FALSE;
  328. } else {
  329. /* remove padding data */
  330. if (res > fcon->content_remaining) {
  331. fcon->padding_remaining -= res - fcon->content_remaining;
  332. res = fcon->content_remaining;
  333. }
  334. g_byte_array_set_size(buf, curlen + res);
  335. fcon->content_remaining -= res;
  336. return TRUE;
  337. }
  338. }
  339. static gboolean read_key_value(fastcgi_connection *fcon, GByteArray *buf, guint *pos, gchar **key, guint *keylen, gchar **value, guint *valuelen) {
  340. const unsigned char *data = (const unsigned char*) buf->data;
  341. guint32 klen, vlen;
  342. guint p = *pos, len = buf->len;
  343. if (len - p < 2) return FALSE;
  344. klen = data[p++];
  345. if (klen & 0x80) {
  346. if (len - p < 100) return FALSE;
  347. klen = ((klen & 0x7f) << 24) | (data[p] << 16) | (data[p+1] << 8) | data[p+2];
  348. p += 3;
  349. }
  350. vlen = data[p++];
  351. if (vlen & 0x80) {
  352. if (len - p < 100) return FALSE;
  353. vlen = ((vlen & 0x7f) << 24) | (data[p] << 16) | (data[p+1] << 8) | data[p+2];
  354. p += 3;
  355. }
  356. if (klen > FASTCGI_MAX_KEYLEN || vlen > FASTCGI_MAX_VALUELEN) {
  357. fastcgi_connection_close(fcon);
  358. return FALSE;
  359. }
  360. if (len - p < klen + vlen) return FALSE;
  361. *key = (gchar*) &buf->data[p];
  362. *keylen = klen;
  363. p += klen;
  364. *value = (gchar*) &buf->data[p];
  365. *valuelen = vlen;
  366. p += vlen;
  367. *pos = p;
  368. return TRUE;
  369. }
  370. static void parse_params(const fastcgi_callbacks *fcbs, fastcgi_connection *fcon) {
  371. if (!fcon->current_header.contentLength) {
  372. fcbs->cb_new_request(fcon);
  373. g_byte_array_set_size(fcon->parambuf, 0);
  374. } else {
  375. guint pos = 0, keylen = 0, valuelen = 0;
  376. gchar *key = NULL, *value = NULL;
  377. while (read_key_value(fcon, fcon->parambuf, &pos, &key, &keylen, &value, &valuelen)) {
  378. gchar *envvar = g_malloc(keylen + valuelen + 2);
  379. memcpy(envvar, key, keylen);
  380. envvar[keylen] = '=';
  381. memcpy(envvar + keylen + 1, value, valuelen);
  382. envvar[keylen+valuelen+1] = '\0';
  383. g_ptr_array_add(fcon->environ, envvar);
  384. }
  385. if (!fcon->closing)
  386. g_byte_array_remove_range(fcon->parambuf, 0, pos);
  387. }
  388. }
  389. static void parse_get_values(fastcgi_connection *fcon) {
  390. /* just send the request back and don't insert results */
  391. GByteArray *tmp = g_byte_array_sized_new(0);
  392. stream_send_bytearray(&fcon->write_queue, FCGI_GET_VALUES_RESULT, 0, fcon->buffer);
  393. *fcon->buffer = *tmp;
  394. /* TODO: provide get-values result */
  395. }
  396. static void read_queue(fastcgi_connection *fcon) {
  397. gssize res;
  398. GByteArray *buf;
  399. const fastcgi_callbacks *fcbs = fcon->fsrv->callbacks;
  400. for (;;) {
  401. if (fcon->closing || fcon->read_suspended) return;
  402. if (fcon->headerbuf_used < 8) {
  403. const unsigned char *data = fcon->headerbuf;
  404. res = read(fcon->fd, fcon->headerbuf + fcon->headerbuf_used, 8 - fcon->headerbuf_used);
  405. if (0 == res) { errno = ECONNRESET; goto handle_error; }
  406. if (-1 == res) goto handle_error;
  407. fcon->headerbuf_used += res;
  408. if (fcon->headerbuf_used < 8) return; /* need more data */
  409. fcon->current_header.version = data[0];
  410. fcon->current_header.type = data[1];
  411. fcon->current_header.requestID = (data[2] << 8) | (data[3]);
  412. fcon->current_header.contentLength = (data[4] << 8) | (data[5]);
  413. fcon->current_header.paddingLength = data[6];
  414. fcon->content_remaining = fcon->current_header.contentLength;
  415. fcon->padding_remaining = fcon->current_header.paddingLength;
  416. fcon->first = TRUE;
  417. g_byte_array_set_size(fcon->buffer, 0);
  418. if (fcon->current_header.version != FCGI_VERSION_1) {
  419. fastcgi_connection_close(fcon);
  420. return;
  421. }
  422. }
  423. if (fcon->current_header.type != FCGI_BEGIN_REQUEST &&
  424. (0 != fcon->current_header.requestID) && fcon->current_header.requestID != fcon->requestID) {
  425. /* ignore packet data */
  426. if (0 != fcon->content_remaining + fcon->padding_remaining) {
  427. if (NULL == (buf = read_content(fcon))) goto handle_error;
  428. g_byte_array_free(buf, TRUE);
  429. }
  430. if (0 == fcon->content_remaining + fcon->padding_remaining) {
  431. fcon->headerbuf_used = 0;
  432. }
  433. continue;
  434. }
  435. if (fcon->first || fcon->content_remaining) {
  436. fcon->first = FALSE;
  437. switch (fcon->current_header.type) {
  438. case FCGI_BEGIN_REQUEST:
  439. if (8 != fcon->current_header.contentLength || 0 == fcon->current_header.requestID) goto error;
  440. if (!read_append_chunk(fcon, fcon->buffer)) goto handle_error;
  441. if (0 == fcon->content_remaining) {
  442. if (fcon->requestID) {
  443. stream_send_end_request(&fcon->write_queue, fcon->current_header.requestID, 0, FCGI_CANT_MPX_CONN);
  444. } else {
  445. unsigned char *data = (unsigned char*) fcon->buffer->data;
  446. fcon->requestID = fcon->current_header.requestID;
  447. fcon->role = (data[0] << 8) | (data[1]);
  448. fcon->flags = data[2];
  449. g_byte_array_set_size(fcon->parambuf, 0);
  450. }
  451. }
  452. break;
  453. case FCGI_ABORT_REQUEST:
  454. if (0 != fcon->current_header.contentLength || 0 == fcon->current_header.requestID) goto error;
  455. fcbs->cb_request_aborted(fcon);
  456. break;
  457. case FCGI_END_REQUEST:
  458. goto error; /* invalid type */
  459. case FCGI_PARAMS:
  460. if (0 == fcon->current_header.requestID) goto error;
  461. if (!read_append_chunk(fcon, fcon->parambuf)) goto handle_error;
  462. parse_params(fcbs, fcon);
  463. break;
  464. case FCGI_STDIN:
  465. if (0 == fcon->current_header.requestID) goto error;
  466. buf = NULL;
  467. if (0 != fcon->content_remaining &&
  468. NULL == (buf = read_content(fcon))) goto handle_error;
  469. if (fcbs->cb_received_stdin) {
  470. fcbs->cb_received_stdin(fcon, buf);
  471. } else {
  472. g_byte_array_free(buf, TRUE);
  473. }
  474. break;
  475. case FCGI_STDOUT:
  476. goto error; /* invalid type */
  477. case FCGI_STDERR:
  478. goto error; /* invalid type */
  479. case FCGI_DATA:
  480. if (0 == fcon->current_header.requestID) goto error;
  481. buf = NULL;
  482. if (0 != fcon->content_remaining &&
  483. NULL == (buf = read_content(fcon))) goto handle_error;
  484. if (fcbs->cb_received_data) {
  485. fcbs->cb_received_data(fcon, buf);
  486. } else {
  487. g_byte_array_free(buf, TRUE);
  488. }
  489. break;
  490. case FCGI_GET_VALUES:
  491. if (0 != fcon->current_header.requestID) goto error;
  492. if (!read_append_chunk(fcon, fcon->buffer)) goto handle_error;
  493. if (0 == fcon->content_remaining)
  494. parse_get_values(fcon);
  495. break;
  496. case FCGI_GET_VALUES_RESULT:
  497. goto error; /* invalid type */
  498. break;
  499. case FCGI_UNKNOWN_TYPE:
  500. /* we didn't send anything fancy, so this is not expected */
  501. goto error; /* invalid type */
  502. default:
  503. break;
  504. }
  505. }
  506. if (0 == fcon->content_remaining) {
  507. if (0 == fcon->padding_remaining) {
  508. fcon->headerbuf_used = 0;
  509. } else {
  510. if (NULL == (buf = read_chunk(fcon, fcon->padding_remaining))) goto handle_error;
  511. fcon->padding_remaining -= buf->len;
  512. if (0 == fcon->padding_remaining) {
  513. fcon->headerbuf_used = 0;
  514. }
  515. g_byte_array_free(buf, TRUE);
  516. }
  517. }
  518. }
  519. return;
  520. handle_error:
  521. switch (errno) {
  522. case EINTR:
  523. case EAGAIN:
  524. #if EWOULDBLOCK != EAGAIN
  525. case EWOULDBLOCK:
  526. #endif
  527. return; /* try again later */
  528. case ECONNRESET:
  529. break;
  530. default:
  531. ERROR("read from fd=%d failed, %s\n", fcon->fd, g_strerror(errno) );
  532. break;
  533. }
  534. error:
  535. if (0 != fcon->requestID)
  536. fcbs->cb_request_aborted(fcon);
  537. fastcgi_connection_close(fcon);
  538. }
  539. static void fastcgi_connection_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
  540. fastcgi_connection *fcon = (fastcgi_connection*) w->data;
  541. if (fcon->closing) {
  542. char buf[1024];
  543. ssize_t r;
  544. r = read(fcon->fd, buf, sizeof(buf));
  545. if (r > 0) return;
  546. if (-1 == r) switch (errno) {
  547. case EINTR:
  548. case EAGAIN:
  549. #if EWOULDBLOCK != EAGAIN
  550. case EWOULDBLOCK:
  551. #endif
  552. return; /* try again later */
  553. default:
  554. break;
  555. }
  556. ev_io_stop(loop, w);
  557. close(fcon->fd);
  558. fcon->fd = -1;
  559. ev_prepare_start(fcon->fsrv->loop, &fcon->fsrv->closing_watcher);
  560. return;
  561. }
  562. if (revents & EV_READ) {
  563. read_queue(fcon);
  564. }
  565. if (revents & EV_WRITE) {
  566. write_queue(fcon);
  567. }
  568. }
  569. static fastcgi_connection *fastcgi_connecion_create(fastcgi_server *fsrv, gint fd, guint id) {
  570. fastcgi_connection *fcon = g_slice_new0(fastcgi_connection);
  571. fcon->fsrv = fsrv;
  572. fcon->fcon_id = id;
  573. fcon->buffer = g_byte_array_sized_new(0);
  574. fcon->parambuf = g_byte_array_sized_new(0);
  575. fcon->environ = g_ptr_array_new();
  576. fcon->fd = fd;
  577. fd_init(fcon->fd);
  578. ev_io_init(&fcon->fd_watcher, fastcgi_connection_fd_cb, fcon->fd, EV_READ);
  579. fcon->fd_watcher.data = fcon;
  580. ev_io_start(fcon->fsrv->loop, &fcon->fd_watcher);
  581. return fcon;
  582. }
  583. static void fastcgi_connection_free(fastcgi_connection *fcon) {
  584. fcon->fsrv->callbacks->cb_reset_connection(fcon);
  585. fastcgi_queue_clear(&fcon->write_queue);
  586. fastcgi_connection_environ_clear(fcon);
  587. g_ptr_array_free(fcon->environ, TRUE);
  588. g_byte_array_free(fcon->buffer, TRUE);
  589. g_byte_array_free(fcon->parambuf, TRUE);
  590. g_slice_free(fastcgi_connection, fcon);
  591. }
  592. void fastcgi_connection_close(fastcgi_connection *fcon) {
  593. fcon->closing = TRUE;
  594. if (fcon->fd != -1) {
  595. shutdown(fcon->fd, SHUT_WR);
  596. }
  597. fastcgi_queue_clear(&fcon->write_queue);
  598. g_byte_array_set_size(fcon->buffer, 0);
  599. g_byte_array_set_size(fcon->parambuf, 0);
  600. fastcgi_connection_environ_clear(fcon);
  601. if (fcon->fd == -1) {
  602. ev_prepare_start(fcon->fsrv->loop, &fcon->fsrv->closing_watcher);
  603. }
  604. }
  605. static void fastcgi_server_fd_cb(struct ev_loop *loop, ev_io *w, int revents) {
  606. fastcgi_server *fsrv = (fastcgi_server*) w->data;
  607. fastcgi_connection *fcon;
  608. void (*cb_new_connection)(fastcgi_connection *fcon) = fsrv->callbacks->cb_new_connection;
  609. g_assert(revents & EV_READ);
  610. for (;;) {
  611. gint fd = accept(fsrv->fd, NULL, NULL);
  612. if (-1 == fd) {
  613. switch (errno) {
  614. case EAGAIN:
  615. #if EWOULDBLOCK != EAGAIN
  616. case EWOULDBLOCK:
  617. #endif
  618. case EINTR:
  619. /* we were stopped _before_ we had a connection */
  620. case ECONNABORTED: /* this is a FreeBSD thingy */
  621. /* we were stopped _after_ we had a connection */
  622. return;
  623. case EMFILE:
  624. fsrv->max_connections = fsrv->connections->len / 2;
  625. if (fsrv->max_connections < 1) fsrv->max_connections = 1;
  626. ERROR("dropped connection limit to %u as we got EMFILE\n", fsrv->max_connections);
  627. ev_io_rem_events(loop, w, EV_READ);
  628. return;
  629. default:
  630. ERROR("accept failed on fd=%d with error: %s\nshutting down\n", fsrv->fd, g_strerror(errno));
  631. fastcgi_server_stop(fsrv);
  632. return;
  633. }
  634. }
  635. fcon = fastcgi_connecion_create(fsrv, fd, fsrv->connections->len);
  636. g_ptr_array_add(fsrv->connections, fcon);
  637. if (cb_new_connection) {
  638. cb_new_connection(fcon);
  639. }
  640. if (fsrv->connections->len >= fsrv->max_connections) {
  641. ev_io_rem_events(loop, w, EV_READ);
  642. return;
  643. }
  644. if (fsrv->do_shutdown) return;
  645. }
  646. }
  647. static void fastcgi_cleanup_connections(fastcgi_server *fsrv) {
  648. guint i;
  649. gboolean closed_con;
  650. for (i = 0; i < fsrv->connections->len; ) {
  651. fastcgi_connection *fcon = g_ptr_array_index(fsrv->connections, i);
  652. if (fcon->closing && -1 == fcon->fd) {
  653. fastcgi_connection *t_fcon;
  654. guint l = fsrv->connections->len-1;
  655. t_fcon = g_ptr_array_index(fsrv->connections, i) = g_ptr_array_index(fsrv->connections, l);
  656. g_ptr_array_set_size(fsrv->connections, l);
  657. t_fcon->fcon_id = i;
  658. fastcgi_connection_free(fcon);
  659. closed_con = TRUE;
  660. } else {
  661. i++;
  662. }
  663. }
  664. if (closed_con && fsrv->connections->len < fsrv->max_connections) {
  665. ev_io_add_events(fsrv->loop, &fsrv->fd_watcher, EV_READ);
  666. }
  667. }
  668. static void fastcgi_closing_cb(struct ev_loop *loop, ev_prepare *w, int revents) {
  669. UNUSED(revents);
  670. ev_prepare_stop(loop, w);
  671. fastcgi_cleanup_connections((fastcgi_server*) w->data);
  672. }
  673. fastcgi_server *fastcgi_server_create(struct ev_loop *loop, gint socketfd, const fastcgi_callbacks *callbacks, guint max_connections) {
  674. fastcgi_server *fsrv = g_slice_new0(fastcgi_server);
  675. fsrv->callbacks = callbacks;
  676. fsrv->max_connections = max_connections;
  677. fsrv->connections = g_ptr_array_sized_new(fsrv->max_connections);
  678. fsrv->loop = loop;
  679. fsrv->fd = socketfd;
  680. fd_init(fsrv->fd);
  681. ev_io_init(&fsrv->fd_watcher, fastcgi_server_fd_cb, fsrv->fd, EV_READ);
  682. fsrv->fd_watcher.data = fsrv;
  683. ev_io_start(fsrv->loop, &fsrv->fd_watcher);
  684. ev_prepare_init(&fsrv->closing_watcher, fastcgi_closing_cb);
  685. fsrv->closing_watcher.data = fsrv;
  686. return fsrv;
  687. }
  688. void fastcgi_server_stop(fastcgi_server *fsrv) {
  689. if (fsrv->do_shutdown) return;
  690. fsrv->do_shutdown = TRUE;
  691. ev_io_stop(fsrv->loop, &fsrv->fd_watcher);
  692. close(fsrv->fd);
  693. fsrv->fd = -1;
  694. }
  695. void fastcgi_server_free(fastcgi_server *fsrv) {
  696. guint i;
  697. void (*cb_request_aborted)(fastcgi_connection *fcon) = fsrv->callbacks->cb_request_aborted;
  698. if (!fsrv->do_shutdown) fastcgi_server_stop(fsrv);
  699. ev_prepare_stop(fsrv->loop, &fsrv->closing_watcher);
  700. for (i = 0; i < fsrv->connections->len; i++) {
  701. fastcgi_connection *fcon = g_ptr_array_index(fsrv->connections, i);
  702. cb_request_aborted(fcon);
  703. fcon->closing = TRUE;
  704. }
  705. fastcgi_cleanup_connections(fsrv);
  706. g_ptr_array_free(fsrv->connections, TRUE);
  707. g_slice_free(fastcgi_server, fsrv);
  708. }
  709. void fastcgi_end_request(fastcgi_connection *fcon, gint32 appStatus, enum FCGI_ProtocolStatus status) {
  710. gboolean had_data = (fcon->write_queue.length > 0);
  711. if (0 == fcon->requestID) return;
  712. stream_send_end_request(&fcon->write_queue, fcon->requestID, appStatus, status);
  713. fcon->requestID = 0;
  714. fastcgi_connection_environ_clear(fcon);
  715. if (!had_data) write_queue(fcon);
  716. }
  717. void fastcgi_suspend_read(fastcgi_connection *fcon) {
  718. fcon->read_suspended = TRUE;
  719. ev_io_rem_events(fcon->fsrv->loop, &fcon->fd_watcher, EV_READ);
  720. }
  721. void fastcgi_resume_read(fastcgi_connection *fcon) {
  722. fcon->read_suspended = FALSE;
  723. ev_io_add_events(fcon->fsrv->loop, &fcon->fd_watcher, EV_READ);
  724. }
  725. void fastcgi_send_out(fastcgi_connection *fcon, GString *data) {
  726. gboolean had_data = (fcon->write_queue.length > 0);
  727. if (!data) {
  728. stream_send_fcgi_record(&fcon->write_queue, FCGI_STDOUT, fcon->requestID, 0);
  729. } else {
  730. stream_send_string(&fcon->write_queue, FCGI_STDOUT, fcon->requestID, data);
  731. }
  732. if (!had_data) write_queue(fcon);
  733. }
  734. void fastcgi_send_err(fastcgi_connection *fcon, GString *data) {
  735. gboolean had_data = (fcon->write_queue.length > 0);
  736. if (!data) {
  737. stream_send_fcgi_record(&fcon->write_queue, FCGI_STDERR, fcon->requestID, 0);
  738. } else {
  739. stream_send_string(&fcon->write_queue, FCGI_STDERR, fcon->requestID, data);
  740. }
  741. if (!had_data) write_queue(fcon);
  742. }
  743. void fastcgi_send_out_bytearray(fastcgi_connection *fcon, GByteArray *data) {
  744. gboolean had_data = (fcon->write_queue.length > 0);
  745. if (!data) {
  746. stream_send_fcgi_record(&fcon->write_queue, FCGI_STDOUT, fcon->requestID, 0);
  747. } else {
  748. stream_send_bytearray(&fcon->write_queue, FCGI_STDOUT, fcon->requestID, data);
  749. }
  750. if (!had_data) write_queue(fcon);
  751. }
  752. void fastcgi_send_err_bytearray(fastcgi_connection *fcon, GByteArray *data) {
  753. gboolean had_data = (fcon->write_queue.length > 0);
  754. if (!data) {
  755. stream_send_fcgi_record(&fcon->write_queue, FCGI_STDERR, fcon->requestID, 0);
  756. } else {
  757. stream_send_bytearray(&fcon->write_queue, FCGI_STDERR, fcon->requestID, data);
  758. }
  759. if (!had_data) write_queue(fcon);
  760. }
  761. void fastcgi_connection_environ_clear(fastcgi_connection *fcon) {
  762. guint i;
  763. for (i = 0; i < fcon->environ->len; i++) {
  764. gchar *s = (gchar*) g_ptr_array_index(fcon->environ, i);
  765. if (s) g_free(s);
  766. }
  767. g_ptr_array_set_size(fcon->environ, 0);
  768. }
  769. const gchar* fastcgi_connection_environ_lookup(fastcgi_connection *fcon, const gchar* key, gsize keylen) {
  770. guint i;
  771. for (i = 0; i < fcon->environ->len; i++) {
  772. gchar *s = (gchar*) g_ptr_array_index(fcon->environ, i);
  773. if (s && 0 == strncmp(s, key, keylen) && s[keylen] == '=') {
  774. return &s[keylen+1];
  775. }
  776. }
  777. return NULL;
  778. }