]> granicus.if.org Git - apache/commitdiff
- Introduce concept of context prefix (which is an URL prefix)
authorStefan Fritsch <sf@apache.org>
Sun, 5 Jun 2011 21:33:12 +0000 (21:33 +0000)
committerStefan Fritsch <sf@apache.org>
Sun, 5 Jun 2011 21:33:12 +0000 (21:33 +0000)
  and context document root (which is the file system directory that
  this URL prefix is mapped to). This generalization of the document
  root makes it easier for scripts to create self-referential URLs and
  to find their files.
- Expose CONTEXT_DOCUMENT_ROOT and CONTEXT_PREFIX as envvars, in mod_rewrite,
  and in ap_expr.
- Make mod_alias and mod_userdir set the context information.
- Allow to override the document root on a per-request basis. This allows
  mass vhosting modules to set DOCUMENT_ROOT correctly.
- Make mod_vhost_alias set the per-request document root

PR: 26052, 46198, 49705

Remaining tasks:
- Use the context document root & prefix in mod_rewrite to make RewriteBase
  unneccessary in many cases. Do this without breaking compatibility.
- Write docs.

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1132494 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
include/ap_mmn.h
include/http_core.h
include/httpd.h
modules/mappers/mod_alias.c
modules/mappers/mod_rewrite.c
modules/mappers/mod_userdir.c
modules/mappers/mod_vhost_alias.c
server/core.c
server/util_expr_eval.c
server/util_script.c

diff --git a/CHANGES b/CHANGES
index 515b0a78a9692ceb01a4970fb27ef696a746a3bd..6a2bab6cba304933f5e762167747c3f68b8030e1 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -2,6 +2,15 @@
 
 Changes with Apache 2.3.13
 
+  *) mod_userdir/mod_alias/mod_vhost_alias: Correctly set DOCUMENT_ROOT,
+     CONTEXT_DOCUMENT_ROOT, CONTEXT_PREFIX. PR 26052. PR 46198.
+     [Stefan Fritsch]
+
+  *) core: Allow to override document_root on a per-request basis. Introduce
+     new context_document_root and context_prefix which provide information
+     about non-global URI-to-directory mappings (from e.g. mod_userdir or
+     mod_alias) to scripts. PR 49705. [Stefan Fritsch]
+
   *) core: Add <ElseIf> and <Else> to complement <If> sections.
      [Stefan Fritsch]
 
index c35b0f093f94f891be754ad5ac4d13e6e17f52a4..02f23ab6c34de658a261b0dc5e2a9c401aca0101 100644 (file)
  *                         ap_expr_exec_ctx()
  * 20110604.0 (2.3.13-dev) Make ap_rputs() inline
  * 20110605.0 (2.3.13-dev) add core_dir_config->condition_ifelse, change return
