Comply better with the CGI specification by unquoting PATH_INFO.
authorFredrik Tolf <fredrik@dolda2000.com>
Sat, 15 Jan 2011 08:16:23 +0000 (09:16 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Sat, 15 Jan 2011 08:16:23 +0000 (09:16 +0100)
python/ashd-wsgi
src/callcgi.c
src/callfcgi.c
src/callscgi.c

index ae08137..7462492 100755 (executable)
@@ -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:
index 528219a..14430aa 100644 (file)
@@ -30,6 +30,7 @@
 #endif
 #include <utils.h>
 #include <log.h>
+#include <req.h>
 
 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);
     }
index a6d3945..9a7a362 100644 (file)
@@ -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;
index 85cc50a..84b63c5 100644 (file)
@@ -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;