commit - 6f4eae69642d0a78da926cf32b3639e883f5fe09
commit + 37f7dbf5f09ff1eb1e37d380b32533e876325ef2
blob - 58a88e7f43f9c77ff11bef8420d7ec926c4ffb56
blob + 2446e2dde7afc86c2e450ef5c9845b2bd569261f
--- gotwebd/fcgi.c
+++ gotwebd/fcgi.c
#include <errno.h>
#include <event.h>
#include <imsg.h>
+#include <signal.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include "log.h"
#include "tmpl.h"
-size_t fcgi_parse_record(uint8_t *, size_t, struct request *);
-void fcgi_parse_begin_request(uint8_t *, uint16_t, struct request *,
+static void fcgi_sighdlr(int, short, void *);
+static void fcgi_shutdown(void);
+static void fcgi_launch(struct gotwebd *);
+
+void fcgi_parse_record(struct gotwebd_fcgi_record *);
+int fcgi_parse_begin_request(uint8_t *, uint16_t, struct request *,
uint16_t);
-void fcgi_parse_params(uint8_t *, uint16_t, struct request *, uint16_t);
+int fcgi_parse_params(uint8_t *, uint16_t, struct gotwebd_fcgi_params *);
int fcgi_send_response(struct request *, int, const void *, size_t);
void dump_fcgi_request_body(const char *, struct fcgi_record_header *);
void dump_fcgi_end_request_body(const char *,
struct fcgi_end_request_body *);
-extern int cgi_inflight;
extern struct requestlist requests;
-void
-fcgi_request(int fd, short events, void *arg)
+static void
+fcgi_shutdown(void)
{
- struct request *c = arg;
- ssize_t n;
- size_t parsed = 0;
-
- n = read(fd, c->buf + c->buf_pos + c->buf_len,
- FCGI_RECORD_SIZE - c->buf_pos - c->buf_len);
-
- switch (n) {
- case -1:
- switch (errno) {
- case EINTR:
- case EAGAIN:
- event_add(&c->ev, NULL);
- return;
- default:
- goto fail;
- }
- break;
- case 0:
- if (c->client_status == CLIENT_CONNECT) {
- log_warnx("client %u closed connection too early",
- c->request_id);
- goto fail;
- }
- return;
- default:
- break;
+ imsgbuf_clear(&gotwebd_env->iev_parent->ibuf);
+ free(gotwebd_env->iev_parent);
+ if (gotwebd_env->iev_server) {
+ imsgbuf_clear(&gotwebd_env->iev_server->ibuf);
+ free(gotwebd_env->iev_server);
}
- c->buf_len += n;
+ free(gotwebd_env);
- /*
- * Parse the records as they are received. Per the FastCGI
- * specification, the server need only receive the FastCGI
- * parameter records in full; it is free to begin execution
- * at that point, which is what happens here.
- */
- do {
- parsed = fcgi_parse_record(c->buf + c->buf_pos, c->buf_len, c);
-
- /*
- * When we start to actually process the entry, we
- * send the request to the gotweb process, so we're
- * done.
- */
- if (c->client_status == CLIENT_REQUEST) {
- fcgi_cleanup_request(c);
- return;
- }
-
- if (parsed != 0) {
- c->buf_pos += parsed;
- c->buf_len -= parsed;
- }
-
- /* drop the parsed record */
- if (parsed != 0 && c->buf_len > 0) {
- memmove(c->buf, c->buf + c->buf_pos, c->buf_len);
- c->buf_pos = 0;
- }
- } while (parsed > 0 && c->buf_len > 0);
-
- event_add(&c->ev, NULL);
- return;
-fail:
- fcgi_cleanup_request(c);
+ exit(0);
}
-size_t
-fcgi_parse_record(uint8_t *buf, size_t n, struct request *c)
+static void
+fcgi_sighdlr(int sig, short event, void *arg)
{
- struct fcgi_record_header *h;
-
- if (n < sizeof(struct fcgi_record_header))
- return 0;
-
- h = (struct fcgi_record_header*) buf;
-
- dump_fcgi_record_header("", h);
-
- if (n < sizeof(struct fcgi_record_header) + ntohs(h->content_len)
- + h->padding_len)
- return 0;
-
- dump_fcgi_request_body("", h);
-
- if (h->version != 1)
- log_warn("wrong version");
-
- switch (h->type) {
- case FCGI_BEGIN_REQUEST:
- fcgi_parse_begin_request(buf +
- sizeof(struct fcgi_record_header),
- ntohs(h->content_len), c, ntohs(h->id));
+ switch (sig) {
+ case SIGHUP:
+ log_info("%s: ignoring SIGHUP", __func__);
break;
- case FCGI_PARAMS:
- fcgi_parse_params(buf + sizeof(struct fcgi_record_header),
- ntohs(h->content_len), c, ntohs(h->id));
+ case SIGPIPE:
+ log_info("%s: ignoring SIGPIPE", __func__);
break;
- case FCGI_STDIN:
- return 0;
- case FCGI_ABORT_REQUEST:
- fcgi_create_end_record(c);
- fcgi_cleanup_request(c);
- return 0;
+ case SIGUSR1:
+ log_info("%s: ignoring SIGUSR1", __func__);
+ break;
+ case SIGCHLD:
+ break;
+ case SIGINT:
+ case SIGTERM:
+ fcgi_shutdown();
+ break;
default:
- log_warn("unimplemented type %d", h->type);
+ log_warn("unexpected signal %d", sig);
break;
}
-
- return (sizeof(struct fcgi_record_header) + ntohs(h->content_len)
- + h->padding_len);
}
-void
-fcgi_parse_begin_request(uint8_t *buf, uint16_t n,
- struct request *c, uint16_t id)
+static void
+send_parsed_params(struct gotwebd_fcgi_params *params)
{
- /* XXX -- FCGI_CANT_MPX_CONN */
- if (c->request_started) {
- log_warn("unexpected FCGI_BEGIN_REQUEST, ignoring");
- return;
- }
+ struct gotwebd *env = gotwebd_env;
- if (n != sizeof(struct fcgi_begin_request_body)) {
- log_warn("wrong size %d != %lu", n,
- sizeof(struct fcgi_begin_request_body));
- return;
- }
-
- c->request_started = 1;
- c->id = id;
+ if (imsg_compose_event(env->iev_server, GOTWEBD_IMSG_FCGI_PARAMS,
+ GOTWEBD_PROC_SERVER, -1, -1, params, sizeof(*params)) == -1)
+ log_warn("imsg_compose_event");
}
static void
-process_request(struct request *c)
+abort_request(uint32_t request_id)
{
struct gotwebd *env = gotwebd_env;
- struct imsgev *iev_gotweb;
- int ret, i;
- struct request ic;
- memcpy(&ic, c, sizeof(ic));
-
- /* Don't leak pointers from our address space to another process. */
- ic.sock = NULL;
- ic.srv = NULL;
- ic.t = NULL;
- ic.tp = NULL;
- ic.buf = NULL;
- ic.outbuf = NULL;
-
- /* Other process will use its own set of temp files. */
- for (i = 0; i < nitems(c->priv_fd); i++)
- ic.priv_fd[i] = -1;
- ic.fd = -1;
-
- /* Round-robin requests across gotweb processes. */
- iev_gotweb = &env->iev_gotweb[env->gotweb_cur];
- env->gotweb_cur = (env->gotweb_cur + 1) % env->prefork;
-
- ret = imsg_compose_event(iev_gotweb, GOTWEBD_IMSG_REQ_PROCESS,
- GOTWEBD_PROC_SERVER, -1, c->fd, &ic, sizeof(ic));
- if (ret == -1) {
+ if (imsg_compose_event(env->iev_server, GOTWEBD_IMSG_REQ_ABORT,
+ GOTWEBD_PROC_SERVER, -1, -1, &request_id, sizeof(request_id)) == -1)
log_warn("imsg_compose_event");
- return;
- }
- c->fd = -1;
-
- c->client_status = CLIENT_REQUEST;
}
void
-fcgi_parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
+fcgi_parse_record(struct gotwebd_fcgi_record *rec)
{
- uint32_t name_len, val_len;
- uint8_t *val;
+ struct fcgi_record_header *h;
+ uint8_t *record_body;
+ struct gotwebd_fcgi_params params = { 0 };
- if (!c->request_started) {
- log_warn("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring");
+ if (rec->record_len < sizeof(struct fcgi_record_header) ||
+ rec->record_len > sizeof(rec->record)) {
+ log_warnx("invalid fcgi record size");
+ abort_request(rec->request_id);
return;
}
- if (c->id != id) {
- log_warn("unexpected id, ignoring");
+ h = (struct fcgi_record_header *)&rec->record[0];
+
+ dump_fcgi_record_header("", h);
+
+ if (rec->record_len != sizeof(*h) + ntohs(h->content_len) +
+ h->padding_len) {
+ abort_request(rec->request_id);
return;
}
- if (n == 0) {
- process_request(c);
+ dump_fcgi_request_body("", h);
+
+ if (h->version != 1) {
+ log_warn("wrong fcgi header version: %u", h->version);
+ abort_request(rec->request_id);
return;
}
+ record_body = &rec->record[sizeof(*h)];
+ switch (h->type) {
+ case FCGI_PARAMS:
+ if (fcgi_parse_params(record_body,
+ ntohs(h->content_len), ¶ms) == -1) {
+ abort_request(rec->request_id);
+ break;
+ }
+ params.request_id = rec->request_id;
+ send_parsed_params(¶ms);
+ break;
+ default:
+ log_warn("unexpected fcgi type %d", h->type);
+ abort_request(rec->request_id);
+ break;
+ }
+}
+
+int
+fcgi_parse_params(uint8_t *buf, uint16_t n, struct gotwebd_fcgi_params *params)
+{
+ uint32_t name_len, val_len;
+ uint8_t *val;
+
+ if (n == 0)
+ return 0;
+
while (n > 0) {
if (buf[0] >> 7 == 0) {
name_len = buf[0];
n -= 4;
buf += 4;
} else
- return;
+ return -1;
}
if (n == 0)
- return;
+ return -1;
if (buf[0] >> 7 == 0) {
val_len = buf[0];
n -= 4;
buf += 4;
} else
- return;
+ return -1;
}
if (n < name_len + val_len)
- return;
+ return -1;
val = buf + name_len;
if (val_len < MAX_QUERYSTRING &&
name_len == 12 &&
strncmp(buf, "QUERY_STRING", 12) == 0) {
- memcpy(c->querystring, val, val_len);
- c->querystring[val_len] = '\0';
+ /* TODO: parse querystring here */
+ memcpy(params->querystring, val, val_len);
+ params->querystring[val_len] = '\0';
}
if (val_len < MAX_DOCUMENT_URI &&
name_len == 12 &&
strncmp(buf, "DOCUMENT_URI", 12) == 0) {
- memcpy(c->document_uri, val, val_len);
- c->document_uri[val_len] = '\0';
+ memcpy(params->document_uri, val, val_len);
+ params->document_uri[val_len] = '\0';
}
if (val_len < MAX_SERVER_NAME &&
name_len == 11 &&
strncmp(buf, "SERVER_NAME", 11) == 0) {
- memcpy(c->server_name, val, val_len);
- c->server_name[val_len] = '\0';
+ memcpy(params->server_name, val, val_len);
+ params->server_name[val_len] = '\0';
}
if (name_len == 5 &&
strncmp(buf, "HTTPS", 5) == 0)
- c->https = 1;
+ params->https = 1;
buf += name_len + val_len;
n -= name_len - val_len;
}
-}
-void
-fcgi_timeout(int fd, short events, void *arg)
-{
- struct request *c = arg;
- log_warnx("request %u has timed out", c->request_id);
- fcgi_cleanup_request((struct request*) arg);
+ return 0;
}
static int
void
fcgi_cleanup_request(struct request *c)
{
- cgi_inflight--;
-
if (evtimer_initialized(&c->tmo))
evtimer_del(&c->tmo);
if (event_initialized(&c->ev))
{
log_debug("%sappStatus: %d", p, ntohl(b->app_status));
log_debug("%sprotocolStatus: %d", p, b->protocol_status);
+}
+
+static void
+fcgi_launch(struct gotwebd *env)
+{
+ if (env->iev_server == NULL)
+ fatalx("server process not connected");
+#ifndef PROFILE
+ if (pledge("stdio", NULL) == -1)
+ fatal("pledge");
+#endif
+ event_add(&env->iev_server->ev, NULL);
+}
+
+static struct gotwebd_fcgi_record *
+recv_record(struct imsg *imsg)
+{
+ struct gotwebd_fcgi_record *record;
+
+ record = calloc(1, sizeof(*record));
+ if (record == NULL) {
+ log_warn("calloc");
+ return NULL;
+ }
+
+ if (imsg_get_data(imsg, record, sizeof(*record)) == -1) {
+ log_warn("imsg_get_data");
+ free(record);
+ return NULL;
+ }
+
+ return record;
+}
+
+static void
+fcgi_dispatch_server(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_FCGI_PARSE_PARAMS: {
+ struct gotwebd_fcgi_record *rec;
+
+ rec = recv_record(&imsg);
+ if (rec) {
+ fcgi_parse_record(rec);
+ free(rec);
+ }
+ break;
+ }
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+static void
+recv_server_pipe(struct gotwebd *env, struct imsg *imsg)
+{
+ struct imsgev *iev;
+ int fd;
+
+ if (env->iev_server != NULL) {
+ log_warn("server pipe already received");
+ return;
+ }
+
+ fd = imsg_get_fd(imsg);
+ if (fd == -1)
+ fatalx("invalid server pipe fd");
+
+ iev = calloc(1, sizeof(*iev));
+ if (iev == NULL)
+ fatal("calloc");
+
+ if (imsgbuf_init(&iev->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+ imsgbuf_allow_fdpass(&iev->ibuf);
+ imsgbuf_set_maxsize(&iev->ibuf, sizeof(struct gotwebd_fcgi_record));
+
+ iev->handler = fcgi_dispatch_server;
+ iev->data = iev;
+ event_set(&iev->ev, fd, EV_READ, fcgi_dispatch_server, iev);
+ imsg_event_add(iev);
+
+ env->iev_server = iev;
}
+
+static void
+fcgi_dispatch_main(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct gotwebd *env = gotwebd_env;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_CFG_DONE:
+ config_getcfg(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CTL_PIPE:
+ recv_server_pipe(env, &imsg);
+ break;
+ case GOTWEBD_IMSG_CTL_START:
+ fcgi_launch(env);
+ break;
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+void
+gotwebd_fcgi(struct gotwebd *env, int fd)
+{
+ struct event sighup, sigint, sigusr1, sigchld, sigterm;
+ struct event_base *evb;
+
+ evb = event_init();
+
+ if ((env->iev_parent = malloc(sizeof(*env->iev_parent))) == NULL)
+ fatal("malloc");
+ if (imsgbuf_init(&env->iev_parent->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+ imsgbuf_allow_fdpass(&env->iev_parent->ibuf);
+ env->iev_parent->handler = fcgi_dispatch_main;
+ env->iev_parent->data = env->iev_parent;
+ event_set(&env->iev_parent->ev, fd, EV_READ, fcgi_dispatch_main,
+ env->iev_parent);
+ event_add(&env->iev_parent->ev, NULL);
+
+ signal(SIGPIPE, SIG_IGN);
+
+ signal_set(&sighup, SIGHUP, fcgi_sighdlr, env);
+ signal_add(&sighup, NULL);
+ signal_set(&sigint, SIGINT, fcgi_sighdlr, env);
+ signal_add(&sigint, NULL);
+ signal_set(&sigusr1, SIGUSR1, fcgi_sighdlr, env);
+ signal_add(&sigusr1, NULL);
+ signal_set(&sigchld, SIGCHLD, fcgi_sighdlr, env);
+ signal_add(&sigchld, NULL);
+ signal_set(&sigterm, SIGTERM, fcgi_sighdlr, env);
+ signal_add(&sigterm, NULL);
+
+#ifndef PROFILE
+ if (pledge("stdio recvfd", NULL) == -1)
+ fatal("pledge");
+#endif
+ event_dispatch();
+ event_base_free(evb);
+ fcgi_shutdown();
+}
blob - cc891f8eb78a1444fed0684e79e52a496a2008c7
blob + 5f2b1c6836e35e7f9ed602b0e1425472f331e026
--- gotwebd/gotweb.c
+++ gotwebd/gotweb.c
return NULL;
}
+static void
+cleanup_request(struct request *c)
+{
+ uint32_t request_id = c->request_id;
+
+ fcgi_cleanup_request(c);
+
+ if (imsg_compose_event(gotwebd_env->iev_server, GOTWEBD_IMSG_REQ_ABORT,
+ GOTWEBD_PROC_GOTWEB, -1, -1, &request_id, sizeof(request_id)) == -1)
+ log_warn("imsg_compose_event");
+}
+
static struct request *
recv_request(struct imsg *imsg)
{
c->tp = template(c, fcgi_write, c->outbuf, GOTWEBD_CACHESIZE);
if (c->tp == NULL) {
log_warn("gotweb init template");
- fcgi_cleanup_request(c);
+ cleanup_request(c);
return NULL;
}
c->sock = gotweb_get_socket(c->sock_id);
if (c->sock == NULL) {
log_warn("socket id '%d' not found", c->sock_id);
- fcgi_cleanup_request(c);
+ cleanup_request(c);
return NULL;
}
error = gotweb_init_transport(&c->t);
if (error) {
log_warnx("gotweb init transport: %s", error->msg);
- fcgi_cleanup_request(c);
+ cleanup_request(c);
return NULL;
}
/* get the gotwebd server */
- srv = gotweb_get_server(c->server_name);
+ srv = gotweb_get_server(c->fcgi_params.server_name);
if (srv == NULL) {
- log_warnx("server '%s' not found", c->server_name);
- fcgi_cleanup_request(c);
+ log_warnx("server '%s' not found", c->fcgi_params.server_name);
+ cleanup_request(c);
return NULL;
}
c->srv = srv;
goto err;
}
c->t->qs = qs;
- error = gotweb_parse_querystring(qs, c->querystring);
+ error = gotweb_parse_querystring(qs, c->fcgi_params.querystring);
if (error) {
log_warnx("%s: %s", __func__, error->msg);
goto err;
/* Log the request. */
if (gotwebd_env->gotwebd_verbose > 0) {
+ struct gotwebd_fcgi_params *p = &c->fcgi_params;
char *server_name = NULL;
char *querystring = NULL;
char *document_uri = NULL;
- if (c->server_name[0] &&
- stravis(&server_name, c->server_name, VIS_SAFE) == -1) {
+ if (p->server_name[0] &&
+ stravis(&server_name, p->server_name, VIS_SAFE) == -1) {
log_warn("stravis");
server_name = NULL;
}
- if (c->querystring[0] &&
- stravis(&querystring, c->querystring, VIS_SAFE) == -1) {
+ if (p->querystring[0] &&
+ stravis(&querystring, p->querystring, VIS_SAFE) == -1) {
log_warn("stravis");
querystring = NULL;
}
- if (c->document_uri[0] &&
- stravis(&document_uri, c->document_uri, VIS_SAFE) == -1) {
+ if (p->document_uri[0] &&
+ stravis(&document_uri, p->document_uri, VIS_SAFE) == -1) {
log_warn("stravis");
document_uri = NULL;
}
gotweb_render_absolute_url(struct request *c, struct gotweb_url *url)
{
struct template *tp = c->tp;
- const char *proto = c->https ? "https" : "http";
+ struct gotwebd_fcgi_params *p = &c->fcgi_params;
+ const char *proto = p->https ? "https" : "http";
if (tp_writes(tp, proto) == -1 ||
tp_writes(tp, "://") == -1 ||
- tp_htmlescape(tp, c->server_name) == -1 ||
- tp_htmlescape(tp, c->document_uri) == -1)
+ tp_htmlescape(tp, p->server_name) == -1 ||
+ tp_htmlescape(tp, p->document_uri) == -1)
return -1;
return gotweb_render_url(c, url);
c = recv_request(&imsg);
if (c) {
int request_id = c->request_id;
+ log_info("%u: %s: request %u", getpid(), __func__, c->request_id);
if (gotweb_process_request(c) == -1) {
log_warnx("request %u failed",
request_id);
}
fcgi_create_end_record(c);
- fcgi_cleanup_request(c);
+ cleanup_request(c);
}
break;
default:
blob - 68ffcc1638c3db490e1b14e4ab1194f8dc7776db
blob + 361e94d9fc08626854f1c0e4d31af3be36bec935
--- gotwebd/gotwebd.c
+++ gotwebd/gotwebd.c
void gotwebd_sighdlr(int sig, short event, void *arg);
void gotwebd_shutdown(void);
void gotwebd_dispatch_server(int, short, void *);
+void gotwebd_dispatch_fcgi(int, short, void *);
void gotwebd_dispatch_gotweb(int, short, void *);
struct gotwebd *gotwebd_env;
void
gotwebd_dispatch_server(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ struct gotwebd *env = gotwebd_env;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_CFG_DONE:
+ gotwebd_configure_done(env);
+ break;
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
+}
+
+void
+gotwebd_dispatch_fcgi(int fd, short event, void *arg)
{
struct imsgev *iev = arg;
struct imsgbuf *ibuf;
if (asprintf(&s, "-S%d", env->prefork) == -1)
fatal("asprintf");
argv[argc++] = s;
+ } else if (proc_type == GOTWEBD_PROC_FCGI) {
+ argv[argc++] = "-F";
+ argv[argc++] = username;
} else if (proc_type == GOTWEBD_PROC_GOTWEB) {
char *s;
fatal("%s: calloc", __func__);
config_init(env);
- while ((ch = getopt(argc, argv, "D:dG:f:nS:vW:")) != -1) {
+ while ((ch = getopt(argc, argv, "D:dG:f:F:nS:vW:")) != -1) {
switch (ch) {
case 'D':
if (cmdline_symset(optarg) < 0)
case 'f':
conffile = optarg;
break;
+ case 'F':
+ proc_type = GOTWEBD_PROC_FCGI;
+ gotwebd_username = optarg;
+ break;
case 'n':
no_action = 1;
break;
sockets(env, GOTWEBD_SOCK_FILENO);
return 1;
+ case GOTWEBD_PROC_FCGI:
+ setproctitle("fcgi");
+ log_procinit("fcgi");
+
+ if (chroot(env->httpd_chroot) == -1)
+ fatal("chroot %s", env->httpd_chroot);
+ if (chdir("/") == -1)
+ fatal("chdir /");
+
+ if (setgroups(gotwebd_ngroups, gotwebd_groups) == -1 ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
+ fatal("failed to drop privileges");
+
+ gotwebd_fcgi(env, GOTWEBD_SOCK_FILENO);
+ return 1;
case GOTWEBD_PROC_GOTWEB:
setproctitle("gotweb");
log_procinit("gotweb");
env->iev_server = calloc(env->server_cnt, sizeof(*env->iev_server));
if (env->iev_server == NULL)
fatal("calloc");
+
+ env->iev_fcgi = calloc(env->server_cnt, sizeof(*env->iev_fcgi));
+ if (env->iev_fcgi == NULL)
+ fatal("calloc");
+
env->iev_gotweb = calloc(env->prefork, sizeof(*env->iev_gotweb));
if (env->iev_gotweb == NULL)
fatal("calloc");
spawn_process(env, argv0, &env->iev_server[i],
GOTWEBD_PROC_SERVER, gotwebd_username,
gotwebd_dispatch_server);
+
+ spawn_process(env, argv0, &env->iev_fcgi[i],
+ GOTWEBD_PROC_FCGI, gotwebd_username,
+ gotwebd_dispatch_fcgi);
}
+
for (i = 0; i < env->prefork; ++i) {
spawn_process(env, argv0, &env->iev_gotweb[i],
GOTWEBD_PROC_GOTWEB, gotwebd_username,
gotwebd_dispatch_gotweb);
}
+
if (chdir("/") == -1)
fatal("chdir /");
static void
connect_children(struct gotwebd *env)
{
- struct imsgev *iev1, *iev2;
+ struct imsgev *iev_server, *iev_fcgi, *iev_gotweb;
int pipe[2];
int i, j;
for (i = 0; i < env->server_cnt; i++) {
- iev1 = &env->iev_server[i];
+ iev_server = &env->iev_server[i];
+ iev_fcgi = &env->iev_fcgi[i];
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe) == -1)
+ fatal("socketpair");
+
+ if (send_imsg(iev_server, GOTWEBD_IMSG_CTL_PIPE, pipe[0],
+ NULL, 0))
+ fatal("send_imsg");
+
+ if (send_imsg(iev_fcgi, GOTWEBD_IMSG_CTL_PIPE, pipe[1],
+ NULL, 0))
+ fatal("send_imsg");
+
for (j = 0; j < env->prefork; j++) {
- iev2 = &env->iev_gotweb[j];
+ iev_gotweb = &env->iev_gotweb[j];
if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC,
pipe) == -1)
fatal("socketpair");
- if (send_imsg(iev1, GOTWEBD_IMSG_CTL_PIPE, pipe[0],
- NULL, 0))
+ if (send_imsg(iev_server, GOTWEBD_IMSG_CTL_PIPE,
+ pipe[0], NULL, 0))
fatal("send_imsg");
- if (send_imsg(iev2, GOTWEBD_IMSG_CTL_PIPE, pipe[1],
- NULL, 0))
+ if (send_imsg(iev_gotweb, GOTWEBD_IMSG_CTL_PIPE,
+ pipe[1], NULL, 0))
fatal("send_imsg");
}
}
blob - b6e69183db3f973c8495e874e281a672de6f3f4c
blob + 18fe22bae49e8cf885500524c79e5780dd102d28
--- gotwebd/gotwebd.h
+++ gotwebd/gotwebd.h
enum gotwebd_proc_type {
GOTWEBD_PROC_PARENT,
GOTWEBD_PROC_SERVER,
+ GOTWEBD_PROC_FCGI,
GOTWEBD_PROC_GOTWEB,
};
GOTWEBD_IMSG_CFG_DONE,
GOTWEBD_IMSG_CTL_PIPE,
GOTWEBD_IMSG_CTL_START,
+ GOTWEBD_IMSG_FCGI_PARSE_PARAMS,
+ GOTWEBD_IMSG_FCGI_PARAMS,
+ GOTWEBD_IMSG_REQ_ABORT,
GOTWEBD_IMSG_REQ_PROCESS,
};
BLOB_FD_1,
BLOB_FD_2,
PRIV_FDS__MAX,
+};
+
+struct gotwebd_fcgi_record {
+ uint32_t request_id;
+ uint8_t record[FCGI_RECORD_SIZE];
+ size_t record_len;
+};
+
+struct gotwebd_fcgi_params {
+ uint32_t request_id;
+ char querystring[MAX_QUERYSTRING];
+ char document_uri[MAX_DOCUMENT_URI];
+ char server_name[MAX_SERVER_NAME];
+ int https;
};
struct template;
uint32_t request_id;
uint8_t *buf;
- size_t buf_pos;
size_t buf_len;
uint8_t *outbuf;
- char querystring[MAX_QUERYSTRING];
- char document_uri[MAX_DOCUMENT_URI];
- char server_name[MAX_SERVER_NAME];
- int https;
+ struct gotwebd_fcgi_params fcgi_params;
+ int nparams;
+ int nparams_parsed;
- uint8_t request_started;
int client_status;
};
TAILQ_HEAD(requestlist, request);
enum client_action {
CLIENT_CONNECT,
+ CLIENT_FCGI_BEGIN,
+ CLIENT_FCGI_PARAMS,
+ CLIENT_FCGI_STDIN,
CLIENT_REQUEST,
CLIENT_DISCONNECT,
};
struct imsgev *iev_parent;
struct imsgev *iev_server;
+ struct imsgev *iev_fcgi;
struct imsgev *iev_gotweb;
uint16_t prefork;
int cmdline_symset(char *);
/* fcgi.c */
-void fcgi_request(int, short, void *);
-void fcgi_timeout(int, short, void *);
void fcgi_cleanup_request(struct request *);
void fcgi_create_end_record(struct request *);
int fcgi_write(void *, const void *, size_t);
+void gotwebd_fcgi(struct gotwebd *, int);
/* got_operations.c */
const struct got_error *got_gotweb_closefile(FILE *);
blob - d5af2ffcb28eb41174cdfe8a016103fbb42d50da
blob + c7e1ac5b684f3f72cb60e8a5260089c8262b08a9
--- gotwebd/pages.tmpl
+++ gotwebd/pages.tmpl
struct server *srv = c->srv;
struct querystring *qs = c->t->qs;
struct gotweb_url u_path;
- const char *prfx = c->document_uri;
+ const char *prfx = c->fcgi_params.document_uri;
const char *css = srv->custom_css;
memset(&u_path, 0, sizeof(u_path));
blob - a06e82cff88e1f0b56f21f10175579e66d777ca1
blob + 14e2eca5e33aa5640070e3a4b9ef8634b2c05f64
--- gotwebd/sockets.c
+++ gotwebd/sockets.c
int cgi_inflight = 0;
+/* Request hash table needs some spare room to avoid collisions. */
+struct requestlist requests[GOTWEBD_MAXCLIENTS * 4];
+static SIPHASH_KEY requests_hash_key;
+
+static void
+requests_init(void)
+{
+ int i;
+
+ arc4random_buf(&requests_hash_key, sizeof(requests_hash_key));
+
+ for (i = 0; i < nitems(requests); i++)
+ TAILQ_INIT(&requests[i]);
+}
+
+static uint64_t
+request_hash(uint32_t request_id)
+{
+ return SipHash24(&requests_hash_key, &request_id, sizeof(request_id));
+}
+
+static void
+add_request(struct request *c)
+{
+ uint64_t slot = request_hash(c->request_id) % nitems(requests);
+ TAILQ_INSERT_HEAD(&requests[slot], c, entry);
+ client_cnt++;
+}
+
+static void
+del_request(struct request *c)
+{
+ uint64_t slot = request_hash(c->request_id) % nitems(requests);
+ TAILQ_REMOVE(&requests[slot], c, entry);
+ client_cnt--;
+}
+
+static struct request *
+find_request(uint32_t request_id)
+{
+ uint64_t slot;
+ struct request *c;
+
+ slot = request_hash(request_id) % nitems(requests);
+ TAILQ_FOREACH(c, &requests[slot], entry) {
+ if (c->request_id == request_id)
+ return c;
+ }
+
+ return NULL;
+}
+
+static void
+cleanup_request(struct request *c)
+{
+ cgi_inflight--;
+
+ del_request(c);
+
+ event_add(&c->sock->ev, NULL);
+
+ if (evtimer_initialized(&c->tmo))
+ evtimer_del(&c->tmo);
+ if (event_initialized(&c->ev))
+ event_del(&c->ev);
+ if (c->fd != -1)
+ close(c->fd);
+ free(c->buf);
+ free(c);
+}
+
+static void
+request_timeout(int fd, short events, void *arg)
+{
+ struct request *c = arg;
+
+ log_warnx("request %u has timed out", c->request_id);
+ cleanup_request(c);
+}
+
+static void
+requests_purge(void)
+{
+ uint64_t slot;
+ struct request *c;
+
+ for (slot = 0; slot < nitems(requests); slot++) {
+ while (!TAILQ_EMPTY(&requests[slot])) {
+ c = TAILQ_FIRST(&requests[slot]);
+ cleanup_request(c);
+ }
+ }
+}
+
+static uint32_t
+get_request_id(void)
+{
+ int duplicate = 0;
+ uint32_t id;
+
+ do {
+ id = arc4random();
+ duplicate = (find_request(id) != NULL);
+ } while (duplicate || id == 0);
+
+ return id;
+}
+
+static void
+request_done(struct request *c)
+{
+ /*
+ * If we have not yet handed the client off to gotweb.c we
+ * must send an FCGI end record ourselves.
+ */
+ if (c->client_status > CLIENT_CONNECT &&
+ c->client_status < CLIENT_REQUEST)
+ fcgi_create_end_record(c);
+
+ cleanup_request(c);
+}
+
void
sockets(struct gotwebd *env, int fd)
{
struct event sighup, sigint, sigusr1, sigchld, sigterm;
struct event_base *evb;
+ requests_init();
+
evb = event_init();
sockets_rlimit(-1);
struct socket *sock;
int i, have_unix = 0, have_inet = 0;
+ if (env->iev_fcgi == NULL)
+ fatalx("fcgi process not connected");
if (env->gotweb_pending != 0)
fatal("gotweb process not connected");
fatal("pledge");
}
#endif
+ event_add(&env->iev_fcgi->ev, NULL);
for (i = 0; i < env->prefork; i++)
event_add(&env->iev_gotweb[i].ev, NULL);
+}
+static void
+abort_request(struct imsg *imsg)
+{
+ struct request *c;
+ uint32_t request_id;
+
+ if (imsg_get_data(imsg, &request_id, sizeof(request_id)) == -1) {
+ log_warn("imsg_get_data");
+ return;
+ }
+
+ c = find_request(request_id);
+ if (c == NULL)
+ return;
+
+ request_done(c);
}
static void
break;
switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_REQ_ABORT:
+ abort_request(&imsg);
+ break;
default:
fatalx("%s: unknown imsg type %d", __func__,
imsg.hdr.type);
if (imsgbuf_init(&iev->ibuf, fd) == -1)
fatal("imsgbuf_init");
imsgbuf_allow_fdpass(&iev->ibuf);
+ imsgbuf_set_maxsize(&iev->ibuf, sizeof(struct gotwebd_fcgi_record));
iev->handler = server_dispatch_gotweb;
iev->data = iev;
imsg_event_add(iev);
env->gotweb_pending--;
+}
+
+static int
+process_request(struct request *c)
+{
+ struct gotwebd *env = gotwebd_env;
+ struct imsgev *iev_gotweb;
+ int ret, i;
+ struct request ic;
+
+ memcpy(&ic, c, sizeof(ic));
+
+ /* Don't leak pointers from our address space to another process. */
+ ic.sock = NULL;
+ ic.srv = NULL;
+ ic.t = NULL;
+ ic.tp = NULL;
+ ic.buf = NULL;
+ ic.outbuf = NULL;
+
+ /* Other process will use its own set of temp files. */
+ for (i = 0; i < nitems(c->priv_fd); i++)
+ ic.priv_fd[i] = -1;
+ ic.fd = -1;
+
+ /* Round-robin requests across gotweb processes. */
+ iev_gotweb = &env->iev_gotweb[env->gotweb_cur];
+ env->gotweb_cur = (env->gotweb_cur + 1) % env->prefork;
+
+ ret = imsg_compose_event(iev_gotweb, GOTWEBD_IMSG_REQ_PROCESS,
+ GOTWEBD_PROC_SERVER, -1, c->fd, &ic, sizeof(ic));
+ if (ret == -1) {
+ log_warn("imsg_compose_event");
+ return -1;
+ }
+
+ c->fd = -1;
+ c->client_status = CLIENT_REQUEST;
+ return 0;
+}
+
+static void
+recv_parsed_params(struct imsg *imsg)
+{
+ struct gotwebd_fcgi_params params, *p;
+ struct request *c;
+
+ if (imsg_get_data(imsg, ¶ms, sizeof(params)) == -1) {
+ log_warn("imsg_get_data");
+ return;
+ }
+
+ c = find_request(params.request_id);
+ if (c == NULL)
+ return;
+
+ if (c->client_status > CLIENT_FCGI_STDIN)
+ return;
+
+ if (c->client_status < CLIENT_FCGI_PARAMS)
+ goto fail;
+
+ p = &c->fcgi_params;
+
+ if (params.querystring[0] != '\0' &&
+ strlcpy(p->querystring, params.querystring,
+ sizeof(p->querystring)) >= sizeof(p->querystring)) {
+ log_warnx("querystring too long");
+ goto fail;
+ }
+
+ if (params.document_uri[0] != '\0' &&
+ strlcpy(p->document_uri, params.document_uri,
+ sizeof(p->document_uri)) >= sizeof(p->document_uri)) {
+ log_warnx("document uri too long");
+ goto fail;
+ }
+
+ if (params.server_name[0] != '\0' &&
+ strlcpy(p->server_name, params.server_name,
+ sizeof(p->server_name)) >= sizeof(p->server_name)) {
+ log_warnx("server name too long");
+ goto fail;
+ }
+
+ if (params.https && !p->https)
+ p->https = 1;
+
+ c->nparams_parsed++;
+
+ if (c->client_status == CLIENT_FCGI_STDIN &&
+ c->nparams_parsed >= c->nparams) {
+ if (process_request(c) == -1)
+ goto fail;
+ }
+
+ return;
+fail:
+ request_done(c);
+}
+
+static void
+server_dispatch_fcgi(int fd, short event, void *arg)
+{
+ struct imsgev *iev = arg;
+ struct imsgbuf *ibuf;
+ struct imsg imsg;
+ ssize_t n;
+ int shut = 0;
+
+ ibuf = &iev->ibuf;
+
+ if (event & EV_READ) {
+ if ((n = imsgbuf_read(ibuf)) == -1)
+ fatal("imsgbuf_read error");
+ if (n == 0) /* Connection closed */
+ shut = 1;
+ }
+ if (event & EV_WRITE) {
+ if (imsgbuf_write(ibuf) == -1)
+ fatal("imsgbuf_write");
+ }
+
+ for (;;) {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ fatal("imsg_get");
+ if (n == 0) /* No more messages. */
+ break;
+
+ switch (imsg.hdr.type) {
+ case GOTWEBD_IMSG_FCGI_PARAMS:
+ recv_parsed_params(&imsg);
+ break;
+ case GOTWEBD_IMSG_REQ_ABORT:
+ abort_request(&imsg);
+ break;
+ default:
+ fatalx("%s: unknown imsg type %d", __func__,
+ imsg.hdr.type);
+ }
+
+ imsg_free(&imsg);
+ }
+
+ if (!shut)
+ imsg_event_add(iev);
+ else {
+ /* This pipe is dead. Remove its event handler */
+ event_del(&iev->ev);
+ event_loopexit(NULL);
+ }
}
static void
+recv_fcgi_pipe(struct gotwebd *env, struct imsg *imsg)
+{
+ struct imsgev *iev;
+ int fd;
+
+ if (env->iev_fcgi != NULL) {
+ log_warn("fcgi pipe already received");
+ return;
+ }
+
+ fd = imsg_get_fd(imsg);
+ if (fd == -1)
+ fatalx("invalid gotweb pipe fd");
+
+ iev = calloc(1, sizeof(*iev));
+ if (iev == NULL)
+ fatal("calloc");
+
+ if (imsgbuf_init(&iev->ibuf, fd) == -1)
+ fatal("imsgbuf_init");
+ imsgbuf_allow_fdpass(&iev->ibuf);
+ imsgbuf_set_maxsize(&iev->ibuf, sizeof(struct gotwebd_fcgi_record));
+
+ iev->handler = server_dispatch_fcgi;
+ iev->data = iev;
+ event_set(&iev->ev, fd, EV_READ, server_dispatch_fcgi, iev);
+ imsg_event_add(iev);
+
+ env->iev_fcgi = iev;
+}
+
+static void
sockets_dispatch_main(int fd, short event, void *arg)
{
struct imsgev *iev = arg;
config_getcfg(env, &imsg);
break;
case GOTWEBD_IMSG_CTL_PIPE:
- recv_gotweb_pipe(env, &imsg);
+ if (env->iev_fcgi == NULL)
+ recv_fcgi_pipe(env, &imsg);
+ else
+ recv_gotweb_pipe(env, &imsg);
break;
case GOTWEBD_IMSG_CTL_START:
sockets_launch(env);
free(sock);
}
+ requests_purge();
+
imsgbuf_clear(&gotwebd_env->iev_parent->ibuf);
free(gotwebd_env->iev_parent);
+
+ imsgbuf_clear(&gotwebd_env->iev_fcgi->ibuf);
+ free(gotwebd_env->iev_fcgi);
+
for (i = 0; i < gotwebd_env->prefork; i++)
imsgbuf_clear(&gotwebd_env->iev_gotweb[i].ibuf);
free(gotwebd_env->iev_gotweb);
+
free(gotwebd_env);
exit(0);
struct socket *sock = (struct socket *)arg;
event_add(&sock->ev, NULL);
+}
+
+static int
+parse_params(struct request *c, uint8_t *record, size_t record_len)
+{
+ struct gotwebd *env = gotwebd_env;
+ struct gotwebd_fcgi_record rec;
+ int ret;
+
+ memset(&rec, 0, sizeof(rec));
+
+ memcpy(rec.record, record, record_len);
+ rec.record_len = record_len;
+ rec.request_id = c->request_id;
+
+ ret = imsg_compose_event(env->iev_fcgi,
+ GOTWEBD_IMSG_FCGI_PARSE_PARAMS,
+ GOTWEBD_PROC_SERVER, -1, -1, &rec, sizeof(rec));
+ if (ret == -1)
+ log_warn("imsg_compose_event");
+
+ return ret;
+}
+
+static void
+read_fcgi_records(int fd, short events, void *arg)
+{
+ struct request *c = arg;
+ ssize_t n;
+ struct fcgi_record_header h;
+ size_t record_len;
+
+ n = read(fd, c->buf + c->buf_len, FCGI_RECORD_SIZE - c->buf_len);
+ log_info("%u: %s: request %u, read=%zd", getpid(), __func__, c->request_id, n);
+
+ switch (n) {
+ case -1:
+ switch (errno) {
+ case EINTR:
+ case EAGAIN:
+ goto more;
+ default:
+ goto fail;
+ }
+ break;
+ case 0:
+ if (c->client_status < CLIENT_FCGI_STDIN) {
+ log_warnx("client %u closed connection too early",
+ c->request_id);
+ goto fail;
+ }
+ return;
+ default:
+ break;
+ }
+
+ c->buf_len += n;
+
+ while (c->buf_len >= sizeof(h)) {
+ memcpy(&h, c->buf, sizeof(h));
+
+ record_len = sizeof(h) + ntohs(h.content_len) + h.padding_len;
+ if (record_len > FCGI_RECORD_SIZE) {
+ log_warnx("FGI record length too large");
+ goto fail;
+ }
+
+ if (c->buf_len < record_len)
+ goto more;
+
+ switch (h.type) {
+ case FCGI_BEGIN_REQUEST:
+ if (c->client_status >= CLIENT_FCGI_BEGIN) {
+ log_warnx("unexpected FCGI_BEGIN_REQUEST");
+ goto fail;
+ }
+
+ if (ntohs(h.content_len) !=
+ sizeof(struct fcgi_begin_request_body)) {
+ log_warnx("wrong begin request size %u != %zu",
+ ntohs(h.content_len),
+ sizeof(struct fcgi_begin_request_body));
+ goto fail;
+ }
+
+ /* XXX -- FCGI_CANT_MPX_CONN */
+ c->client_status = CLIENT_FCGI_BEGIN;
+ c->id = ntohs(h.id);
+ break;
+ case FCGI_PARAMS:
+ if (c->client_status < CLIENT_FCGI_BEGIN) {
+ log_warnx("FCGI_PARAMS without "
+ "FCGI_BEGIN_REQUEST");
+ goto fail;
+ }
+ if (c->client_status > CLIENT_FCGI_PARAMS) {
+ log_warnx("FCGI_PARAMS after FCGI_STDIN");
+ goto fail;
+ }
+
+ if (c->id != ntohs(h.id)) {
+ log_warnx("unexpected ID in FCGI header");
+ goto fail;
+ }
+
+ c->client_status = CLIENT_FCGI_PARAMS;
+ c->nparams++;
+
+ if (parse_params(c, c->buf, record_len) == -1)
+ goto fail;
+ break;
+ case FCGI_ABORT_REQUEST:
+ log_warnx("received FCGI_ABORT_REQUEST from client");
+ request_done(c);
+ return;
+ case FCGI_STDIN:
+ if (c->client_status < CLIENT_FCGI_BEGIN) {
+ log_warnx("FCGI_STDIN without "
+ "FCGI_BEGIN_REQUEST");
+ goto fail;
+ }
+
+ if (c->client_status < CLIENT_FCGI_PARAMS) {
+ log_warnx("FCGI_STDIN without FCGI_PARAMS");
+ goto fail;
+ }
+
+ if (c->id != ntohs(h.id)) {
+ log_warnx("unexpected ID in FCGI header");
+ goto fail;
+ }
+
+ c->client_status = CLIENT_FCGI_STDIN;
+ if (c->nparams_parsed >= c->nparams) {
+ if (process_request(c) == -1)
+ goto fail;
+ }
+ break;
+ default:
+ log_warn("unexpected FCGI type %u", h.type);
+ goto fail;
+ }
+
+ /* drop the parsed record */
+ c->buf_len -= record_len;
+ memmove(c->buf, c->buf + record_len, c->buf_len);
+ }
+more:
+ event_add(&c->ev, NULL);
+ return;
+fail:
+ request_done(c);
}
void
socklen_t len;
int s;
+ log_info("%u: %s: %d clients", getpid(), __func__, client_cnt);
+
backoff.tv_sec = 1;
backoff.tv_usec = 0;
- event_add(&sock->ev, NULL);
- if (event & EV_TIMEOUT)
+ if (event & EV_TIMEOUT) {
+ event_add(&sock->ev, NULL);
+ log_info("%u: %s: timeout", getpid(), __func__);
return;
+ }
len = sizeof(ss);
case EINTR:
case EWOULDBLOCK:
case ECONNABORTED:
+ log_info("%u: %s: errno %d", getpid(), __func__, errno);
+ event_add(&sock->ev, NULL);
return;
case EMFILE:
case ENFILE:
}
}
- if (client_cnt > GOTWEBD_MAXCLIENTS)
- goto err;
+ if (client_cnt > GOTWEBD_MAXCLIENTS) {
+ cgi_inflight--;
+ close(s);
+ if (c != NULL)
+ free(c);
+ event_add(&sock->ev, NULL);
+ return;
+ }
c = calloc(1, sizeof(struct request));
if (c == NULL) {
log_warn("%s: calloc", __func__);
close(s);
cgi_inflight--;
+ event_add(&sock->ev, NULL);
return;
}
close(s);
cgi_inflight--;
free(c);
+ event_add(&sock->ev, NULL);
return;
}
c->sock = sock;
memcpy(c->priv_fd, gotwebd_env->priv_fd, sizeof(c->priv_fd));
c->sock_id = sock->conf.id;
- c->buf_pos = 0;
c->buf_len = 0;
- c->request_started = 0;
c->client_status = CLIENT_CONNECT;
+ c->request_id = get_request_id();
- event_set(&c->ev, s, EV_READ, fcgi_request, c);
+ event_set(&c->ev, s, EV_READ, read_fcgi_records, c);
event_add(&c->ev, NULL);
- evtimer_set(&c->tmo, fcgi_timeout, c);
+ evtimer_set(&c->tmo, request_timeout, c);
evtimer_add(&c->tmo, &timeout);
- return;
-err:
- cgi_inflight--;
- close(s);
- if (c != NULL)
- free(c);
+ log_info("%u: %s: add_request %d", getpid(), __func__, c->request_id);
+ add_request(c);
}
void