From: reyk Date: Mon, 4 Aug 2014 14:49:24 +0000 (+0000) Subject: Implement PATH_INFO and add DOCUMENT_ROOT. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=ef353f367ac875db70b87ddcec74c4791c1fbe94;p=openbsd Implement PATH_INFO and add DOCUMENT_ROOT. PATH_INFO was requested by naddy@ who successfully tested it with "cvsweb". ok naddy@ --- diff --git a/usr.sbin/httpd/httpd.c b/usr.sbin/httpd/httpd.c index c807dd4ed45..be3e1772d55 100644 --- a/usr.sbin/httpd/httpd.c +++ b/usr.sbin/httpd/httpd.c @@ -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 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -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) { diff --git a/usr.sbin/httpd/httpd.h b/usr.sbin/httpd/httpd.h index 92413cc6d22..e62bac3064e 100644 --- a/usr.sbin/httpd/httpd.h +++ b/usr.sbin/httpd/httpd.h @@ -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 @@ -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); diff --git a/usr.sbin/httpd/server_fcgi.c b/usr.sbin/httpd/server_fcgi.c index 87e1eb43777..a5ba108a67e 100644 --- a/usr.sbin/httpd/server_fcgi.c +++ b/usr.sbin/httpd/server_fcgi.c @@ -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 @@ -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(¶m, "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(¶m, "SCRIPT_FILENAME", str, - clt); - free(str); - if (ret == -1) { + if (scriptlen) { + if (fcgi_add_param(¶m, "PATH_INFO", + script + scriptlen, clt) == -1) { errstr = "failed to encode param"; goto fail; } + script[scriptlen] = '\0'; + } + + if (fcgi_add_param(¶m, "SCRIPT_NAME", + script + strlen(srv_conf->root), clt) == -1) { + errstr = "failed to encode param"; + goto fail; + } + if (fcgi_add_param(¶m, "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(¶m, "DOCUMENT_ROOT", srv_conf->root, + clt) == -1) { + errstr = "failed to encode param"; + goto fail; + } if (fcgi_add_param(¶m, "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);