- *                         type of ap_add_if_conf()
+ *                         type of ap_add_if_conf().
+ *                         Add members of core_request_config: document_root,
+ *                         context_document_root, context_prefix.
+ *                         Add ap_context_*(), ap_set_context_info(), ap_set_document_root()
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
index c32a86540c47ed06f553cbebcd58f2bd9a5e636b..c48c7fa63cd0b733d3d6e5916d33fddd9ae50a16 100644 (file)
@@ -340,6 +340,24 @@ typedef struct {
                                    * ErrorDocument
                                    */
 
+    /** per-request document root of the server. This allows mass vhosting
+     * modules better compatibility with some scripts. Normally the
+     * context_* info should be used instead */
+    const char *document_root;
+
+    /*
+     * more fine-grained context information which is set by modules like
+     * mod_alias and mod_userdir
+     */
+    /** the context root directory on disk for the current resource,
+     *  without trailing slash
+     */
+    const char *context_document_root;
+    /** the URI prefix that corresponds to the context_document_root directory,
+     *  without trailing slash
+     */
+    const char *context_prefix;
+
     /** There is a script processor installed on the output filter chain,
      * so it needs the default_handler to deliver a (script) file into
      * the chain so it can process it. Normally, default_handler only
index e03a77ab9365454dffdeb10825e345c05b6ab18b..89d421a5f9676c3f4893c76c0337fdda9c7db5da 100644 (file)
@@ -1295,6 +1295,42 @@ typedef struct core_net_rec {
     core_ctx_t *in_ctx;
 } core_net_rec;
 
+/**
+ * Get the context_document_root for a request. This is a generalization of
+ * the document root, which is too limited in the presence of mappers like
+ * mod_userdir and mod_alias. The context_document_root is the directory
+ * on disk that maps to the context_prefix URI prefix.
+ * @param r The request
+ * @note For resources that do not map to the file system or for very complex
+ * mappings, this information may still be wrong.
+ */
+AP_DECLARE(const char *) ap_context_document_root(request_rec *r);
+
+/**
+ * Get the context_prefix for a request. The context_prefix URI prefix
+ * maps to the context_document_root on disk.
+ * @param r The request
+ */
+AP_DECLARE(const char *) ap_context_prefix(request_rec *r);
+
+/** Set context_prefix and context_document_root for a request.
+ * @param r The request
+ * @param prefix the URI prefix, without trailing slash
+ * @param document_root the corresponding directory on disk, without trailing
+ * slash
+ * @note If one of prefix of document_root is NULL, the corrsponding
+ * property will not be changed.
+ */
+AP_DECLARE(void) ap_set_context_info(request_rec *r, const char *prefix,
+                                     const char *document_root);
+
+/** Set per-request document root. This is for mass virtual hosting modules
+ * that want to provide the correct DOCUMENT_ROOT value to scripts.
+ * @param r The request
+ * @param document_root the document root for the request.
+ */
+AP_DECLARE(void) ap_set_document_root(request_rec *r, const char *document_root);
+
 /**
  * Examine a field value (such as a media-/content-type) string and return
  * it sans any parameters; e.g., strip off any ';charset=foo' and the like.
index dc40b670867f7e951fb02cf990373daa95c095d7..18b48f557e57d83ef42ba5b8964c36ce2736f1de 100644 (file)
@@ -334,7 +334,7 @@ static int alias_matches(const char *uri, const char *alias_fakename)
 }
 
 static char *try_alias_list(request_rec *r, apr_array_header_t *aliases,
-                            int doesc, int *status)
+                            int is_redir, int *status)
 {
     alias_entry *entries = (alias_entry *) aliases->elts;
     ap_regmatch_t regm[AP_MAX_REG_MATCH];
@@ -350,21 +350,34 @@ static char *try_alias_list(request_rec *r, apr_array_header_t *aliases,
                 if (alias->real) {
                     found = ap_pregsub(r->pool, alias->real, r->uri,
                                        AP_MAX_REG_MATCH, regm);
-                    if (found && doesc) {
-                        apr_uri_t uri;
-                        apr_uri_parse(r->pool, found, &uri);
-                        /* Do not escape the query string or fragment. */
-                        found = apr_uri_unparse(r->pool, &uri,
-                                                APR_URI_UNP_OMITQUERY);
-                        found = ap_escape_uri(r->pool, found);
-                        if (uri.query) {
-                            found = apr_pstrcat(r->pool, found, "?",
-                                                uri.query, NULL);
-                        }
-                        if (uri.fragment) {
-                            found = apr_pstrcat(r->pool, found, "#",
-                                                uri.fragment, NULL);
-                        }
+                    if (found) {
+                       if (is_redir) {
+                            apr_uri_t uri;
+                            apr_uri_parse(r->pool, found, &uri);
+                            /* Do not escape the query string or fragment. */
+                            found = apr_uri_unparse(r->pool, &uri,
+                                                    APR_URI_UNP_OMITQUERY);
+                            found = ap_escape_uri(r->pool, found);
+                            if (uri.query) {
+                                found = apr_pstrcat(r->pool, found, "?",
+                                                    uri.query, NULL);
+                            }
+                            if (uri.fragment) {
+                                found = apr_pstrcat(r->pool, found, "#",
+                                                    uri.fragment, NULL);
+                            }
+                       }
+                       else {
+                           int pathlen = strlen(found) -
+                                         (strlen(r->uri + regm[0].rm_eo));
+                           AP_DEBUG_ASSERT(pathlen >= 0);
+                           AP_DEBUG_ASSERT(pathlen <= strlen(found));
+                           ap_set_context_info(r,
+                                               apr_pstrmemdup(r->pool, r->uri,
+                                                              regm[0].rm_eo),
+                                               apr_pstrmemdup(r->pool, found,
+                                                              pathlen));
+                       }
                     }
                 }
                 else {
@@ -377,7 +390,8 @@ static char *try_alias_list(request_rec *r, apr_array_header_t *aliases,
             l = alias_matches(r->uri, alias->fake);
 
             if (l > 0) {
-                if (doesc) {
+                ap_set_context_info(r, alias->fake, alias->real);
+                if (is_redir) {
                     char *escurl;
                     escurl = ap_os_escape_path(r->pool, r->uri + l, 1);
 
@@ -398,7 +412,7 @@ static char *try_alias_list(request_rec *r, apr_array_header_t *aliases,
              * canonicalized.  After I finish eliminating os canonical.
              * Better fail test for ap_server_root_relative needed here.
              */
-            if (!doesc) {
+            if (!is_redir) {
                 found = ap_server_root_relative(r->pool, found);
             }
             if (found) {
index a5bd3520e8de3a50647b7cf99776682498b3169e..32def93669a3741ffbae122d7cad61c0917cb6f0 100644 (file)
@@ -2088,6 +2088,9 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx)
             if (*var == 'H' && !strcmp(var, "HTTP_FORWARDED")) {
                 result = lookup_header("Forwarded", ctx);
             }
+            else if (*var == 'C' && !strcmp(var, "CONTEXT_PREFIX")) {
+                result = ap_context_prefix(r);
+            }
             else if (var[8] == 'M' && !strcmp(var, "REQUEST_METHOD")) {
                 result = r->method;
             }
@@ -2134,6 +2137,9 @@ static char *lookup_variable(char *var, rewrite_ctx *ctx)
             if (!strcmp(var, "HTTP_PROXY_CONNECTION")) {
                 result = lookup_header("Proxy-Connection", ctx);
             }
+            else if (!strcmp(var, "CONTEXT_DOCUMENT_ROOT")) {
+                result = ap_context_document_root(r);
+            }
             break;
         }
     }
index 09a856ccf91c1b9196f27652fc845ade62ba2bf9..9d619729b2674c89919ec75a6c63f0274d3cf9bf 100644 (file)
@@ -323,6 +323,9 @@ static int translate_userdir(request_rec *r)
                                          r->pool)) == APR_SUCCESS
                                              || rv == APR_INCOMPLETE))) {
             r->filename = apr_pstrcat(r->pool, filename, dname, NULL);
+            ap_set_context_info(r, apr_pstrmemdup(r->pool, r->uri,
+                                                  dname - r->uri),
+                                filename);
             /* XXX: Does this walk us around FollowSymLink rules?
              * When statbuf contains info on r->filename we can save a syscall
              * by copying it to r->finfo
index c35c1fe51e41dde03109d6e82e355271db83d09c..70c857d4ee421d7dbee722ad46af9b05dc25cac0 100644 (file)
@@ -259,7 +259,8 @@ static void vhost_alias_interpolate(request_rec *r, const char *name,
     int ndots;
 
     char buf[HUGE_STRING_LEN];
-    char *dest, last;
+    char *dest;
+    const char *docroot;
 
     int N, M, Np, Mp, Nd, Md;
     const char *start, *end;
@@ -278,18 +279,15 @@ static void vhost_alias_interpolate(request_rec *r, const char *name,
     r->filename = NULL;
 
     dest = buf;
-    last = '\0';
     while (*map) {
         if (*map != '%') {
             /* normal characters */
             vhost_alias_checkspace(r, buf, &dest, 1);
-            last = *dest++ = *map++;
+            *dest++ = *map++;
             continue;
         }
         /* we are in a format specifier */
         ++map;
