Skip to content
Commit bd847bdd authored by William A. Rowe Jr's avatar William A. Rowe Jr
Browse files

Author: minfrin

Date: Sun Mar 21 18:36:59 2010
New Revision: 925858

URL: http://svn.apache.org/viewvc?rev=925858&view=rev
Log:
core: Support wildcards in both the directory and file components of
the path specified by the Include directive.
Submitted by: minfrin, poirier
Reviewed by: minfrin, jim, poirier

Modified:
    httpd/httpd/branches/2.2.x/CHANGES
    httpd/httpd/branches/2.2.x/STATUS
    httpd/httpd/branches/2.2.x/docs/manual/mod/core.xml
    httpd/httpd/branches/2.2.x/server/config.c

Modified: httpd/httpd/branches/2.2.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/CHANGES?rev=925858&r1=925857&r2=925858&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.2.x/CHANGES [utf-8] Sun Mar 21 18:36:59 2010
@@ -1,6 +1,9 @@
                                                          -*- coding: utf-8 -*-
 Changes with Apache 2.2.16
 
+  *) core: Support wildcards in both the directory and file components of
+     the path specified by the Include directive. [Graham Leggett, Dan
+     Poirier]
 
 
 Changes with Apache 2.2.15

Modified: httpd/httpd/branches/2.2.x/STATUS
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/STATUS?rev=925858&r1=925857&r2=925858&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/STATUS (original)
+++ httpd/httpd/branches/2.2.x/STATUS Sun Mar 21 18:36:59 2010
@@ -86,15 +86,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  * core: Support wildcards in both the directory and file components of
-    the path specified by the Include directive.
-    Trunk patch: http://svn.apache.org/viewvc?rev=909878&view=rev
-                 http://svn.apache.org/viewvc?rev=917735&view=rev
-                 http://svn.apache.org/viewvc?rev=917759&view=rev
-    2.2.x patch: http://people.apache.org/~minfrin/httpd-wildcard+docs2.patch
-    Submitted by: minfrin, poirier
-    +1: minfrin, jim, poirier
-
 
 PATCHES PROPOSED TO BACKPORT FROM TRUNK:
   [ New proposals should be added at the end of the list ]

Modified: httpd/httpd/branches/2.2.x/docs/manual/mod/core.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/docs/manual/mod/core.xml?rev=925858&r1=925857&r2=925858&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/docs/manual/mod/core.xml (original)
+++ httpd/httpd/branches/2.2.x/docs/manual/mod/core.xml Sun Mar 21 18:36:59 2010
@@ -1513,20 +1513,33 @@ the server configuration files</descript
 <contextlist><context>server config</context><context>virtual host</context>
 <context>directory</context>
 </contextlist>
-<compatibility>Wildcard matching available in 2.0.41 and later</compatibility>
+<compatibility>Wildcard matching available in 2.0.41 and later, directory
+wildcard matching available in 2.3.6 and later</compatibility>
 
 <usage>
     <p>This directive allows inclusion of other configuration files
     from within the server configuration files.</p>
 
-    <p>Shell-style (<code>fnmatch()</code>) wildcard characters can be used to
-    include several files at once, in alphabetical order. In
-    addition, if <directive>Include</directive> points to a directory,
-    rather than a file, Apache will read all files in that directory
-    and any subdirectory.  But including entire directories is not
-    recommended, because it is easy to accidentally leave temporary
-    files in a directory that can cause <program>httpd</program> to
-    fail.</p>
+    <p>Shell-style (<code>fnmatch()</code>) wildcard characters can be used
+    in the filename or directory parts of the path to include several files
+    at once, in alphabetical order. In addition, if
+    <directive>Include</directive> points to a directory, rather than a file,
+    Apache will read all files in that directory and any subdirectory.
+    However, including entire directories is not recommended, because it is
+    easy to accidentally leave temporary files in a directory that can cause
+    <program>httpd</program> to fail. Instead, we encourage you to use the
+    wildcard syntax shown below, to include files that match a particular
+    pattern, such as *.conf, for example.</p>
+  
+    <p>When a wildcard is specified for a file or directory component of the
+    path, and no file or directory matches the wildcard, the
+    <directive module="core">Include</directive> directive will be
+    silently ignored. When a directory or file component of the path is
+    specified exactly, and that directory or file does not exist,
+    <directive module="core">Include</directive> directive will fail with an
+    error saying the file or directory cannot be found. This removes the need
+    for placeholder files to exist so that at least one file or directory is
+    found by the wildcard.</p>
 
     <p>The file path specified may be an absolute path, or may be relative 
     to the <directive module="core">ServerRoot</directive> directory.</p>

