commit 0f7fdd21050e3795db896b99e542523c84e075d7 from: Omar Polo date: Sat Jul 01 18:37:59 2023 UTC parse (and log) the header from fastcgi commit - a6f2cfe7927f8385938f220016280629d3e8a6d9 commit + 0f7fdd21050e3795db896b99e542523c84e075d7 blob - 9452e306aa4eb3545ae87c9a4dd30836e029723a blob + 7a141a58fe7808af08033bb33aa9643e5e19b143 --- fcgi.c +++ fcgi.c @@ -17,6 +17,7 @@ #include "gmid.h" #include +#include #include #include @@ -209,6 +210,65 @@ static inline int reclen(struct fcgi_header *h) { return h->content_len0 + (h->content_len1 << 8); +} + +static void +fcgi_handle_stdout(struct client *c, struct evbuffer *src, size_t len) +{ + struct bufferevent *bev = c->cgibev; + char *t; + size_t l; + int code; + + if (c->code == 0) { + l = len; + if (l > sizeof(c->sbuf) - c->soff) + l = sizeof(c->sbuf) - c->soff; + + memcpy(&c->sbuf[c->soff], EVBUFFER_DATA(src), l); + c->soff += l; + evbuffer_drain(src, l); + len -= l; + + if ((t = memmem(c->sbuf, c->soff, "\r\n", 2)) == NULL) { + if (c->soff == sizeof(c->sbuf)) { + log_warnx("FastCGI application is trying to" + " send a header that's too long."); + fcgi_error(bev, EVBUFFER_ERROR, c); + } + + /* wait a bit */ + return; + } + *t = '\0'; + t += 2; /* skip CRLF */ + + if (!isdigit((unsigned char)c->sbuf[0]) || + !isdigit((unsigned char)c->sbuf[1]) || + c->sbuf[2] != ' ') { + fcgi_error(bev, EVBUFFER_ERROR, c); + return; + } + + code = (c->sbuf[0] - '0') * 10 + (c->sbuf[1] - '0'); + if (code < 10 || code >= 70) { + log_warnx("FastCGI application is trying to send an" + " invalid reply code: %d", code); + fcgi_error(bev, EVBUFFER_ERROR, c); + return; + } + + start_reply(c, code, c->sbuf + 3); + if (c->code < 20 || c->code > 29) { + fcgi_error(bev, EVBUFFER_EOF, c); + return; + } + + bufferevent_write(c->bev, t, &c->sbuf[c->soff] - t); + } + + bufferevent_write(c->bev, EVBUFFER_DATA(src), len); + evbuffer_drain(src, len); } void @@ -259,8 +319,7 @@ fcgi_read(struct bufferevent *bev, void *d) break; case FCGI_STDOUT: - bufferevent_write(c->bev, EVBUFFER_DATA(src), len); - evbuffer_drain(src, len); + fcgi_handle_stdout(c, src, len); break; default: @@ -290,14 +349,25 @@ fcgi_error(struct bufferevent *bev, short err, void *d { struct client *c = d; - if (!(err & (EVBUFFER_ERROR|EVBUFFER_EOF))) - log_warn("unknown event error (%x)", err); + /* + * If we're here it means that some kind of non-recoverable + * error happened. + */ - c->type = REQUEST_DONE; - if (c->code != 0) - client_close(c); - else + bufferevent_free(bev); + c->cgibev = NULL; + + close(c->pfd); + c->pfd = -1; + + /* EOF and no header */ + if (c->code == 0) { start_reply(c, CGI_ERROR, "CGI error"); + return; + } + + c->type = REQUEST_DONE; + client_write(c->bev, c); } void blob - 885a7a7d669e99bb45a7818e2104d0e7beaff221 blob + 770deeae94340a541a8e2827b2574e8d371488e2 --- gmid.h +++ gmid.h @@ -306,7 +306,7 @@ struct client { /* big enough to store STATUS + SPACE + META + CRLF */ char sbuf[1029]; - ssize_t len, off; + size_t soff; struct sockaddr_storage raddr; socklen_t raddrlen;