mirror of https://github.com/nealey/eris.git
CGI passing some tests
This commit is contained in:
parent
c5550f134b
commit
ba030d7917
126
cgi.c
126
cgi.c
|
@ -15,12 +15,12 @@ cgi_child(const char *relpath)
|
||||||
setenv("REMOTE_ADDR", remote_ip, 1);
|
setenv("REMOTE_ADDR", remote_ip, 1);
|
||||||
setenv("REMOTE_PORT", remote_port, 1);
|
setenv("REMOTE_PORT", remote_port, 1);
|
||||||
setenv("REMOTE_IDENT", remote_ident, 1);
|
setenv("REMOTE_IDENT", remote_ident, 1);
|
||||||
setenv("CONTENT_TYPE", content_type, 1);
|
if (content_length) {
|
||||||
{
|
|
||||||
char cl[20];
|
char cl[20];
|
||||||
|
|
||||||
snprintf(cl, sizeof cl, "%llu", (unsigned long long) content_length);
|
snprintf(cl, sizeof cl, "%llu", (unsigned long long) content_length);
|
||||||
setenv("CONTENT_LENGTH", cl, 1);
|
setenv("CONTENT_LENGTH", cl, 1);
|
||||||
|
setenv("CONTENT_TYPE", content_type, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
execl(relpath, relpath, NULL);
|
execl(relpath, relpath, NULL);
|
||||||
|
@ -28,44 +28,45 @@ cgi_child(const char *relpath)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
cgi_parent(int cin, int cout)
|
cgi_parent(int cin, int cout, int passthru)
|
||||||
{
|
{
|
||||||
|
char cgiheader[BUFFER_SIZE];
|
||||||
|
size_t cgiheaderlen = 0;
|
||||||
FILE *cinf = fdopen(cin, "rb");
|
FILE *cinf = fdopen(cin, "rb");
|
||||||
int passthru = nph;
|
size_t size = 0;
|
||||||
|
int header_sent = 0;
|
||||||
|
|
||||||
fcntl(child_in, F_SETFL, O_NONBLOCK);
|
fcntl(cin, F_SETFL, O_NONBLOCK);
|
||||||
signal(SIGCHLD, sigchld);
|
signal(SIGCHLD, sigchld);
|
||||||
signal(SIGPIPE, SIG_IGN); /* NO! no signal! */
|
signal(SIGPIPE, SIG_IGN); /* NO! no signal! */
|
||||||
|
|
||||||
/* Eris is not this smart yet */
|
|
||||||
keepalive = 0;
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
int nfds;
|
int nfds;
|
||||||
fd_set rfds, wfds;
|
fd_set rfds, wfds;
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_ZERO(&wfds);
|
FD_ZERO(&wfds);
|
||||||
FD_SET(cin[0], &rfds);
|
FD_SET(cin, &rfds);
|
||||||
nfds = cin[0];
|
nfds = cin;
|
||||||
|
|
||||||
if (post_len) {
|
if (content_length) {
|
||||||
/* have post data */
|
/* have post data */
|
||||||
FD_SET(cout[1], &wfds);
|
FD_SET(cout, &wfds);
|
||||||
if (cout[1] > nfds) {
|
if (cout > nfds) {
|
||||||
nfds = cout[1];
|
nfds = cout;
|
||||||
}
|
}
|
||||||
} else if (cout[1] >= 0) {
|
} else if (cout >= 0) {
|
||||||
close(cout[1]); /* no post data */
|
close(cout); /* no post data */
|
||||||
cout[1] = -1;
|
cout = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 == select(nfds+1, &rfds, &wfds, NULL, NULL)) {
|
if (-1 == select(nfds+1, &rfds, &wfds, NULL, NULL)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (FD_ISSET(cin[0], &rfds)) {
|
if (FD_ISSET(cin, &rfds)) {
|
||||||
if (passthru) {
|
if (passthru) {
|
||||||
|
/* Pass everything through verbatim */
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
/* Re-use this big buffer */
|
/* Re-use this big buffer */
|
||||||
|
@ -77,72 +78,74 @@ cgi_parent(int cin, int cout)
|
||||||
fwrite(cgiheader, 1, len, stdout);
|
fwrite(cgiheader, 1, len, stdout);
|
||||||
size += len;
|
size += len;
|
||||||
} else {
|
} else {
|
||||||
int ret;
|
/* Interpret header fields */
|
||||||
|
size_t readlen = (sizeof cgiheader) - cgiheaderlen;
|
||||||
|
|
||||||
ret = read_header(cinf, cgiheader, &cgiheaderlen);
|
if (NULL == fgets(cgiheader + cgiheaderlen, readlen, cinf)) {
|
||||||
if (0 == ret) {
|
|
||||||
/* Call read_header again */
|
|
||||||
} else if (-1 == ret) {
|
|
||||||
/* EOF or error */
|
/* EOF or error */
|
||||||
badrequest(500, "CGI Error",
|
badrequest(500, "CGI Error", "CGI output too weird");
|
||||||
"CGI output too weird");
|
}
|
||||||
} else {
|
cgiheaderlen = strlen(cgiheader);
|
||||||
/* Entire header is in memory now */
|
|
||||||
passthru = 1;
|
|
||||||
|
|
||||||
/* XXX: I think we need to look for Location:
|
|
||||||
* anywhere, but fnord got away with checking
|
|
||||||
* only the first header field, so I will too.
|
|
||||||
*/
|
|
||||||
if (memcmp(cgiheader, "Location: ", 10) == 0) {
|
|
||||||
retcode = 302;
|
|
||||||
printf
|
|
||||||
("HTTP/1.0 302 CGI-Redirect\r\nConnection: close\r\n");
|
|
||||||
fwrite(cgiheader, 1, cgiheaderlen, stdout);
|
|
||||||
dolog(0);
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
retcode = 200;
|
if ('\n' == cgiheader[cgiheaderlen - 1]) {
|
||||||
printf("HTTP/1.0 200 OK\r\nServer: "
|
/* We read a whole line */
|
||||||
FNORD
|
size_t len;
|
||||||
"\r\nPragma: no-cache\r\nConnection: close\r\n");
|
char *val;
|
||||||
signal(SIGCHLD, SIG_IGN);
|
|
||||||
fwrite(cgiheader, 1, cgiheaderlen, stdout);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (FD_ISSET(cout[1], &wfds)) {
|
} else if (FD_ISSET(cout, &wfds)) {
|
||||||
/*
|
/*
|
||||||
* write to cgi the post data
|
* write to cgi the post data
|
||||||
*/
|
*/
|
||||||
if (post_len) {
|
if (content_length) {
|
||||||
size_t len;
|
size_t len;
|
||||||
char buf[BUFFER_SIZE];
|
char buf[BUFFER_SIZE];
|
||||||
size_t nmemb = min(BUFFER_SIZE, post_len);
|
size_t nmemb = min(BUFFER_SIZE, content_length);
|
||||||
|
|
||||||
len = fread(buf, 1, nmemb, stdin);
|
len = fread(buf, 1, nmemb, stdin);
|
||||||
if (len < 1) {
|
if (len < 1) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
post_len -= len;
|
content_length -= len;
|
||||||
write(cout[1], buf, len);
|
write(cout, buf, len);
|
||||||
} else {
|
} else {
|
||||||
close(cout[1]);
|
close(cout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alarm(0);
|
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
dolog(size);
|
dolog(200, size);
|
||||||
cork(0);
|
cork(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
serve_cgi(char *relpath)
|
serve_cgi(char *relpath)
|
||||||
{
|
{
|
||||||
size_t size = 0;
|
|
||||||
int pid;
|
int pid;
|
||||||
char buf[BUFFER_SIZE];
|
|
||||||
int cin[2];
|
int cin[2];
|
||||||
int cout[2];
|
int cout[2];
|
||||||
|
|
||||||
|
@ -158,9 +161,14 @@ serve_cgi(char *relpath)
|
||||||
close(cin[1]);
|
close(cin[1]);
|
||||||
close(cout[0]);
|
close(cout[0]);
|
||||||
|
|
||||||
alarm(CHILD_TIMEOUT);
|
/* Eris is not this smart yet */
|
||||||
cgi_parent(cin[0], cout[1]);
|
keepalive = 0;
|
||||||
|
|
||||||
|
alarm(CGI_TIMEOUT);
|
||||||
|
cgi_parent(cin[0], cout[1], 0);
|
||||||
alarm(0);
|
alarm(0);
|
||||||
|
|
||||||
|
exit(0);
|
||||||
} else {
|
} else {
|
||||||
close(cwd);
|
close(cwd);
|
||||||
close(cout[1]);
|
close(cout[1]);
|
||||||
|
|
9
eris.c
9
eris.c
|
@ -102,7 +102,6 @@ char stdout_buf[BUFFER_SIZE];
|
||||||
#include "strings.c"
|
#include "strings.c"
|
||||||
#include "mime.c"
|
#include "mime.c"
|
||||||
#include "time.c"
|
#include "time.c"
|
||||||
#include "cgi.c"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* TCP_CORK is a Linux extension to work around a TCP problem.
|
* TCP_CORK is a Linux extension to work around a TCP problem.
|
||||||
|
@ -173,6 +172,8 @@ badrequest(long code, const char *httpcomment, const char *message)
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#include "cgi.c"
|
||||||
|
|
||||||
void
|
void
|
||||||
not_found()
|
not_found()
|
||||||
{
|
{
|
||||||
|
@ -408,12 +409,6 @@ serve_idx(int fd, char *path)
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
|
||||||
serve_cgi(char *path)
|
|
||||||
{
|
|
||||||
DUMP_s(path);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
void
|
||||||
find_serve_file(char *relpath)
|
find_serve_file(char *relpath)
|
||||||
{
|
{
|
||||||
|
|
2
test.sh
2
test.sh
|
@ -124,7 +124,7 @@ printf 'GET /empty/ HTTP/1.0\r\n\r\n' | $HTTPD_IDX 2>/dev/null | d | grep -Fq '<
|
||||||
H "CGI"
|
H "CGI"
|
||||||
|
|
||||||
title "Basic CGI"
|
title "Basic CGI"
|
||||||
printf 'GET /a.cgi HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | d | grep -q 'HTTP/1.0 200 OK#%Server: .*#%Pragma: no-cache#%Connection: close#%Content-type: text/plain#%#%james%' && pass || fail
|
printf 'GET /a.cgi HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | d | grep -q 'HTTP/1.0 200 OK#%Server: .*#%Connection: close#%Pragma: no-cache#%Content-type: text/plain#%#%james%' && pass || fail
|
||||||
|
|
||||||
title "GET with arguments"
|
title "GET with arguments"
|
||||||
printf 'GET /a.cgi?foo HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | d | grep -q 'HTTP/1.0 200 OK#%Server: .*#%Pragma: no-cache#%Connection: close#%Content-type: text/plain#%#%foo%' && pass || fail
|
printf 'GET /a.cgi?foo HTTP/1.0\r\n\r\n' | $HTTPD_CGI 2>/dev/null | d | grep -q 'HTTP/1.0 200 OK#%Server: .*#%Pragma: no-cache#%Connection: close#%Content-type: text/plain#%#%foo%' && pass || fail
|
||||||
|
|
Loading…
Reference in New Issue