Modified: httpd/httpd/branches/2.2.x/server/config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/server/config.c?rev=925858&r1=925857&r2=925858&view=diff
==============================================================================
--- httpd/httpd/branches/2.2.x/server/config.c (original)
+++ httpd/httpd/branches/2.2.x/server/config.c Sun Mar 21 18:36:59 2010
@@ -1528,7 +1528,7 @@ static const char *process_command_confi
 }
 
 typedef struct {
-    char *fname;
+    const char *fname;
 } fnames;
 
 static int fname_alphasort(const void *fn1, const void *fn2)
@@ -1639,6 +1639,107 @@ static const char *process_resource_conf
     return NULL;
 }
 
+static const char *process_resource_config_fnmatch(server_rec *s,
+                                                   const char *path,
+                                                   const char *fname,
+                                                   ap_directive_t **conftree,
+                                                   apr_pool_t *p,
+                                                   apr_pool_t *ptemp,
+                                                   unsigned depth)
+{
+    char *rest;
+    apr_status_t rv;
+    apr_dir_t *dirp;
+    apr_finfo_t dirent;
+    apr_array_header_t *candidates = NULL;
+    fnames *fnew;
+    int current;
+
+    /* find the first part of the filename */
+    rest = ap_strchr(fname, '/');
+    if (rest) {
+        fname = apr_pstrndup(ptemp, fname, rest - fname);
+        rest++;
+    }
+
+    /* optimisation - if the filename isn't a wildcard, process it directly */
+    if (!apr_fnmatch_test(fname)) {
+        path = ap_make_full_path(ptemp, path, fname);
+        if (!rest) {
+            return process_resource_config_nofnmatch(s, path,
+                                                     conftree, p,
+                                                     ptemp, 0);
+        }
+        else {
+            return process_resource_config_fnmatch(s, path, rest,
+                                                   conftree, p,
+                                                   ptemp, 0);
+        }
+    }
+
+    /*
+     * first course of business is to grok all the directory
+     * entries here and store 'em away. Recall we need full pathnames
+     * for this.
+     */
+    rv = apr_dir_open(&dirp, path, ptemp);
+    if (rv != APR_SUCCESS) {
+        char errmsg[120];
+        return apr_psprintf(p, "Could not open config directory %s: %s",
+                            path, apr_strerror(rv, errmsg, sizeof errmsg));
+    }
+
+    candidates = apr_array_make(ptemp, 1, sizeof(fnames));
+    while (apr_dir_read(&dirent, APR_FINFO_DIRENT | APR_FINFO_TYPE, dirp) == APR_SUCCESS) {
+        /* strip out '.' and '..' */
+        if (strcmp(dirent.name, ".")
+            && strcmp(dirent.name, "..")
+            && (apr_fnmatch(fname, dirent.name,
+                            APR_FNM_PERIOD) == APR_SUCCESS)) {
+            const char *full_path = ap_make_full_path(ptemp, path, dirent.name);
+            /* If matching internal to path, and we happen to match something
+             * other than a directory, skip it
+             */
+            if (rest && (rv == APR_SUCCESS) && (dirent.filetype != APR_DIR)) {
+                continue;
+            }
+            fnew = (fnames *) apr_array_push(candidates);
+            fnew->fname = full_path;
+        }
+    }
+
+    apr_dir_close(dirp);
+    if (candidates->nelts != 0) {
+        const char *error;
+
+        qsort((void *) candidates->elts, candidates->nelts,
+              sizeof(fnames), fname_alphasort);
+
+        /*
+         * Now recurse these... we handle errors and subdirectories
+         * via the recursion, which is nice
+         */
+        for (current = 0; current < candidates->nelts; ++current) {
+            fnew = &((fnames *) candidates->elts)[current];
+            if (!rest) {
+                error = process_resource_config_nofnmatch(s, fnew->fname,
+                                                          conftree, p,
+                                                          ptemp, 0);
+            }
+            else {
+                error = process_resource_config_fnmatch(s, fnew->fname, rest,
+                                                        conftree, p,
+                                                        ptemp, 0);
+            }
+            if (error) {
+                return error;
+            }
+        }
+    }
+
+    return NULL;
+}
+
 AP_DECLARE(const char *) ap_process_resource_config(server_rec *s,
                                                     const char *fname,
                                                     ap_directive_t **conftree,
@@ -1663,80 +1764,24 @@ AP_DECLARE(const char *) ap_process_reso
                                                  0);
     }
     else {
-        apr_dir_t *dirp;
-        apr_finfo_t dirent;
-        int current;
-        apr_array_header_t *candidates = NULL;
-        fnames *fnew;
-        apr_status_t rv;
-        char *path = apr_pstrdup(p, fname), *pattern = NULL;
-
-        pattern = ap_strrchr(path, '/');
+        apr_status_t status;
+        const char *rootpath, *filepath = fname;
 
-        AP_DEBUG_ASSERT(pattern != NULL); /* path must be absolute. */
+        /* locate the start of the directories proper */
+        status = apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME, ptemp);
 
