X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=blobdiff_plain;f=src%2Fcallcgi.c;h=3a28880b41ad03b99a4000dcf78e2ecdda9ed1f2;hp=72f814a828729f06bf6af15ace8923b719fb3c61;hb=18838a2eddc3ae7fdc8f3fefb8cd83c012328a5e;hpb=df96b2220cf1f738fdfc26236df1e91d5c89e078 diff --git a/src/callcgi.c b/src/callcgi.c index 72f814a..3a28880 100644 --- a/src/callcgi.c +++ b/src/callcgi.c @@ -24,12 +24,14 @@ #include #include #include +#include #ifdef HAVE_CONFIG_H #include #endif #include #include +#include static char **environ; @@ -53,7 +55,7 @@ static int passdata(FILE *in, FILE *out) } } if(ret > 0) { - if(pfds[0].revents & POLLIN) { + if(pfds[0].revents & (POLLIN | POLLERR | POLLHUP)) { ret = fread(buf, 1, 65536, in); if(ferror(in)) { flog(LOG_ERR, "callcgi: could not read input: %s", strerror(errno)); @@ -84,10 +86,10 @@ static char *absolutify(char *file) static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *url, char *rest, int *infd, int *outfd) { - int i; char *qp, **env, *name; int inp[2], outp[2]; pid_t pid; + char *pi; pipe(inp); pipe(outp); @@ -96,12 +98,12 @@ static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *u exit(1); } if(pid == 0) { - close(inp[1]); - close(outp[0]); dup2(inp[0], 0); dup2(outp[1], 1); - for(i = 3; i < FD_SETSIZE; i++) - close(i); + close(inp[0]); + close(inp[1]); + close(outp[0]); + close(outp[1]); if((qp = strchr(url, '?')) != NULL) *(qp++) = 0; putenv(sprintf2("SERVER_SOFTWARE=ashd/%s", VERSION)); @@ -109,7 +111,6 @@ static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *u if(getenv("HTTP_VERSION")) putenv(sprintf2("SERVER_PROTOCOL=%s", getenv("HTTP_VERSION"))); putenv(sprintf2("REQUEST_METHOD=%s", method)); - putenv(sprintf2("PATH_INFO=%s", rest)); name = url; /* XXX: This is an ugly hack (I think), but though I can think * of several alternatives, none seem to be better. */ @@ -117,6 +118,29 @@ static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *u !strcmp(rest, url + strlen(url) - strlen(rest))) { name = sprintf2("%.*s", (int)(strlen(url) - strlen(rest)), url); } + if((pi = unquoteurl(rest)) == NULL) + pi = rest; + if(!strcmp(name, "/")) { + /* + * Normal CGI behavior appears to be to always let + * PATH_INFO begin with a slash and never let SCRIPT_NAME + * end with one. That conflicts, however, with some + * behaviors, such as "mounting" CGI applications on a + * directory element of the URI space -- a handler + * responding to "/foo/" would not be able to tell that it + * is not called "/foo", which makes a large difference, + * not least in relation to URI reconstruction and + * redirections. A common practical case is CGI-handled + * index files in directories. Therefore, this only + * handles the nonconditional case of the root directory + * and leaves other decisions to the previous handler + * handing over the request to callcgi. It is unclear if + * there is a better way to handle the problem. + */ + name[0] = 0; + pi = sprintf2("/%s", pi); + } + putenv(sprintf2("PATH_INFO=%s", pi)); putenv(sprintf2("SCRIPT_NAME=%s", name)); putenv(sprintf2("QUERY_STRING=%s", qp?qp:"")); if(getenv("REQ_HOST")) @@ -127,6 +151,8 @@ static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *u putenv("HTTPS=on"); if(getenv("REQ_X_ASH_ADDRESS")) putenv(sprintf2("REMOTE_ADDR=%s", getenv("REQ_X_ASH_ADDRESS"))); + if(getenv("REQ_X_ASH_REMOTE_USER")) + putenv(sprintf2("REMOTE_USER=%s", getenv("REQ_X_ASH_REMOTE_USER"))); if(getenv("REQ_CONTENT_TYPE")) putenv(sprintf2("CONTENT_TYPE=%s", getenv("REQ_CONTENT_TYPE"))); if(getenv("REQ_CONTENT_LENGTH")) @@ -162,7 +188,7 @@ static void trim(struct charbuf *buf) for(p = buf->b + buf->d - 1; (p > buf->b) && isspace(*p); p--, buf->d--); } -static char **parseheaders(FILE *s) +static char **parsecgiheaders(FILE *s) { int c, state; struct charvbuf hbuf; @@ -317,6 +343,7 @@ int main(int argc, char **argv, char **envp) FILE *in, *out; char **headers; pid_t child; + int estat; environ = envp; signal(SIGPIPE, SIG_IGN); @@ -369,7 +396,7 @@ int main(int argc, char **argv, char **envp) passdata(stdin, in); /* Ignore errors, perhaps? */ fclose(in); out = fdopen(outfd, "r"); - if((headers = parseheaders(out)) == NULL) { + if((headers = parsecgiheaders(out)) == NULL) { flog(LOG_WARNING, "CGI handler returned invalid headers"); exit(1); } @@ -378,5 +405,14 @@ int main(int argc, char **argv, char **envp) printf("\n"); if(passdata(out, stdout)) kill(child, SIGINT); - return(0); + if(waitpid(child, &estat, 0) == child) { + if(WCOREDUMP(estat)) + flog(LOG_WARNING, "CGI handler `%s' dumped core", prog); + if(WIFEXITED(estat) && !WEXITSTATUS(estat)) + return(0); + else + return(1); + } + flog(LOG_WARNING, "could not wait for CGI handler: %s", strerror(errno)); + return(1); }