#include <ctype.h>
#include <signal.h>
#include <sys/poll.h>
+#include <sys/wait.h>
#ifdef HAVE_CONFIG_H
#include <config.h>
return(1);
}
if(fwrite(buf, 1, ret, out) != ret) {
- flog(LOG_ERR, "callcgi: could not write output: %s", strerror(errno));
+ if(errno != EPIPE)
+ flog(LOG_ERR, "callcgi: could not write output: %s", strerror(errno));
return(1);
}
}
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 *unqr;
+ char *pi;
pipe(inp);
pipe(outp);
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));
if(getenv("HTTP_VERSION"))
putenv(sprintf2("SERVER_PROTOCOL=%s", getenv("HTTP_VERSION")));
putenv(sprintf2("REQUEST_METHOD=%s", method));
- unqr = unquoteurl(rest);
- putenv(sprintf2("PATH_INFO=%s", unqr?unqr:rest));
name = url;
/* XXX: This is an ugly hack (I think), but though I can think
* of several alternatives, none seem to be better. */
!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"))
putenv(sprintf2("SERVER_NAME=%s", getenv("REQ_HOST")));
+ if(getenv("REQ_X_ASH_SERVER_ADDRESS"))
+ putenv(sprintf2("SERVER_ADDR=%s", getenv("REQ_X_ASH_SERVER_ADDRESS")));
if(getenv("REQ_X_ASH_SERVER_PORT"))
putenv(sprintf2("SERVER_PORT=%s", getenv("REQ_X_ASH_SERVER_PORT")));
if(getenv("REQ_X_ASH_PROTOCOL") && !strcmp(getenv("REQ_X_ASH_PROTOCOL"), "https"))
putenv("HTTPS=on");
if(getenv("REQ_X_ASH_ADDRESS"))
putenv(sprintf2("REMOTE_ADDR=%s", getenv("REQ_X_ASH_ADDRESS")));
+ if(getenv("REQ_X_ASH_PORT"))
+ putenv(sprintf2("REMOTE_PORT=%s", getenv("REQ_X_ASH_PORT")));
if(getenv("REQ_X_ASH_REMOTE_USER"))
putenv(sprintf2("REMOTE_USER=%s", getenv("REQ_X_ASH_REMOTE_USER")));
if(getenv("REQ_CONTENT_TYPE"))
FILE *in, *out;
char **headers;
pid_t child;
+ int estat;
environ = envp;
signal(SIGPIPE, SIG_IGN);
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);
}