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.

895 lines
26 KiB

12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
12 years ago
  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. }