mirror of https://github.com/nealey/eris.git
POST working: passing regression tests now
This commit is contained in:
parent
03d532240a
commit
4536afe4a6
205
eris.c
205
eris.c
|
@ -448,133 +448,146 @@ start_cgi(int nph, const char *pathinfo, const char *const *envp)
|
||||||
int pid;
|
int pid;
|
||||||
char cgiheader[BUFFER_SIZE];
|
char cgiheader[BUFFER_SIZE];
|
||||||
size_t cgiheaderlen = BUFFER_SIZE;
|
size_t cgiheaderlen = BUFFER_SIZE;
|
||||||
int fd[2],
|
int cin[2];
|
||||||
df[2];
|
int cout[2];
|
||||||
FILE *cin;
|
FILE *cinf;
|
||||||
|
|
||||||
if (pipe(fd) || pipe(df) || !(cin = fdopen(fd[0], "r"))) {
|
if (pipe(cin) || pipe(cout) || !(cinf = fdopen(cin[0], "rb"))) {
|
||||||
badrequest(500, "Internal Server Error",
|
badrequest(500, "Internal Server Error",
|
||||||
"Server Resource problem.");
|
"Server Resource problem.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pid = fork())) {
|
pid = fork();
|
||||||
if (pid > 0) {
|
if (-1 == pid) {
|
||||||
|
badrequest(500, "Internal Server Error",
|
||||||
|
"Unable to fork.");
|
||||||
|
}
|
||||||
|
if (pid) {
|
||||||
|
/* Parent */
|
||||||
|
int passthru = nph;
|
||||||
|
|
||||||
|
fcntl(cin[0], F_SETFL, O_NONBLOCK);
|
||||||
|
signal(SIGCHLD, cgi_child);
|
||||||
|
signal(SIGPIPE, SIG_IGN); /* NO! no signal! */
|
||||||
|
|
||||||
|
close(cin[1]);
|
||||||
|
close(cout[0]);
|
||||||
|
|
||||||
|
alarm(CGI_TIMEOUT);
|
||||||
|
|
||||||
|
while (1) {
|
||||||
int nfds;
|
int nfds;
|
||||||
fd_set rfds, wfds;
|
fd_set rfds, wfds;
|
||||||
int passthru = nph;
|
|
||||||
|
|
||||||
fcntl(fd[0], F_SETFL, O_NONBLOCK);
|
|
||||||
signal(SIGCHLD, cgi_child);
|
|
||||||
signal(SIGPIPE, SIG_IGN); /* NO! no signal! */
|
|
||||||
|
|
||||||
close(df[0]);
|
|
||||||
close(fd[1]);
|
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
FD_ZERO(&rfds);
|
||||||
FD_ZERO(&wfds);
|
FD_ZERO(&wfds);
|
||||||
FD_SET(fd[0], &rfds);
|
FD_SET(cin[0], &rfds);
|
||||||
nfds = fd[0];
|
nfds = cin[0];
|
||||||
|
|
||||||
if (post_len) {
|
if (post_len) {
|
||||||
/* have post data */
|
/* have post data */
|
||||||
FD_SET(df[0], &wfds);
|
FD_SET(cout[1], &wfds);
|
||||||
if (df[0] > nfds) {
|
if (cout[1] > nfds) {
|
||||||
nfds = df[0];
|
nfds = cout[1];
|
||||||
}
|
}
|
||||||
} else if (df[1] >= 0) {
|
} else if (cout[1] >= 0) {
|
||||||
close(df[1]); /* no post data */
|
close(cout[1]); /* no post data */
|
||||||
df[1] = -1;
|
cout[1] = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (select(nfds+1, &rfds, &wfds, NULL, NULL) != -1) {
|
if (-1 == select(nfds+1, &rfds, &wfds, NULL, NULL)) {
|
||||||
if (FD_ISSET(fd[0], &rfds)) {
|
break;
|
||||||
if (passthru) {
|
}
|
||||||
size_t len;
|
|
||||||
|
|
||||||
/* Re-use this big buffer */
|
if (FD_ISSET(cin[0], &rfds)) {
|
||||||
len = fread(cgiheader, 1, sizeof cgiheader, cin);
|
if (passthru) {
|
||||||
if (0 == len) {
|
size_t len;
|
||||||
/* CGI is done */
|
|
||||||
break;
|
/* Re-use this big buffer */
|
||||||
}
|
len = fread(cgiheader, 1, sizeof cgiheader, cinf);
|
||||||
fwrite(cgiheader, 1, len, stdout);
|
if (0 == len) {
|
||||||
size += len;
|
/* CGI is done */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fwrite(cgiheader, 1, len, stdout);
|
||||||
|
size += len;
|
||||||
|
} else {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = read_header(cinf, cgiheader, &cgiheaderlen);
|
||||||
|
if (0 == ret) {
|
||||||
|
/* Call read_header again */
|
||||||
|
} else if (-1 == ret) {
|
||||||
|
/* EOF or error */
|
||||||
|
badrequest(500, "CGI Error",
|
||||||
|
"CGI output too weird");
|
||||||
} else {
|
} else {
|
||||||
int ret;
|
/* Entire header is in memory now */
|
||||||
|
passthru = 1;
|
||||||
|
|
||||||
ret = read_header(cin, cgiheader, &cgiheaderlen);
|
/* XXX: I think we need to look for Location:
|
||||||
if (0 == ret) {
|
* anywhere, but fnord got away with checking
|
||||||
/* Call read_header again */
|
* only the first header field, so I will too.
|
||||||
} else if (-1 == ret) {
|
*/
|
||||||
/* EOF or error */
|
if (memcmp(cgiheader, "Location: ", 10) == 0) {
|
||||||
badrequest(500, "CGI Error",
|
retcode = 302;
|
||||||
"CGI output too weird");
|
printf
|
||||||
} else {
|
("HTTP/1.0 302 CGI-Redirect\r\nConnection: close\r\n");
|
||||||
/* 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;
|
|
||||||
printf("HTTP/1.0 200 OK\r\nServer: "
|
|
||||||
FNORD
|
|
||||||
"\r\nPragma: no-cache\r\nConnection: close\r\n");
|
|
||||||
signal(SIGCHLD, SIG_IGN);
|
|
||||||
fwrite(cgiheader, 1, cgiheaderlen, stdout);
|
fwrite(cgiheader, 1, cgiheaderlen, stdout);
|
||||||
|
dolog(0);
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (FD_ISSET(df[1], &wfds)) {
|
|
||||||
/*
|
|
||||||
* write to cgi the post data
|
|
||||||
*/
|
|
||||||
if (post_len) {
|
|
||||||
size_t len;
|
|
||||||
char buf[BUFFER_SIZE];
|
|
||||||
size_t nmemb = min(BUFFER_SIZE, post_len);
|
|
||||||
|
|
||||||
len = fread(buf, 1, nmemb, stdin);
|
retcode = 200;
|
||||||
if (len < 1) {
|
printf("HTTP/1.0 200 OK\r\nServer: "
|
||||||
break;
|
FNORD
|
||||||
}
|
"\r\nPragma: no-cache\r\nConnection: close\r\n");
|
||||||
post_len -= len;
|
signal(SIGCHLD, SIG_IGN);
|
||||||
write(df[1], buf, len);
|
fwrite(cgiheader, 1, cgiheaderlen, stdout);
|
||||||
} else {
|
|
||||||
close(df[1]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (FD_ISSET(cout[1], &wfds)) {
|
||||||
|
/*
|
||||||
|
* write to cgi the post data
|
||||||
|
*/
|
||||||
|
if (post_len) {
|
||||||
|
size_t len;
|
||||||
|
char buf[BUFFER_SIZE];
|
||||||
|
size_t nmemb = min(BUFFER_SIZE, post_len);
|
||||||
|
|
||||||
fflush(stdout);
|
len = fread(buf, 1, nmemb, stdin);
|
||||||
dolog(size);
|
if (len < 1) {
|
||||||
#ifdef TCP_CORK
|
break;
|
||||||
{
|
}
|
||||||
int zero = 0;
|
post_len -= len;
|
||||||
setsockopt(1, IPPROTO_TCP, TCP_CORK, &zero, sizeof(zero));
|
write(cout[1], buf, len);
|
||||||
|
} else {
|
||||||
|
close(cout[1]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
alarm(0);
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
dolog(size);
|
||||||
|
#ifdef TCP_CORK
|
||||||
|
{
|
||||||
|
int zero = 0;
|
||||||
|
setsockopt(1, IPPROTO_TCP, TCP_CORK, &zero, sizeof(zero));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
close(df[1]);
|
/* Child */
|
||||||
close(fd[0]);
|
|
||||||
|
|
||||||
dup2(df[0], 0);
|
close(cout[1]);
|
||||||
dup2(fd[1], 1);
|
close(cin[0]);
|
||||||
|
|
||||||
close(df[0]);
|
dup2(cout[0], 0);
|
||||||
close(fd[1]);
|
dup2(cin[1], 1);
|
||||||
|
|
||||||
|
close(cout[0]);
|
||||||
|
close(cin[1]);
|
||||||
|
|
||||||
alarm(CGI_TIMEOUT);
|
|
||||||
do_cgi(pathinfo, envp);
|
do_cgi(pathinfo, envp);
|
||||||
}
|
}
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|
|
@ -70,6 +70,7 @@ class BasicTests(LinesTests):
|
||||||
so, se = self.p.communicate(h.encode('utf-8'))
|
so, se = self.p.communicate(h.encode('utf-8'))
|
||||||
return (so, se)
|
return (so, se)
|
||||||
|
|
||||||
|
|
||||||
class DirTests(BasicTests):
|
class DirTests(BasicTests):
|
||||||
args = ['-d']
|
args = ['-d']
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ class CGITests(BasicTests):
|
||||||
|
|
||||||
def testPost(self):
|
def testPost(self):
|
||||||
so, se = self.post('/cgi/set.cgi', 'default', 'a=1&b=2&c=3')
|
so, se = self.post('/cgi/set.cgi', 'default', 'a=1&b=2&c=3')
|
||||||
self.assertLinesEqual(se, b'10.1.2.3 200 330 default (null) (null) /cgi/set.cgi\n')
|
self.assertLinesEqual(se, b'10.1.2.3 200 306 default (null) (null) /cgi/set.cgi\n')
|
||||||
self.assertLinesEqual(so, b'HTTP/1.0 200 OK\r\nServer: eris/2.0\r\nPragma: no-cache\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\nGATEWAY_INTERFACE:CGI/1.1\nSERVER_PROTOCOL:HTTP/1.0\nSERVER_SOFTWARE:eris/2.0\nSERVER_NAME:default\nSERVER_PORT:80\nREQUEST_METHOD:POST\nREQUEST_URI:/cgi/set.cgi\nSCRIPT_NAME:/cgi/set.cgi\nREMOTE_ADDR:10.1.2.3\nREMOTE_PORT:5858\nCONTENT_TYPE:application/x-www-form-urlencoded\nCONTENT_LENGTH:11\nForm data: a=1&b=2&c=3')
|
self.assertLinesEqual(so, b'HTTP/1.0 200 OK\r\nServer: eris/2.0\r\nPragma: no-cache\r\nConnection: close\r\nContent-Type: text/plain\r\n\r\nGATEWAY_INTERFACE:CGI/1.1\nSERVER_PROTOCOL:HTTP/1.0\nSERVER_SOFTWARE:eris/2.0\nSERVER_NAME:default\nSERVER_PORT:80\nREQUEST_METHOD:POST\nREQUEST_URI:/cgi/set.cgi\nSCRIPT_NAME:/cgi/set.cgi\nREMOTE_ADDR:10.1.2.3\nREMOTE_PORT:5858\nCONTENT_TYPE:application/x-www-form-urlencoded\nCONTENT_LENGTH:11\nForm data: a=1&b=2&c=3')
|
||||||
|
|
||||||
# XXX: Test posting to static html with keepalive
|
# XXX: Test posting to static html with keepalive
|
||||||
|
|
Loading…
Reference in New Issue