You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by mi...@apache.org on 2010/02/13 20:48:04 UTC

svn commit: r909878 - in /httpd/httpd/trunk: CHANGES docs/manual/mod/core.xml server/config.c

Author: minfrin
Date: Sat Feb 13 19:48:04 2010
New Revision: 909878

URL: http://svn.apache.org/viewvc?rev=909878&view=rev
Log:
Support wildcards in both the directory and file components of
the path specified by the Include directive.

Modified:
    httpd/httpd/trunk/CHANGES
    httpd/httpd/trunk/docs/manual/mod/core.xml
    httpd/httpd/trunk/server/config.c

Modified: httpd/httpd/trunk/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/CHANGES?rev=909878&r1=909877&r2=909878&view=diff
==============================================================================
--- httpd/httpd/trunk/CHANGES [utf-8] (original)
+++ httpd/httpd/trunk/CHANGES [utf-8] Sat Feb 13 19:48:04 2010
@@ -2,6 +2,9 @@
 
 Changes with Apache 2.3.7
 
+  *) Support wildcards in both the directory and file components of
+     the path specified by the Include directive. [Graham Leggett]
+
   *) mod_proxy, mod_proxy_http: Support remote https proxies
      by using HTTP CONNECT.
      PR 19188.  [Philippe Dutrueux <lilas evidian.com>, Rainer Jung]

Modified: httpd/httpd/trunk/docs/manual/mod/core.xml
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/docs/manual/mod/core.xml?rev=909878&r1=909877&r2=909878&view=diff
==============================================================================
--- httpd/httpd/trunk/docs/manual/mod/core.xml (original)
+++ httpd/httpd/trunk/docs/manual/mod/core.xml Sat Feb 13 19:48:04 2010
@@ -1541,23 +1541,33 @@
 <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
-    in the filename part of the path (not the directory part) 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>
+    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>
@@ -1576,6 +1586,15 @@
       Include conf/ssl.conf<br />
       Include conf/vhosts/*.conf
     </example>
+
+    <p>Wildcards may be included in the directory or file portion of the
+    path:</p>
+  
+    <example>
+      Include conf/vhosts/*/vhost.conf
+      Include conf/vhosts/*/*.conf
+    </example>
+
 </usage>
 
 <seealso><program>apachectl</program></seealso>

Modified: httpd/httpd/trunk/server/config.c
URL: http://svn.apache.org/viewvc/httpd/httpd/trunk/server/config.c?rev=909878&r1=909877&r2=909878&view=diff
==============================================================================
--- httpd/httpd/trunk/server/config.c (original)
+++ httpd/httpd/trunk/server/config.c Sat Feb 13 19:48:04 2010
@@ -1653,6 +1653,100 @@
     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, dirp) == APR_SUCCESS) {
+        /* strip out '.' and '..' */
+        if (strcmp(dirent.name, ".")
+            && strcmp(dirent.name, "..")
+            && (apr_fnmatch(fname, dirent.name,
+                            APR_FNM_PERIOD) == APR_SUCCESS)) {
+            fnew = (fnames *) apr_array_push(candidates);
+            fnew->fname = ap_make_full_path(ptemp, path, dirent.name);
+        }
+    }
+
+    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,
@@ -1677,80 +1771,24 @@
                                                  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, '/');
-
-        AP_DEBUG_ASSERT(pattern != NULL); /* path must be absolute. */
+        apr_status_t status;
+        const char *rootpath, *filepath = fname;
 
-        *pattern++ = '\0';
-
-        if (apr_fnmatch_test(path)) {
-            return apr_pstrcat(p, "Wildcard patterns not allowed in Include ",
-                               fname, NULL);
-        }
+        /* locate the start of the directories proper */
+        status = apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME, ptemp);
 
-        if (!ap_is_directory(p, path)){
-            return apr_pstrcat(p, "Include directory '", path, "' not found",
-                               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 (!apr_fnmatch_test(pattern)) {
-            return apr_pstrcat(p, "Must include a wildcard pattern for "
-                               "Include ", fname, NULL);
+        else if (APR_EBADPATH == status) {
+            return apr_pstrcat(p, "Include has a bad path, ", 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);
-            }
-        }
+        /* walk the filepath */
+        return process_resource_config_fnmatch(s, rootpath, filepath, conftree, p, ptemp,
+                                                 0);
 
-        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];
-                error = process_resource_config_nofnmatch(s, fnew->fname,
-                                                          conftree, p,
-                                                          ptemp, 0);
-                if (error) {
-                    return error;
-                }
-            }
-        }
     }
 
     return NULL;