-        *pattern++ = '\0';
-
-        if (apr_fnmatch_test(path)) {
-            return apr_pstrcat(p, "Wildcard patterns not allowed in Include ",
-                               fname, NULL);
+        /* we allow APR_SUCCESS and APR_EINCOMPLETE */
+        if (APR_ERELATIVE == status) {
+            return apr_pstrcat(p, "Include must have an absolute path, ", fname, NULL);
         }
-
-        if (!ap_is_directory(p, path)){
-            return apr_pstrcat(p, "Include directory '", path, "' not found",
-                               NULL);
+        else if (APR_EBADPATH == status) {
+            return apr_pstrcat(p, "Include has a bad path, ", fname, NULL);
         }
 
-        if (!apr_fnmatch_test(pattern)) {
-            return apr_pstrcat(p, "Must include a wildcard pattern for "
-                               "Include ", fname, NULL);
-        }
-
-        /*
-         * first course of business is to grok all the directory
-         * entries here and store 'em away. Recall we need full pathnames
-         * for this.
-         */
-        rv = apr_dir_open(&dirp, path, p);
-        if (rv != APR_SUCCESS) {
-            char errmsg[120];
-            return apr_psprintf(p, "Could not open config directory %s: %s",
-                                path, apr_strerror(rv, errmsg, sizeof errmsg));
-        }
-
-        candidates = apr_array_make(p, 1, sizeof(fnames));
-        while (apr_dir_read(&dirent, APR_FINFO_DIRENT, dirp) == APR_SUCCESS) {
-            /* strip out '.' and '..' */
-            if (strcmp(dirent.name, ".")
-                && strcmp(dirent.name, "..")
-                && (apr_fnmatch(pattern, dirent.name,
-                                APR_FNM_PERIOD) == APR_SUCCESS)) {
-                fnew = (fnames *) apr_array_push(candidates);
-                fnew->fname = ap_make_full_path(p, path, dirent.name);
-            }
-        }
-
-        apr_dir_close(dirp);
-        if (candidates->nelts != 0) {
-            const char *error;
-
-            qsort((void *) candidates->elts, candidates->nelts,
-                  sizeof(fnames), fname_alphasort);
+        /* walk the filepath */
+        return process_resource_config_fnmatch(s, rootpath, filepath, conftree, p, ptemp,
+                                                 0);
 
-            /*
-             * Now recurse these... we handle errors and subdirectories
-             * via the recursion, which is nice
-             */
-            for (current = 0; current < candidates->nelts; ++current) {
-                fnew = &((fnames *) candidates->elts)[current];
-                error = process_resource_config_nofnmatch(s, fnew->fname,
-                                                          conftree, p,
-                                                          ptemp, 0);
-                if (error) {
-                    return error;
-                }
-            }
-        }
     }
 
     return NULL;





git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x@928928 13f79535-47bb-0310-9956-ffa450edef68
parent 96276280
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment