From: Fredrik Tolf Date: Sun, 26 Jun 2011 05:16:08 +0000 (+0200) Subject: call*cgi, python: Try to emulate standard CGI behavior closer. X-Git-Tag: 0.9~7 X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=commitdiff_plain;h=53d666cafb4af8f07bf74af9278702db82085d45 call*cgi, python: Try to emulate standard CGI behavior closer. The proper way to handle the problem in question seems very unclear, however; see the comment in callcgi.c for further details. --- diff --git a/python/ashd-wsgi b/python/ashd-wsgi index e43dbc0..894211d 100755 --- a/python/ashd-wsgi +++ b/python/ashd-wsgi @@ -92,10 +92,6 @@ def dowsgi(req): env["SERVER_PROTOCOL"] = req.ver env["REQUEST_METHOD"] = req.method env["REQUEST_URI"] = req.url - try: - env["PATH_INFO"] = unquoteurl(req.rest) - except: - env["PATH_INFO"] = req.rest name = req.url p = name.find('?') if p >= 0: @@ -104,8 +100,19 @@ def dowsgi(req): else: env["QUERY_STRING"] = "" if name[-len(req.rest):] == req.rest: + # This is the same hack used in call*cgi. name = name[:-len(req.rest)] + try: + pi = unquoteurl(req.rest) + except: + pi = req.rest + if name == '/': + # This seems to be normal CGI behavior, but see callcgi.c for + # details. + pi = "/" + pi + name = "" env["SCRIPT_NAME"] = name + env["PATH_INFO"] = pi if "Host" in req: env["SERVER_NAME"] = req["Host"] if "X-Ash-Server-Port" in req: env["SERVER_PORT"] = req["X-Ash-Server-Port"] if "X-Ash-Protocol" in req and req["X-Ash-Protocol"] == "https": env["HTTPS"] = "on" diff --git a/src/callcgi.c b/src/callcgi.c index 14430aa..3add3ed 100644 --- a/src/callcgi.c +++ b/src/callcgi.c @@ -89,7 +89,7 @@ static pid_t forkchild(int inpath, char *prog, char *file, char *method, char *u char *qp, **env, *name; int inp[2], outp[2]; pid_t pid; - char *unqr; + char *pi; pipe(inp); pipe(outp); @@ -111,8 +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)); - 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. */ @@ -120,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")) diff --git a/src/callfcgi.c b/src/callfcgi.c index 9af5929..99d21ca 100644 --- a/src/callfcgi.c +++ b/src/callfcgi.c @@ -441,19 +441,13 @@ static char *absolutify(char *file) static void mkcgienv(struct hthead *req, struct charbuf *dst) { int i; - char *url, *unq, *qp, *h, *p; + 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); - if((unq = unquoteurl(req->rest)) != NULL) { - bufaddenv(dst, "PATH_INFO", unq); - free(unq); - } else { - bufaddenv(dst, "PATH_INFO", req->rest); - } url = sstrdup(req->url); if((qp = strchr(url, '?')) != NULL) *(qp++) = 0; @@ -461,11 +455,21 @@ static void mkcgienv(struct hthead *req, struct charbuf *dst) * several alternatives, none seem to be better. */ if(*req->rest && (strlen(url) >= strlen(req->rest)) && !strcmp(req->rest, url + strlen(url) - strlen(req->rest))) { - bufaddenv(dst, "SCRIPT_NAME", "%.*s", (int)(strlen(url) - strlen(req->rest)), url); - } else { - bufaddenv(dst, "SCRIPT_NAME", "%s", url); - } + 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", pi); + bufaddenv(dst, "SCRIPT_NAME", url); bufaddenv(dst, "QUERY_STRING", "%s", qp?qp:""); + free(pi); free(url); if((h = getheader(req, "Host")) != NULL) bufaddenv(dst, "SERVER_NAME", "%s", h); diff --git a/src/callscgi.c b/src/callscgi.c index 062baa1..299e09f 100644 --- a/src/callscgi.c +++ b/src/callscgi.c @@ -403,7 +403,7 @@ static char *absolutify(char *file) static void mkcgienv(struct hthead *req, struct charbuf *dst) { int i; - char *url, *unq, *qp, *h, *p; + char *url, *pi, *tmp, *qp, *h, *p; bufaddenv(dst, "SERVER_SOFTWARE", "ashd/%s", VERSION); bufaddenv(dst, "GATEWAY_INTERFACE", "CGI/1.1"); @@ -411,12 +411,6 @@ static void mkcgienv(struct hthead *req, struct charbuf *dst) bufaddenv(dst, "SERVER_PROTOCOL", "%s", req->ver); bufaddenv(dst, "REQUEST_METHOD", "%s", req->method); bufaddenv(dst, "REQUEST_URI", "%s", req->url); - if((unq = unquoteurl(req->rest)) != NULL) { - bufaddenv(dst, "PATH_INFO", unq); - free(unq); - } else { - bufaddenv(dst, "PATH_INFO", req->rest); - } url = sstrdup(req->url); if((qp = strchr(url, '?')) != NULL) *(qp++) = 0; @@ -424,11 +418,21 @@ static void mkcgienv(struct hthead *req, struct charbuf *dst) * several alternatives, none seem to be better. */ if(*req->rest && (strlen(url) >= strlen(req->rest)) && !strcmp(req->rest, url + strlen(url) - strlen(req->rest))) { - bufaddenv(dst, "SCRIPT_NAME", "%.*s", (int)(strlen(url) - strlen(req->rest)), url); - } else { - bufaddenv(dst, "SCRIPT_NAME", "%s", url); + 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", pi); + bufaddenv(dst, "SCRIPT_NAME", url); bufaddenv(dst, "QUERY_STRING", "%s", qp?qp:""); + free(pi); free(url); if((h = getheader(req, "Host")) != NULL) bufaddenv(dst, "SERVER_NAME", "%s", h);