2012-03-07 20:55:27 -07:00
|
|
|
void
|
|
|
|
sigchld(int sig)
|
|
|
|
{
|
|
|
|
while (waitpid(0, NULL, WNOHANG) > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
cgi_child(const char *relpath)
|
|
|
|
{
|
2012-03-09 10:27:00 -07:00
|
|
|
env("GATEWAY_INTERFACE", "CGI/1.1");
|
|
|
|
env("SERVER_SOFTWARE", FNORD);
|
|
|
|
env("REQUEST_URI", path);
|
|
|
|
env("SERVER_NAME", host);
|
|
|
|
env("SCRIPT_NAME", relpath);
|
|
|
|
env("REMOTE_ADDR", remote_ip);
|
|
|
|
env("REMOTE_PORT", remote_port);
|
|
|
|
env("REMOTE_IDENT", remote_ident);
|
2012-03-07 22:16:02 -07:00
|
|
|
if (content_length) {
|
2012-03-07 20:55:27 -07:00
|
|
|
char cl[20];
|
|
|
|
|
|
|
|
snprintf(cl, sizeof cl, "%llu", (unsigned long long) content_length);
|
2012-03-09 10:27:00 -07:00
|
|
|
env("CONTENT_LENGTH", cl);
|
|
|
|
env("CONTENT_TYPE", content_type);
|
2012-03-07 20:55:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
execl(relpath, relpath, NULL);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-03-07 22:16:02 -07:00
|
|
|
cgi_parent(int cin, int cout, int passthru)
|
2012-03-07 20:55:27 -07:00
|
|
|
{
|
2012-03-07 22:16:02 -07:00
|
|
|
char cgiheader[BUFFER_SIZE];
|
|
|
|
size_t cgiheaderlen = 0;
|
2012-03-07 20:55:27 -07:00
|
|
|
FILE *cinf = fdopen(cin, "rb");
|
2012-03-07 22:16:02 -07:00
|
|
|
size_t size = 0;
|
|
|
|
int header_sent = 0;
|
2012-03-07 20:55:27 -07:00
|
|
|
|
2012-03-07 22:16:02 -07:00
|
|
|
fcntl(cin, F_SETFL, O_NONBLOCK);
|
2012-03-07 20:55:27 -07:00
|
|
|
signal(SIGCHLD, sigchld);
|
|
|
|
signal(SIGPIPE, SIG_IGN); /* NO! no signal! */
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
int nfds;
|
|
|
|
fd_set rfds, wfds;
|
|
|
|
|
|
|
|
FD_ZERO(&rfds);
|
|
|
|
FD_ZERO(&wfds);
|
2012-03-07 22:16:02 -07:00
|
|
|
FD_SET(cin, &rfds);
|
|
|
|
nfds = cin;
|
2012-03-07 20:55:27 -07:00
|
|
|
|
2012-03-07 22:16:02 -07:00
|
|
|
if (content_length) {
|
2012-03-07 20:55:27 -07:00
|
|
|
/* have post data */
|
2012-03-07 22:16:02 -07:00
|
|
|
FD_SET(cout, &wfds);
|
|
|
|
if (cout > nfds) {
|
|
|
|
nfds = cout;
|
2012-03-07 20:55:27 -07:00
|
|
|
}
|
2012-03-07 22:16:02 -07:00
|
|
|
} else if (cout >= 0) {
|
|
|
|
close(cout); /* no post data */
|
|
|
|
cout = -1;
|
2012-03-07 20:55:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (-1 == select(nfds+1, &rfds, &wfds, NULL, NULL)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-03-07 22:16:02 -07:00
|
|
|
if (FD_ISSET(cin, &rfds)) {
|
2012-03-07 20:55:27 -07:00
|
|
|
if (passthru) {
|
2012-03-07 22:16:02 -07:00
|
|
|
/* Pass everything through verbatim */
|
2012-03-07 20:55:27 -07:00
|
|
|
size_t len;
|
|
|
|
|
|
|
|
/* Re-use this big buffer */
|
|
|
|
len = fread(cgiheader, 1, sizeof cgiheader, cinf);
|
|
|
|
if (0 == len) {
|
|
|
|
/* CGI is done */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fwrite(cgiheader, 1, len, stdout);
|
|
|
|
size += len;
|
|
|
|
} else {
|
2012-03-07 22:16:02 -07:00
|
|
|
/* Interpret header fields */
|
|
|
|
size_t readlen = (sizeof cgiheader) - cgiheaderlen;
|
2012-03-07 20:55:27 -07:00
|
|
|
|
2012-03-07 22:16:02 -07:00
|
|
|
if (NULL == fgets(cgiheader + cgiheaderlen, readlen, cinf)) {
|
2012-03-07 20:55:27 -07:00
|
|
|
/* EOF or error */
|
2012-03-07 22:16:02 -07:00
|
|
|
badrequest(500, "CGI Error", "CGI output too weird");
|
|
|
|
}
|
|
|
|
cgiheaderlen = strlen(cgiheader);
|
|
|
|
|
|
|
|
if ('\n' == cgiheader[cgiheaderlen - 1]) {
|
|
|
|
/* We read a whole line */
|
|
|
|
size_t len;
|
|
|
|
char *val;
|
|
|
|
|
|
|
|
len = extract_header_field(cgiheader, &val, 0);
|
|
|
|
if (! len) {
|
|
|
|
/* We've read the entire header block */
|
|
|
|
passthru = 1;
|
|
|
|
eoh();
|
|
|
|
} else {
|
|
|
|
if (! header_sent) {
|
|
|
|
if (! strcasecmp(cgiheader, "Location")) {
|
|
|
|
header(302, "CGI Redirect");
|
|
|
|
fwrite(cgiheader, 1, cgiheaderlen, stdout);
|
|
|
|
dolog(302, 0);
|
|
|
|
exit(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
header(200, "OK");
|
|
|
|
printf("Pragma: no-cache\r\n");
|
|
|
|
|
|
|
|
header_sent = 1;
|
|
|
|
}
|
|
|
|
printf("%s: %s\r\n", cgiheader, val);
|
|
|
|
cgiheaderlen = 0;
|
2012-03-07 20:55:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-07 22:16:02 -07:00
|
|
|
} else if (FD_ISSET(cout, &wfds)) {
|
2012-03-07 20:55:27 -07:00
|
|
|
/*
|
|
|
|
* write to cgi the post data
|
|
|
|
*/
|
2012-03-07 22:16:02 -07:00
|
|
|
if (content_length) {
|
2012-03-07 20:55:27 -07:00
|
|
|
size_t len;
|
|
|
|
char buf[BUFFER_SIZE];
|
2012-03-07 22:16:02 -07:00
|
|
|
size_t nmemb = min(BUFFER_SIZE, content_length);
|
2012-03-07 20:55:27 -07:00
|
|
|
|
|
|
|
len = fread(buf, 1, nmemb, stdin);
|
|
|
|
if (len < 1) {
|
|
|
|
break;
|
|
|
|
}
|
2012-03-07 22:16:02 -07:00
|
|
|
content_length -= len;
|
|
|
|
write(cout, buf, len);
|
2012-03-07 20:55:27 -07:00
|
|
|
} else {
|
2012-03-07 22:16:02 -07:00
|
|
|
close(cout);
|
2012-03-07 20:55:27 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fflush(stdout);
|
2012-03-07 22:16:02 -07:00
|
|
|
dolog(200, size);
|
2012-03-07 20:55:27 -07:00
|
|
|
cork(0);
|
|
|
|
}
|
2012-03-07 22:16:02 -07:00
|
|
|
|
2012-03-07 20:55:27 -07:00
|
|
|
void
|
|
|
|
serve_cgi(char *relpath)
|
|
|
|
{
|
|
|
|
int pid;
|
|
|
|
int cin[2];
|
|
|
|
int cout[2];
|
|
|
|
|
|
|
|
if (pipe(cin) || pipe(cout)) {
|
|
|
|
badrequest(500, "Internal Server Error", "Server Resource problem.");
|
|
|
|
}
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
if (-1 == pid) {
|
|
|
|
badrequest(500, "Internal Server Error", "Unable to fork.");
|
|
|
|
}
|
|
|
|
if (pid) {
|
|
|
|
close(cin[1]);
|
|
|
|
close(cout[0]);
|
|
|
|
|
2012-03-07 22:16:02 -07:00
|
|
|
/* Eris is not this smart yet */
|
|
|
|
keepalive = 0;
|
|
|
|
|
|
|
|
alarm(CGI_TIMEOUT);
|
|
|
|
cgi_parent(cin[0], cout[1], 0);
|
2012-03-07 20:55:27 -07:00
|
|
|
alarm(0);
|
2012-03-07 22:16:02 -07:00
|
|
|
|
|
|
|
exit(0);
|
2012-03-07 20:55:27 -07:00
|
|
|
} else {
|
|
|
|
close(cwd);
|
|
|
|
close(cout[1]);
|
|
|
|
close(cin[0]);
|
|
|
|
|
|
|
|
dup2(cout[0], 0);
|
|
|
|
dup2(cin[1], 1);
|
|
|
|
|
|
|
|
close(cout[0]);
|
|
|
|
close(cin[1]);
|
|
|
|
|
|
|
|
cgi_child(relpath);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|