commit 3ff00eade6c3b17a852658c28502edbfc83ef25b from: Omar Polo date: Tue Aug 09 14:09:29 2022 UTC gotwebd: add a some buffering This adds some buffering to fcgi_gen_binary_response so that we don't end up sending too many (very) small fastcgi records. While here also make fcgi_send_response non-void and make its errors "sticky". ok tracey@ commit - 7ecc4542fefb0ad0b7babe055da2f9ac447a906b commit + 3ff00eade6c3b17a852658c28502edbfc83ef25b blob - f0de1b24e2bf33d38244b293dc7316561566af60 blob + f6cb81448f5778d7872b537fd6b90838285c99ee --- gotwebd/fcgi.c +++ gotwebd/fcgi.c @@ -40,7 +40,7 @@ size_t fcgi_parse_record(uint8_t *, size_t, struct re void fcgi_parse_begin_request(uint8_t *, uint16_t, struct request *, uint16_t); void fcgi_parse_params(uint8_t *, uint16_t, struct request *, uint16_t); -void fcgi_send_response(struct request *, int, const void *, size_t); +int fcgi_send_response(struct request *, int, const void *, size_t); void dump_fcgi_record_header(const char *, struct fcgi_record_header *); void dump_fcgi_begin_request_body(const char *, @@ -137,6 +137,12 @@ fcgi_parse_record(uint8_t *buf, size_t n, struct reque break; case FCGI_STDIN: case FCGI_ABORT_REQUEST: + if (c->sock->client_status != CLIENT_DISCONNECT && + c->outbuf_len != 0) { + fcgi_send_response(c, FCGI_STDOUT, c->outbuf, + c->outbuf_len); + } + fcgi_create_end_record(c); fcgi_cleanup_request(c); return 0; @@ -304,13 +310,39 @@ fcgi_timeout(int fd, short events, void *arg) int fcgi_gen_binary_response(struct request *c, const uint8_t *data, int len) { + int r; + if (c->sock->client_status == CLIENT_DISCONNECT) return -1; if (data == NULL || len == 0) return 0; - fcgi_send_response(c, FCGI_STDOUT, data, len); + /* + * special case: send big replies -like blobs- directly + * without copying. + */ + if (len > sizeof(c->outbuf)) { + if (c->outbuf_len > 0) { + fcgi_send_response(c, FCGI_STDOUT, + c->outbuf, c->outbuf_len); + c->outbuf_len = 0; + } + return fcgi_send_response(c, FCGI_STDOUT, data, len); + } + + if (len < sizeof(c->outbuf) - c->outbuf_len) { + memcpy(c->outbuf + c->outbuf_len, data, len); + c->outbuf_len += len; + return 0; + } + + r = fcgi_send_response(c, FCGI_STDOUT, c->outbuf, c->outbuf_len); + if (r == -1) + return -1; + + memcpy(c->outbuf, data, len); + c->outbuf_len = len; return 0; } @@ -322,7 +354,7 @@ fcgi_gen_response(struct request *c, const char *data) return fcgi_gen_binary_response(c, data, strlen(data)); } -static void +static int send_response(struct request *c, int type, const uint8_t *data, size_t len) { @@ -382,7 +414,7 @@ send_response(struct request *c, int type, const uint8 } log_warn("%s: write failure", __func__); c->sock->client_status = CLIENT_DISCONNECT; - break; + return -1; } if (nw != tot) @@ -400,25 +432,29 @@ send_response(struct request *c, int type, const uint8 iov[i].iov_len = 0; } } + + return 0; } -void +int fcgi_send_response(struct request *c, int type, const void *data, size_t len) { + if (c->sock->client_status == CLIENT_DISCONNECT) + return -1; + while (len > FCGI_CONTENT_SIZE) { - send_response(c, type, data, len); - if (c->sock->client_status == CLIENT_DISCONNECT) - return; + if (send_response(c, type, data, len) == -1) + return -1; data += FCGI_CONTENT_SIZE; len -= FCGI_CONTENT_SIZE; } if (len == 0) - return; + return 0; - send_response(c, type, data, len); + return send_response(c, type, data, len); } void blob - aafdb73fcd040caf5d1182eb5bd173b3e7bd6a95 blob + b58b1e7be0421dac9ff6c9717bacb59208ad1bbb --- gotwebd/gotwebd.h +++ gotwebd/gotwebd.h @@ -39,6 +39,7 @@ #define GOTWEBD_USER "www" +#define GOTWEBD_CACHESIZE 1024 #define GOTWEBD_MAXCLIENTS 1024 #define GOTWEBD_MAXTEXT 511 #define GOTWEBD_MAXNAME 64 @@ -212,6 +213,9 @@ struct request { uint8_t buf[FCGI_RECORD_SIZE]; size_t buf_pos; size_t buf_len; + + uint8_t outbuf[GOTWEBD_CACHESIZE]; + size_t outbuf_len; char querystring[MAX_QUERYSTRING]; char http_host[GOTWEBD_MAXTEXT];