From 09c82f9c7bc563c081425141853e6ff8e402e358 Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Sat, 15 Jan 2011 09:16:23 +0100 Subject: [PATCH] Comply better with the CGI specification by unquoting PATH_INFO. --- python/ashd-wsgi | 38 +++++++++++++++++++++++++++++++++++++- src/callcgi.c | 9 ++++++--- src/callfcgi.c | 9 +++++++-- src/callscgi.c | 9 +++++++-- 4 files changed, 57 insertions(+), 8 deletions(-) diff --git a/python/ashd-wsgi b/python/ashd-wsgi index ae08137..7462492 100755 --- a/python/ashd-wsgi +++ b/python/ashd-wsgi @@ -42,6 +42,39 @@ def absolutify(path): return os.path.join(cwd, path) return path +def unquoteurl(url): + buf = "" + i = 0 + while i < len(url): + c = url[i] + i += 1 + if c == '%': + if len(url) > i + 2: + c = 0 + if '0' <= url[i] <= '9': + c |= (ord(url[i]) - ord('0')) << 4 + elif 'a' <= url[i] <= 'f': + c |= (ord(url[i]) - ord('a')) << 4 + elif 'A' <= url[i] <= 'F': + c |= (ord(url[i]) - ord('A')) << 4 + else: + raise ValueError("Illegal URL escape character") + if '0' <= url[i + 1] <= '9': + c |= ord(url[i + 1]) - ord('0') + elif 'a' <= url[i + 1] <= 'f': + c |= ord(url[i + 1]) - ord('a') + elif 'A' <= url[i + 1] <= 'F': + c |= ord(url[i + 1]) - ord('A') + else: + raise ValueError("Illegal URL escape character") + buf += chr(c) + i += 2 + else: + raise ValueError("Incomplete URL escape character") + else: + buf += c + return buf + def dowsgi(req): env = {} env["wsgi.version"] = 1, 0 @@ -52,7 +85,10 @@ def dowsgi(req): env["SERVER_PROTOCOL"] = req.ver env["REQUEST_METHOD"] = req.method env["REQUEST_URI"] = req.url - env["PATH_INFO"] = req.rest + try: + env["PATH_INFO"] = unquoteurl(req.rest) + except: + env["PATH_INFO"] = req.rest name = req.url p = name.find('?') if p >= 0: diff --git a/src/callcgi.c b/src/callcgi.c index 528219a..14430aa 100644 --- a/src/callcgi.c +++ b/src/callcgi.c @@ -30,6 +30,7 @@ #endif #include #include +#include static char **environ; @@ -88,6 +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; pipe(inp); pipe(outp); @@ -109,7 +111,8 @@ 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)); + 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. */ @@ -164,7 +167,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; @@ -371,7 +374,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); } diff --git a/src/callfcgi.c b/src/callfcgi.c index a6d3945..9a7a362 100644 --- a/src/callfcgi.c +++ b/src/callfcgi.c @@ -441,14 +441,19 @@ static char *absolutify(char *file) static void mkcgienv(struct hthead *req, struct charbuf *dst) { int i; - char *url, *qp, *h, *p; + char *url, *unq, *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); - bufaddenv(dst, "PATH_INFO", req->rest); + 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; diff --git a/src/callscgi.c b/src/callscgi.c index 85cc50a..84b63c5 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, *qp, *h, *p; + char *url, *unq, *qp, *h, *p; bufaddenv(dst, "SERVER_SOFTWARE", "ashd/%s", VERSION); bufaddenv(dst, "GATEWAY_INTERFACE", "CGI/1.1"); @@ -411,7 +411,12 @@ 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); - bufaddenv(dst, "PATH_INFO", req->rest); + 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; -- 2.11.0