1 /* $OpenBSD: slowcgi.c,v 1.64 2022/08/07 07:43:53 op Exp $ */
3 * Copyright (c) 2013 David Gwynne <dlg@openbsd.org>
4 * Copyright (c) 2013 Florian Obser <florian@openbsd.org>
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 #include <sys/types.h>
20 #include <sys/ioctl.h>
21 #include <sys/queue.h>
22 #include <sys/socket.h>
27 #include <arpa/inet.h>
42 #define TIMEOUT_DEFAULT 120
43 #define TIMEOUT_MAX (86400 * 365)
44 #define SLOWCGI_USER "www"
46 #define FCGI_CONTENT_SIZE 65535
47 #define FCGI_PADDING_SIZE 255
48 #define FCGI_RECORD_SIZE \
49 (sizeof(struct fcgi_record_header) + FCGI_CONTENT_SIZE + FCGI_PADDING_SIZE)
51 #define FCGI_ALIGNMENT 8
52 #define FCGI_ALIGN(n) \
53 (((n) + (FCGI_ALIGNMENT - 1)) & ~(FCGI_ALIGNMENT - 1))
59 #define FCGI_BEGIN_REQUEST 1
60 #define FCGI_ABORT_REQUEST 2
61 #define FCGI_END_REQUEST 3
67 #define FCGI_GET_VALUES 9
68 #define FCGI_GET_VALUES_RESULT 10
69 #define FCGI_UNKNOWN_TYPE 11
70 #define FCGI_MAXTYPE (FCGI_UNKNOWN_TYPE)
72 #define FCGI_REQUEST_COMPLETE 0
73 #define FCGI_CANT_MPX_CONN 1
74 #define FCGI_OVERLOADED 2
75 #define FCGI_UNKNOWN_ROLE 3
82 struct event ev, pause;
86 SLIST_ENTRY(env_val) entry;
89 SLIST_HEAD(env_head, env_val);
91 struct fcgi_record_header {
100 struct fcgi_response {
101 TAILQ_ENTRY(fcgi_response) entry;
102 uint8_t data[FCGI_RECORD_SIZE];
106 TAILQ_HEAD(fcgi_response_head, fcgi_response);
109 TAILQ_ENTRY(fcgi_stdin) entry;
110 uint8_t data[FCGI_RECORD_SIZE];
114 TAILQ_HEAD(fcgi_stdin_head, fcgi_stdin);
117 LIST_ENTRY(request) entry;
119 struct event resp_ev;
122 uint8_t buf[FCGI_RECORD_SIZE];
125 struct fcgi_response_head response_head;
126 struct fcgi_stdin_head stdin_head;
128 char script_name[PATH_MAX];
133 struct event script_ev;
134 struct event script_err_ev;
135 struct event script_stdin_ev;
137 int stdout_fd_closed;
138 int stderr_fd_closed;
139 uint8_t script_flags;
140 uint8_t request_started;
141 int inflight_fds_accounted;
144 LIST_HEAD(requests_head, request);
146 struct slowcgi_proc {
147 struct requests_head requests;
148 struct event ev_sigchld;
151 struct fcgi_begin_request_body {
157 struct fcgi_end_request_body {
159 uint8_t protocol_status;
163 __dead void usage(void);
164 int slowcgi_listen(char *, struct passwd *);
165 void slowcgi_paused(int, short, void *);
166 int accept_reserve(int, struct sockaddr *, socklen_t *, int, int *);
167 void slowcgi_accept(int, short, void *);
168 void slowcgi_request(int, short, void *);
169 void slowcgi_response(int, short, void *);
170 void slowcgi_add_response(struct request *, struct fcgi_response *);
171 void slowcgi_timeout(int, short, void *);
172 void slowcgi_sig_handler(int, short, void *);
173 size_t parse_record(uint8_t * , size_t, struct request *);
174 void parse_begin_request(uint8_t *, uint16_t, struct request *,
176 void parse_params(uint8_t *, uint16_t, struct request *, uint16_t);
177 void parse_stdin(uint8_t *, uint16_t, struct request *, uint16_t);
178 void exec_cgi(struct request *);
179 void script_in(int, struct event *, struct request *, uint8_t);
180 void script_std_in(int, short, void *);
181 void script_err_in(int, short, void *);
182 void script_out(int, short, void *);
183 void create_end_record(struct request *);
184 void dump_fcgi_record(const char *,
185 struct fcgi_record_header *);
186 void dump_fcgi_record_header(const char *,
187 struct fcgi_record_header *);
188 void dump_fcgi_begin_request_body(const char *,
189 struct fcgi_begin_request_body *);
190 void dump_fcgi_end_request_body(const char *,
191 struct fcgi_end_request_body *);
192 void cleanup_request(struct request *);
195 __dead void (*err)(int, const char *, ...)
196 __attribute__((__format__ (printf, 2, 3)));
197 __dead void (*errx)(int, const char *, ...)
198 __attribute__((__format__ (printf, 2, 3)));
199 void (*warn)(const char *, ...)
200 __attribute__((__format__ (printf, 1, 2)));
201 void (*warnx)(const char *, ...)
202 __attribute__((__format__ (printf, 1, 2)));
203 void (*info)(const char *, ...)
204 __attribute__((__format__ (printf, 1, 2)));
205 void (*debug)(const char *, ...)
206 __attribute__((__format__ (printf, 1, 2)));
209 const struct loggers conslogger = {
218 __dead void syslog_err(int, const char *, ...)
219 __attribute__((__format__ (printf, 2, 3)));
220 __dead void syslog_errx(int, const char *, ...)
221 __attribute__((__format__ (printf, 2, 3)));
222 void syslog_warn(const char *, ...)
223 __attribute__((__format__ (printf, 1, 2)));
224 void syslog_warnx(const char *, ...)
225 __attribute__((__format__ (printf, 1, 2)));
226 void syslog_info(const char *, ...)
227 __attribute__((__format__ (printf, 1, 2)));
228 void syslog_debug(const char *, ...)
229 __attribute__((__format__ (printf, 1, 2)));
230 void syslog_vstrerror(int, int, const char *, va_list)
231 __attribute__((__format__ (printf, 3, 0)));
233 const struct loggers syslogger = {
242 const struct loggers *logger = &conslogger;
244 #define lerr(_e, _f...) logger->err((_e), _f)
245 #define lerrx(_e, _f...) logger->errx((_e), _f)
246 #define lwarn(_f...) logger->warn(_f)
247 #define lwarnx(_f...) logger->warnx(_f)
248 #define linfo(_f...) logger->info(_f)
249 #define ldebug(_f...) logger->debug(_f)
254 extern char *__progname;
256 "usage: %s [-dv] [-p path] [-s socket] [-t timeout] [-U user] "
257 "[-u user]\n", __progname);
261 struct timeval timeout = { TIMEOUT_DEFAULT, 0 };
262 struct slowcgi_proc slowcgi_proc;
266 char *fcgi_socket = "/var/www/run/slowcgi.sock";
269 main(int argc, char *argv[])
271 extern char *__progname;
272 struct listener *l = NULL;
276 const char *chrootpath = NULL;
277 const char *sock_user = SLOWCGI_USER;
278 const char *slowcgi_user = SLOWCGI_USER;
282 * Ensure we have fds 0-2 open so that we have no fd overlaps
283 * in exec_cgi() later. Just exit on error, we don't have enough
284 * fds open to output an error message anywhere.
286 for (c=0; c < 3; c++) {
287 if (fstat(c, &sb) == -1) {
288 if ((fd = open("/dev/null", O_RDWR)) != -1) {
289 if (dup2(fd, c) == -1)
298 while ((c = getopt(argc, argv, "dp:s:t:U:u:v")) != -1) {
307 fcgi_socket = optarg;
310 timeout.tv_sec = strtonum(optarg, 1, TIMEOUT_MAX,
313 errx(1, "timeout is %s: %s", errstr, optarg);
319 slowcgi_user = optarg;
331 errx(1, "need root privileges");
333 if (!debug && daemon(0, 0) == -1)
337 openlog(__progname, LOG_PID|LOG_NDELAY, LOG_DAEMON);
341 ldebug("sock_user: %s", sock_user);
342 pw = getpwnam(sock_user);
344 lerrx(1, "no %s user", sock_user);
346 fd = slowcgi_listen(fcgi_socket, pw);
348 ldebug("slowcgi_user: %s", slowcgi_user);
349 pw = getpwnam(slowcgi_user);
351 lerrx(1, "no %s user", slowcgi_user);
353 if (chrootpath == NULL)
354 chrootpath = pw->pw_dir;
356 if (chroot(chrootpath) == -1)
357 lerr(1, "chroot(%s)", chrootpath);
359 ldebug("chroot: %s", chrootpath);
361 if (chdir("/") == -1)
364 if (setgroups(1, &pw->pw_gid) ||
365 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
366 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
367 lerr(1, "unable to revoke privs");
369 if (pledge("stdio rpath unix proc exec", NULL) == -1)
372 LIST_INIT(&slowcgi_proc.requests);
375 l = calloc(1, sizeof(*l));
377 lerr(1, "listener ev alloc");
379 event_set(&l->ev, fd, EV_READ | EV_PERSIST, slowcgi_accept, l);
380 event_add(&l->ev, NULL);
381 evtimer_set(&l->pause, slowcgi_paused, l);
383 signal_set(&slowcgi_proc.ev_sigchld, SIGCHLD, slowcgi_sig_handler,
385 signal(SIGPIPE, SIG_IGN);
387 signal_add(&slowcgi_proc.ev_sigchld, NULL);
394 slowcgi_listen(char *path, struct passwd *pw)
396 struct sockaddr_un sun;
400 if ((fd = socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC,
402 lerr(1, "slowcgi_listen: socket");
404 bzero(&sun, sizeof(sun));
405 sun.sun_family = AF_UNIX;
406 if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
407 sizeof(sun.sun_path))
408 lerrx(1, "socket path too long");
410 if (unlink(path) == -1)
412 lerr(1, "slowcgi_listen: unlink %s", path);
414 old_umask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
416 if (bind(fd, (struct sockaddr *)&sun, sizeof(sun)) == -1)
417 lerr(1,"slowcgi_listen: bind: %s", path);
421 if (chown(path, pw->pw_uid, pw->pw_gid) == -1)
422 lerr(1, "slowcgi_listen: chown: %s", path);
424 if (listen(fd, 5) == -1)
427 ldebug("socket: %s", path);
432 slowcgi_paused(int fd, short events, void *arg)
434 struct listener *l = arg;
435 event_add(&l->ev, NULL);
439 accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
440 int reserve, int *counter)
443 if (getdtablecount() + reserve +
444 ((*counter + 1) * FD_NEEDED) >= getdtablesize()) {
445 ldebug("inflight fds exceeded");
450 if ((ret = accept4(sockfd, addr, addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC))
453 ldebug("inflight incremented, now %d", *counter);
459 slowcgi_accept(int fd, short events, void *arg)
462 struct sockaddr_storage ss;
463 struct timeval backoff;
474 if ((s = accept_reserve(fd, (struct sockaddr *)&ss,
475 &len, FD_RESERVE, &cgi_inflight)) == -1) {
484 evtimer_add(&l->pause, &backoff);
491 c = calloc(1, sizeof(*c));
493 lwarn("cannot calloc request");
501 c->request_started = 0;
502 c->stdin_fd_closed = c->stdout_fd_closed = c->stderr_fd_closed = 0;
503 c->inflight_fds_accounted = 0;
504 TAILQ_INIT(&c->response_head);
505 TAILQ_INIT(&c->stdin_head);
507 event_set(&c->ev, s, EV_READ | EV_PERSIST, slowcgi_request, c);
508 event_add(&c->ev, NULL);
509 event_set(&c->resp_ev, s, EV_WRITE | EV_PERSIST, slowcgi_response, c);
510 evtimer_set(&c->tmo, slowcgi_timeout, c);
511 evtimer_add(&c->tmo, &timeout);
512 LIST_INSERT_HEAD(&slowcgi_proc.requests, c, entry);
516 slowcgi_timeout(int fd, short events, void *arg)
518 cleanup_request((struct request*) arg);
522 slowcgi_sig_handler(int sig, short event, void *arg)
525 struct slowcgi_proc *p;
533 while ((pid = waitpid(WAIT_ANY, &status, WNOHANG)) > 0) {
534 LIST_FOREACH(c, &p->requests, entry)
535 if (c->script_pid == pid)
538 lwarnx("caught exit of unknown child %i", pid);
542 if (WIFSIGNALED(status))
543 c->script_status = WTERMSIG(status);
545 c->script_status = WEXITSTATUS(status);
547 if (c->script_flags == (STDOUT_DONE | STDERR_DONE))
548 create_end_record(c);
549 c->script_flags |= SCRIPT_DONE;
551 ldebug("wait: %s", c->script_name);
553 if (pid == -1 && errno != ECHILD)
557 lerr(1, "unexpected signal: %d", sig);
563 slowcgi_add_response(struct request *c, struct fcgi_response *resp)
565 struct fcgi_record_header *header;
568 header = (struct fcgi_record_header*)resp->data;
570 /* The FastCGI spec suggests to align the output buffer */
571 padded_len = FCGI_ALIGN(resp->data_len);
572 if (padded_len > resp->data_len) {
573 /* There should always be FCGI_PADDING_SIZE bytes left */
574 if (padded_len > FCGI_RECORD_SIZE)
575 lerr(1, "response too long");
576 header->padding_len = padded_len - resp->data_len;
577 resp->data_len = padded_len;
580 TAILQ_INSERT_TAIL(&c->response_head, resp, entry);
581 event_add(&c->resp_ev, NULL);
585 slowcgi_response(int fd, short events, void *arg)
588 struct fcgi_record_header *header;
589 struct fcgi_response *resp;
594 while ((resp = TAILQ_FIRST(&c->response_head))) {
595 header = (struct fcgi_record_header*) resp->data;
597 dump_fcgi_record("resp ", header);
599 n = write(fd, resp->data + resp->data_pos, resp->data_len);
601 if (errno == EAGAIN || errno == EINTR)
608 if (resp->data_len == 0) {
609 TAILQ_REMOVE(&c->response_head, resp, entry);
614 if (TAILQ_EMPTY(&c->response_head)) {
615 if (c->script_flags == (STDOUT_DONE | STDERR_DONE |
619 event_del(&c->resp_ev);
624 slowcgi_request(int fd, short events, void *arg)
632 n = read(fd, c->buf + c->buf_pos + c->buf_len,
633 FCGI_RECORD_SIZE - c->buf_pos-c->buf_len);
647 ldebug("closed connection");
656 * Parse the records as they are received. Per the FastCGI
657 * specification, the server need only receive the FastCGI
658 * parameter records in full; it is free to begin execution
659 * at that point, which is what happens here.
662 parsed = parse_record(c->buf + c->buf_pos, c->buf_len, c);
663 c->buf_pos += parsed;
664 c->buf_len -= parsed;
665 } while (parsed > 0 && c->buf_len > 0);
667 /* Make space for further reads */
668 if (c->buf_len > 0) {
669 bcopy(c->buf + c->buf_pos, c->buf, c->buf_len);
678 parse_begin_request(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
680 /* XXX -- FCGI_CANT_MPX_CONN */
681 if (c->request_started) {
682 lwarnx("unexpected FCGI_BEGIN_REQUEST, ignoring");
686 if (n != sizeof(struct fcgi_begin_request_body)) {
687 lwarnx("wrong size %d != %lu", n,
688 sizeof(struct fcgi_begin_request_body));
692 c->request_started = 1;
700 parse_params(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
702 struct env_val *env_entry;
703 uint32_t name_len, val_len;
705 if (!c->request_started) {
706 lwarnx("FCGI_PARAMS without FCGI_BEGIN_REQUEST, ignoring");
711 lwarnx("unexpected id, ignoring");
716 * If this is the last FastCGI parameter record,
717 * begin execution of the CGI script.
725 if (buf[0] >> 7 == 0) {
731 name_len = ((buf[0] & 0x7f) << 24) +
732 (buf[1] << 16) + (buf[2] << 8) + buf[3];
740 if (buf[0] >> 7 == 0) {
746 val_len = ((buf[0] & 0x7f) << 24) +
747 (buf[1] << 16) + (buf[2] << 8) +
757 if (n < name_len + val_len)
760 if ((env_entry = malloc(sizeof(struct env_val))) == NULL) {
761 lwarnx("cannot allocate env_entry");
765 if ((env_entry->val = calloc(sizeof(char), name_len + val_len +
767 lwarnx("cannot allocate env_entry->val");
772 bcopy(buf, env_entry->val, name_len);
776 env_entry->val[name_len] = '\0';
777 if (val_len < PATH_MAX && strcmp(env_entry->val,
778 "SCRIPT_NAME") == 0 && c->script_name[0] == '\0') {
779 bcopy(buf, c->script_name, val_len);
780 c->script_name[val_len] = '\0';
781 } else if (val_len < PATH_MAX && strcmp(env_entry->val,
782 "SCRIPT_FILENAME") == 0) {
783 bcopy(buf, c->script_name, val_len);
784 c->script_name[val_len] = '\0';
786 env_entry->val[name_len] = '=';
788 bcopy(buf, (env_entry->val) + name_len + 1, val_len);
792 SLIST_INSERT_HEAD(&c->env, env_entry, entry);
793 ldebug("env[%d], %s", c->env_count, env_entry->val);
799 parse_stdin(uint8_t *buf, uint16_t n, struct request *c, uint16_t id)
801 struct fcgi_stdin *node;
804 lwarnx("unexpected id, ignoring");
808 if ((node = calloc(1, sizeof(struct fcgi_stdin))) == NULL) {
809 lwarnx("cannot calloc stdin node");
813 bcopy(buf, node->data, n);
817 TAILQ_INSERT_TAIL(&c->stdin_head, node, entry);
819 if (event_initialized(&c->script_stdin_ev))
820 event_add(&c->script_stdin_ev, NULL);
824 parse_record(uint8_t *buf, size_t n, struct request *c)
826 struct fcgi_record_header *h;
828 if (n < sizeof(struct fcgi_record_header))
831 h = (struct fcgi_record_header*) buf;
834 dump_fcgi_record("", h);
836 if (n < sizeof(struct fcgi_record_header) + ntohs(h->content_len)
841 lerrx(1, "wrong version");
844 case FCGI_BEGIN_REQUEST:
845 parse_begin_request(buf + sizeof(struct fcgi_record_header),
846 ntohs(h->content_len), c, ntohs(h->id));
849 parse_params(buf + sizeof(struct fcgi_record_header),
850 ntohs(h->content_len), c, ntohs(h->id));
853 parse_stdin(buf + sizeof(struct fcgi_record_header),
854 ntohs(h->content_len), c, ntohs(h->id));
857 lwarnx("unimplemented type %d", h->type);
861 return (sizeof(struct fcgi_record_header) + ntohs(h->content_len)
866 * Fork a new CGI process to handle the request, translating
867 * between FastCGI parameter records and CGI's environment variables,
868 * as well as between the CGI process' stdin/stdout and the
869 * corresponding FastCGI records.
872 exec_cgi(struct request *c)
874 struct env_val *env_entry;
875 int s_in[2], s_out[2], s_err[2], i;
883 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s_in) == -1)
884 lerr(1, "socketpair");
885 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s_out) == -1)
886 lerr(1, "socketpair");
887 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, s_err) == -1)
888 lerr(1, "socketpair");
890 c->inflight_fds_accounted = 1;
891 ldebug("fork: %s", c->script_name);
893 switch (pid = fork()) {
895 c->script_status = errno;
907 c->stdin_fd_closed = c->stdout_fd_closed =
908 c->stderr_fd_closed = 1;
909 c->script_flags = (STDOUT_DONE | STDERR_DONE | SCRIPT_DONE);
911 create_end_record(c);
915 if (pledge("stdio rpath exec", NULL) == -1)
921 if (dup2(s_in[1], STDIN_FILENO) == -1)
923 if (dup2(s_out[1], STDOUT_FILENO) == -1)
925 if (dup2(s_err[1], STDERR_FILENO) == -1)
932 signal(SIGPIPE, SIG_DFL);
934 path = strrchr(c->script_name, '/');
936 if (path != c->script_name) {
938 if (chdir(c->script_name) == -1)
939 lwarn("cannot chdir to %s",
943 if (chdir("/") == -1)
944 lwarn("cannot chdir to /");
947 argv[0] = c->script_name;
949 if ((env = calloc(c->env_count + 1, sizeof(char*))) == NULL)
951 SLIST_FOREACH(env_entry, &c->env, entry)
952 env[i++] = env_entry->val;
954 execve(c->script_name, argv, env);
955 lwarn("execve %s", c->script_name);
965 fcntl(s_in[0], F_SETFD, FD_CLOEXEC);
966 fcntl(s_out[0], F_SETFD, FD_CLOEXEC);
967 fcntl(s_err[0], F_SETFD, FD_CLOEXEC);
969 if (ioctl(s_in[0], FIONBIO, &on) == -1)
970 lerr(1, "script ioctl(FIONBIO)");
971 if (ioctl(s_out[0], FIONBIO, &on) == -1)
972 lerr(1, "script ioctl(FIONBIO)");
973 if (ioctl(s_err[0], FIONBIO, &on) == -1)
974 lerr(1, "script ioctl(FIONBIO)");
977 event_set(&c->script_stdin_ev, s_in[0], EV_WRITE | EV_PERSIST,
979 event_add(&c->script_stdin_ev, NULL);
980 event_set(&c->script_ev, s_out[0], EV_READ | EV_PERSIST,
982 event_add(&c->script_ev, NULL);
983 event_set(&c->script_err_ev, s_err[0], EV_READ | EV_PERSIST,
985 event_add(&c->script_err_ev, NULL);
989 create_end_record(struct request *c)
991 struct fcgi_response *resp;
992 struct fcgi_record_header *header;
993 struct fcgi_end_request_body *end_request;
995 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) {
996 lwarnx("cannot malloc fcgi_response");
999 header = (struct fcgi_record_header*) resp->data;
1000 header->version = 1;
1001 header->type = FCGI_END_REQUEST;
1002 header->id = htons(c->id);
1003 header->content_len = htons(sizeof(struct
1004 fcgi_end_request_body));
1005 header->padding_len = 0;
1006 header->reserved = 0;
1007 end_request = (struct fcgi_end_request_body *) (resp->data +
1008 sizeof(struct fcgi_record_header));
1009 end_request->app_status = htonl(c->script_status);
1010 end_request->protocol_status = FCGI_REQUEST_COMPLETE;
1011 end_request->reserved[0] = 0;
1012 end_request->reserved[1] = 0;
1013 end_request->reserved[2] = 0;
1015 resp->data_len = sizeof(struct fcgi_end_request_body) +
1016 sizeof(struct fcgi_record_header);
1017 slowcgi_add_response(c, resp);
1021 script_in(int fd, struct event *ev, struct request *c, uint8_t type)
1023 struct fcgi_response *resp;
1024 struct fcgi_record_header *header;
1027 if ((resp = calloc(1, sizeof(struct fcgi_response))) == NULL) {
1028 lwarnx("cannot malloc fcgi_response");
1031 header = (struct fcgi_record_header*) resp->data;
1032 header->version = 1;
1033 header->type = type;
1034 header->id = htons(c->id);
1035 header->padding_len = 0;
1036 header->reserved = 0;
1038 n = read(fd, resp->data + sizeof(struct fcgi_record_header),
1048 n = 0; /* fake empty FCGI_STD{OUT,ERR} response */
1051 header->content_len = htons(n);
1053 resp->data_len = n + sizeof(struct fcgi_record_header);
1054 slowcgi_add_response(c, resp);
1057 if (type == FCGI_STDOUT)
1058 c->script_flags |= STDOUT_DONE;
1060 c->script_flags |= STDERR_DONE;
1062 if (c->script_flags == (STDOUT_DONE | STDERR_DONE |
1064 create_end_record(c);
1068 if (type == FCGI_STDOUT)
1069 c->stdout_fd_closed = 1;
1071 c->stderr_fd_closed = 1;
1076 script_std_in(int fd, short events, void *arg)
1078 struct request *c = arg;
1079 script_in(fd, &c->script_ev, c, FCGI_STDOUT);
1083 script_err_in(int fd, short events, void *arg)
1085 struct request *c = arg;
1086 script_in(fd, &c->script_err_ev, c, FCGI_STDERR);
1090 script_out(int fd, short events, void *arg)
1093 struct fcgi_stdin *node;
1098 while ((node = TAILQ_FIRST(&c->stdin_head))) {
1099 if (node->data_len == 0) { /* end of stdin marker */
1101 c->stdin_fd_closed = 1;
1104 n = write(fd, node->data + node->data_pos, node->data_len);
1106 if (errno == EAGAIN || errno == EINTR)
1108 event_del(&c->script_stdin_ev);
1111 node->data_pos += n;
1112 node->data_len -= n;
1113 if (node->data_len == 0) {
1114 TAILQ_REMOVE(&c->stdin_head, node, entry);
1118 event_del(&c->script_stdin_ev);
1122 cleanup_request(struct request *c)
1124 struct fcgi_response *resp;
1125 struct fcgi_stdin *stdin_node;
1126 struct env_val *env_entry;
1128 evtimer_del(&c->tmo);
1129 if (event_initialized(&c->ev))
1131 if (event_initialized(&c->resp_ev))
1132 event_del(&c->resp_ev);
1133 if (event_initialized(&c->script_ev)) {
1134 if (!c->stdout_fd_closed)
1135 close(EVENT_FD(&c->script_ev));
1136 event_del(&c->script_ev);
1138 if (event_initialized(&c->script_err_ev)) {
1139 if (!c->stderr_fd_closed)
1140 close(EVENT_FD(&c->script_err_ev));
1141 event_del(&c->script_err_ev);
1143 if (event_initialized(&c->script_stdin_ev)) {
1144 if (!c->stdin_fd_closed)
1145 close(EVENT_FD(&c->script_stdin_ev));
1146 event_del(&c->script_stdin_ev);
1149 while (!SLIST_EMPTY(&c->env)) {
1150 env_entry = SLIST_FIRST(&c->env);
1151 SLIST_REMOVE_HEAD(&c->env, entry);
1152 free(env_entry->val);
1156 while ((resp = TAILQ_FIRST(&c->response_head))) {
1157 TAILQ_REMOVE(&c->response_head, resp, entry);
1160 while ((stdin_node = TAILQ_FIRST(&c->stdin_head))) {
1161 TAILQ_REMOVE(&c->stdin_head, stdin_node, entry);
1164 LIST_REMOVE(c, entry);
1165 if (! c->inflight_fds_accounted)
1171 dump_fcgi_record(const char *p, struct fcgi_record_header *h)
1173 dump_fcgi_record_header(p, h);
1175 if (h->type == FCGI_BEGIN_REQUEST)
1176 dump_fcgi_begin_request_body(p,
1177 (struct fcgi_begin_request_body *)(h + 1));
1178 else if (h->type == FCGI_END_REQUEST)
1179 dump_fcgi_end_request_body(p,
1180 (struct fcgi_end_request_body *)(h + 1));
1184 dump_fcgi_record_header(const char* p, struct fcgi_record_header *h)
1186 ldebug("%sversion: %d", p, h->version);
1187 ldebug("%stype: %d", p, h->type);
1188 ldebug("%srequestId: %d", p, ntohs(h->id));
1189 ldebug("%scontentLength: %d", p, ntohs(h->content_len));
1190 ldebug("%spaddingLength: %d", p, h->padding_len);
1191 ldebug("%sreserved: %d", p, h->reserved);
1195 dump_fcgi_begin_request_body(const char *p, struct fcgi_begin_request_body *b)
1197 ldebug("%srole %d", p, ntohs(b->role));
1198 ldebug("%sflags %d", p, b->flags);
1202 dump_fcgi_end_request_body(const char *p, struct fcgi_end_request_body *b)
1204 ldebug("%sappStatus: %d", p, ntohl(b->app_status));
1205 ldebug("%sprotocolStatus: %d", p, b->protocol_status);
1209 syslog_vstrerror(int e, int priority, const char *fmt, va_list ap)
1213 if (vasprintf(&s, fmt, ap) == -1) {
1214 syslog(LOG_EMERG, "unable to alloc in syslog_vstrerror");
1217 syslog(priority, "%s: %s", s, strerror(e));
1222 syslog_err(int ecode, const char *fmt, ...)
1227 syslog_vstrerror(errno, LOG_CRIT, fmt, ap);
1233 syslog_errx(int ecode, const char *fmt, ...)
1238 vsyslog(LOG_CRIT, fmt, ap);
1244 syslog_warn(const char *fmt, ...)
1249 syslog_vstrerror(errno, LOG_ERR, fmt, ap);
1254 syslog_warnx(const char *fmt, ...)
1259 vsyslog(LOG_ERR, fmt, ap);
1264 syslog_info(const char *fmt, ...)
1269 vsyslog(LOG_INFO, fmt, ap);
1274 syslog_debug(const char *fmt, ...)
1279 vsyslog(LOG_DEBUG, fmt, ap);