/* Mostly copied from callcgi. */ static void mkcgienv(struct hthead *req, struct charbuf *dst) { int i; char *url, *pi, *tmp, *qp, *h, *p; bufaddenv(dst, "SERVER_SOFTWARE", "ashd/%s", VERSION); bufaddenv(dst, "GATEWAY_INTERFACE", "CGI/1.1"); bufaddenv(dst, "SERVER_PROTOCOL", "%s", req->ver); bufaddenv(dst, "REQUEST_METHOD", "%s", req->method); bufaddenv(dst, "REQUEST_URI", "%s", req->url); url = sstrdup(req->url); if((qp = strchr(url, '?')) != NULL) *(qp++) = 0; /* XXX: This is an ugly hack (I think), but though I can think of * several alternatives, none seem to be better. */ if(*req->rest && (strlen(url) >= strlen(req->rest)) && !strcmp(req->rest, url + strlen(url) - strlen(req->rest))) { url[strlen(url) - strlen(req->rest)] = 0; } if((pi = unquoteurl(req->rest)) == NULL) pi = sstrdup(req->rest); if(!strcmp(url, "/")) { /* This seems to be normal CGI behavior, but see callcgi.c for * details. */ url[0] = 0; pi = sprintf2("/%s", tmp = pi); free(tmp); } bufaddenv(dst, "PATH_INFO", "%s", pi); bufaddenv(dst, "SCRIPT_NAME", "%s", url); bufaddenv(dst, "QUERY_STRING", "%s", qp?qp:""); free(pi); free(url); if((h = getheader(req, "Host")) != NULL) bufaddenv(dst, "SERVER_NAME", "%s", h); if((h = getheader(req, "X-Ash-Server-Address")) != NULL) bufaddenv(dst, "SERVER_ADDR", "%s", h); if((h = getheader(req, "X-Ash-Server-Port")) != NULL) bufaddenv(dst, "SERVER_PORT", "%s", h); if((h = getheader(req, "X-Ash-Remote-User")) != NULL) bufaddenv(dst, "REMOTE_USER", "%s", h); if(((h = getheader(req, "X-Ash-Protocol")) != NULL) && !strcmp(h, "https")) bufaddenv(dst, "HTTPS", "on"); if((h = getheader(req, "X-Ash-Address")) != NULL) bufaddenv(dst, "REMOTE_ADDR", "%s", h); if((h = getheader(req, "X-Ash-Port")) != NULL) bufaddenv(dst, "REMOTE_PORT", "%s", h); if((h = getheader(req, "Content-Type")) != NULL) bufaddenv(dst, "CONTENT_TYPE", "%s", h); if((h = getheader(req, "Content-Length")) != NULL) bufaddenv(dst, "CONTENT_LENGTH", "%s", h); else bufaddenv(dst, "CONTENT_LENGTH", "0"); if((h = getheader(req, "X-Ash-File")) != NULL) { h = absolutify(h); bufaddenv(dst, "SCRIPT_FILENAME", "%s", h); free(h); } for(i = 0; i < req->noheaders; i++) { h = sprintf2("HTTP_%s", req->headers[i][0]); for(p = h; *p; p++) { if(isalnum(*p)) *p = toupper(*p); else *p = '_'; } bufcatkv(dst, h, req->headers[i][1]); free(h); } }
static pid_t forkchild(int inpath, char **prog, char *file, char *method, char *url, char *rest, int *infd, int *outfd) { char *qp, **env, *name; int inp[2], outp[2]; pid_t pid; char *pi; int (*execfun)(const char *, char *const []); pipe(inp); pipe(outp); if((pid = fork()) < 0) { flog(LOG_ERR, "callcgi: could not fork"); exit(1); } if(pid == 0) { dup2(inp[0], 0); dup2(outp[1], 1); 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)); putenv("GATEWAY_INTERFACE=CGI/1.1"); if(getenv("HTTP_VERSION")) putenv(sprintf2("SERVER_PROTOCOL=%s", getenv("HTTP_VERSION"))); putenv(sprintf2("REQUEST_METHOD=%s", method)); name = url; /* XXX: This is an ugly hack (I think), but though I can think * of several alternatives, none seem to be better. */ if(*rest && (strlen(url) >= strlen(rest)) && !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")) putenv(sprintf2("CONTENT_TYPE=%s", getenv("REQ_CONTENT_TYPE"))); if(getenv("REQ_CONTENT_LENGTH")) putenv(sprintf2("CONTENT_LENGTH=%s", getenv("REQ_CONTENT_LENGTH"))); for(env = environ; *env; env++) { if(!strncmp(*env, "REQ_", 4)) putenv(sprintf2("HTTP_%s", (*env) + 4)); } /* * This is (understandably) missing from the CGI * specification, but PHP seems to require it. */ execfun = inpath?execvp:execv; if(file != NULL) putenv(sprintf2("SCRIPT_FILENAME=%s", absolutify(file))); execfun(prog[0], prog); exit(127); } close(inp[0]); close(outp[1]); *infd = inp[1]; *outfd = outp[0]; return(pid); }
Referen::Referen(Path path, Path context) : absPath(absolutify(path, context)), qualifiedName(qualify(absPath)) { }