-        /* can't be a slash */
-        last = '\0';
         /* %% -> % */
         if (*map == '%') {
             ++map;
@@ -366,18 +364,19 @@ static void vhost_alias_interpolate(request_rec *r, const char *name,
             *dest++ = apr_tolower(*p);
         }
     }
-    *dest = '\0';
     /* no double slashes */
-    if (last == '/') {
-        ++uri;
+    if (dest - buf > 0 && dest[-1] == '/') {
+        --dest;
     }
+    *dest = '\0';
 
-    if (r->filename) {
-        r->filename = apr_pstrcat(r->pool, r->filename, buf, uri, NULL);
-    }
-    else {
-        r->filename = apr_pstrcat(r->pool, buf, uri, NULL);
-    }
+    if (r->filename)
+        docroot = apr_pstrcat(r->pool, r->filename, buf, NULL);
+    else
+        docroot = apr_pstrdup(r->pool, buf);
+    r->filename = apr_pstrcat(r->pool, docroot, uri, NULL);
+    ap_set_context_info(r, NULL, docroot);
+    ap_set_document_root(r, docroot);
 }
 
 static int mva_translate(request_rec *r)
@@ -432,6 +431,7 @@ static int mva_translate(request_rec *r)
         /* see is_scriptaliased() in mod_cgi */
         r->handler = "cgi-script";
         apr_table_setn(r->notes, "alias-forced-type", r->handler);
+        ap_set_context_info(r, "/cgi-bin", NULL);
     }
 
     return OK;
