Implement PATH_INFO and add DOCUMENT_ROOT.
authorreyk <reyk@openbsd.org>
Mon, 4 Aug 2014 14:49:24 +0000 (14:49 +0000)
committerreyk <reyk@openbsd.org>
Mon, 4 Aug 2014 14:49:24 +0000 (14:49 +0000)
PATH_INFO was requested by naddy@ who successfully tested it with "cvsweb".

ok naddy@

usr.sbin/httpd/httpd.c
usr.sbin/httpd/httpd.h
usr.sbin/httpd/server_fcgi.c

index c807dd4..be3e177 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: httpd.c,v 1.13 2014/08/04 11:09:25 reyk Exp $ */
+/*     $OpenBSD: httpd.c,v 1.14 2014/08/04 14:49:24 reyk Exp $ */
 
 /*
  * Copyright (c) 2014 Reyk Floeter <reyk@openbsd.org>
@@ -19,6 +19,7 @@
 #include <sys/types.h>
 #include <sys/queue.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <sys/wait.h>
 #include <sys/resource.h>
 #include <sys/hash.h>
@@ -515,6 +516,30 @@ canonicalize_path(const char *input, char *path, size_t len)
        return (path);
 }
 
+ssize_t
+path_info(char *name)
+{
+       char            *p, *start, *end;
+       char             path[MAXPATHLEN];
+       struct stat      st;
+
+       if (strlcpy(path, name, sizeof(path)) >= sizeof(path))
+               return (-1);
+
+       start = path;
+       end = start + strlen(path);
+
+       for (p = end; p > start; p--) {
+               if (*p != '/')
+                       continue;
+               if (stat(path, &st) == 0)
+                       break;
+               *p = '\0';
+       }
+
+       return (strlen(path));
+}
+
 void
 socket_rlimit(int maxfd)
 {
index 92413cc..e62bac3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: httpd.h,v 1.38 2014/08/04 06:35:10 deraadt Exp $      */
+/*     $OpenBSD: httpd.h,v 1.39 2014/08/04 14:49:24 reyk Exp $ */
 
 /*
  * Copyright (c) 2006 - 2014 Reyk Floeter <reyk@openbsd.org>
@@ -473,6 +473,7 @@ void                 event_again(struct event *, int, short,
                    struct timeval *, struct timeval *, void *);
 const char     *canonicalize_host(const char *, char *, size_t);
 const char     *canonicalize_path(const char *, char *, size_t);
+ssize_t                 path_info(char *);
 void            imsg_event_add(struct imsgev *);
 int             imsg_compose_event(struct imsgev *, u_int16_t, u_int32_t,
                    pid_t, int, void *, u_int16_t);
index 87e1eb4..a5ba108 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: server_fcgi.c,v 1.19 2014/08/04 11:09:25 reyk Exp $   */
+/*     $OpenBSD: server_fcgi.c,v 1.20 2014/08/04 14:49:24 reyk Exp $   */
 
 /*
  * Copyright (c) 2014 Florian Obser <florian@openbsd.org>
@@ -102,9 +102,10 @@ server_fcgi(struct httpd *env, struct client *clt)
        struct fcgi_record_header       *h;
        struct fcgi_begin_request_body  *begin;
        size_t                           len;
+       ssize_t                          scriptlen;
        int                              fd = -1, ret;
        const char                      *errstr = NULL;
-       char                            *str, *p;
+       char                            *str, *p, *script = NULL;
        in_port_t                        port;
        struct sockaddr_storage          ss;
 
@@ -188,20 +189,30 @@ server_fcgi(struct httpd *env, struct client *clt)
        h->type = FCGI_PARAMS;
        h->content_len = param.total_len = 0;
 
-       if (fcgi_add_param(&param, "SCRIPT_NAME", desc->http_path,
-           clt) == -1) {
-               errstr = "failed to encode param";
+       if (asprintf(&script, "%s%s", srv_conf->root,
+           desc->http_path) == -1 ||
+           (scriptlen = path_info(script)) == -1) {
+               errstr = "failed to get script name";
                goto fail;
        }
 
-       if (asprintf(&str, "%s%s", srv_conf->root, desc->http_path) != -1) {
-               ret = fcgi_add_param(&param, "SCRIPT_FILENAME", str,
-                   clt);
-               free(str);
-               if (ret == -1) {
+       if (scriptlen) {
+               if (fcgi_add_param(&param, "PATH_INFO",
+                   script + scriptlen, clt) == -1) {
                        errstr = "failed to encode param";
                        goto fail;
                }
+               script[scriptlen] = '\0';
+       }
+
+       if (fcgi_add_param(&param, "SCRIPT_NAME",
+           script + strlen(srv_conf->root), clt) == -1) {
+               errstr = "failed to encode param";
+               goto fail;
+       }
+       if (fcgi_add_param(&param, "SCRIPT_FILENAME", script, clt) == -1) {
+               errstr = "failed to encode param";
+               goto fail;
        }
 
        if (desc->http_query)
@@ -211,6 +222,11 @@ server_fcgi(struct httpd *env, struct client *clt)
                        goto fail;
                }
 
+       if (fcgi_add_param(&param, "DOCUMENT_ROOT", srv_conf->root,
+           clt) == -1) {
+               errstr = "failed to encode param";
+               goto fail;
+       }
        if (fcgi_add_param(&param, "DOCUMENT_URI", desc->http_path,
            clt) == -1) {
                errstr = "failed to encode param";
@@ -321,8 +337,10 @@ server_fcgi(struct httpd *env, struct client *clt)
        clt->clt_persist = 0;
        clt->clt_done = 0;
 
+       free(script);
        return (0);
  fail:
+       free(script);
        if (errstr == NULL)
                errstr = strerror(errno);
        server_abort_http(clt, 500, errstr);