index 6566bef1fb09a2f1c8720a9df7606c649344b1a2..fdeceb79c5739c286daeaa8001f0960d8b95dcdf 100644 (file)
@@ -722,12 +722,51 @@ AP_DECLARE(int) ap_satisfies(request_rec *r)
 
 AP_DECLARE(const char *) ap_document_root(request_rec *r) /* Don't use this! */
 {
-    core_server_config *conf;
+    core_server_config *sconf;
+    core_request_config *rconf = ap_get_module_config(r->request_config,
+                                                     &core_module);
+    if (rconf->document_root)
+        return rconf->document_root;
+    sconf = ap_get_module_config(r->server->module_config, &core_module);
+    return sconf->ap_document_root;
+}
 
-    conf = (core_server_config *)ap_get_module_config(r->server->module_config,
-                                                      &core_module);
+AP_DECLARE(const char *) ap_context_prefix(request_rec *r)
+{
+    core_request_config *conf = ap_get_module_config(r->request_config,
+                                                     &core_module);
+    if (conf->context_prefix)
+        return conf->context_prefix;
+    else
+        return "";
+}
 
-    return conf->ap_document_root;
+AP_DECLARE(const char *) ap_context_document_root(request_rec *r)
+{
+    core_request_config *conf = ap_get_module_config(r->request_config,
+                                                     &core_module);
+    if (conf->context_document_root)
+        return conf->context_document_root;
+    else
+        return ap_document_root(r);
+}
+
+AP_DECLARE(void) ap_set_document_root(request_rec *r, const char *document_root)
+{
+    core_request_config *conf = ap_get_module_config(r->request_config,
+                                                     &core_module);
+    conf->document_root = document_root;
+}
+
+AP_DECLARE(void) ap_set_context_info(request_rec *r, const char *context_prefix,
+                                     const char *context_document_root)
+{
+    core_request_config *conf = ap_get_module_config(r->request_config,
+                                                     &core_module);
+    if (context_prefix)
+        conf->context_prefix = context_prefix;
+    if (context_document_root)
+        conf->context_document_root = context_document_root;
 }
 
 /* Should probably just get rid of this... the only code that cares is
index 544b7a043ed56c40ba3a60a0917d400642556787..6ba414f02acdbc94a8e56f3863ce57efd68253fc 100644 (file)
@@ -1081,6 +1081,8 @@ static const char *request_var_names[] = {
     "SCRIPT_GROUP",             /* 22 */
     "DOCUMENT_URI",             /* 23 */
     "LAST_MODIFIED",            /* 24 */
+    "CONTEXT_PREFIX",           /* 25 */
+    "CONTEXT_DOCUMENT_ROOT",    /* 26 */
     NULL
 };
 
@@ -1160,6 +1162,10 @@ static const char *request_var_fn(ap_expr_eval_ctx_t *ctx, const void *data)
                                 tm.tm_mon+1, tm.tm_mday, tm.tm_hour, tm.tm_min,
                                 tm.tm_sec);
         }
+    case 25:
+        return ap_context_prefix(r);
+    case 26:
+        return ap_context_document_root(r);
     default:
         ap_assert(0);
         return NULL;
index 2d070816f0536ac49efecf2014dc106823523afe..2008beeb6a6e3975d521f6e6b4c840d6ae5b049f 100644 (file)
@@ -238,6 +238,9 @@ AP_DECLARE(void) ap_add_common_vars(request_rec *r)
                     ap_get_remote_host(c, r->per_dir_config, REMOTE_HOST, NULL));
     apr_table_addn(e, "REMOTE_ADDR", c->remote_ip);
     apr_table_addn(e, "DOCUMENT_ROOT", ap_document_root(r));    /* Apache */
+    apr_table_setn(e, "REQUEST_SCHEME", ap_http_scheme(r));
+    apr_table_addn(e, "CONTEXT_PREFIX", ap_context_prefix(r));
+    apr_table_addn(e, "CONTEXT_DOCUMENT_ROOT", ap_context_document_root(r));
     apr_table_addn(e, "SERVER_ADMIN", s->server_admin); /* Apache */
     apr_table_addn(e, "SCRIPT_FILENAME", r->filename);  /* Apache */
 
@@ -337,7 +340,6 @@ AP_DECLARE(void) ap_add_cgi_vars(request_rec *r)
     apr_table_setn(e, "GATEWAY_INTERFACE", "CGI/1.1");
     apr_table_setn(e, "SERVER_PROTOCOL", r->protocol);
     apr_table_setn(e, "REQUEST_METHOD", r->method);
-    apr_table_setn(e, "REQUEST_SCHEME", ap_http_scheme(r));
     apr_table_setn(e, "QUERY_STRING", r->args ? r->args : "");
     apr_table_setn(e, "REQUEST_URI", original_uri(r));