Index: docs/manual/mod/core.xml =================================================================== --- docs/manual/mod/core.xml (revision 909869) +++ docs/manual/mod/core.xml (working copy) @@ -1541,24 +1541,34 @@ server configvirtual host directory -Wildcard matching available in 2.0.41 and later +Wildcard matching available in 2.0.41 and later, directory +wildcard matching available in 2.3.6 and later

This directive allows inclusion of other configuration files from within the server configuration files.

Shell-style (fnmatch()) 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 Include 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 httpd 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.

+ in the filename or directory parts of the path to include several files + at once, in alphabetical order. In addition, if + Include 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 + httpd 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.

+

When a wildcard is specified for a file or directory component of the + path, and no file or directory matches the wildcard, the + Include 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, + Include 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.

+

The file path specified may be an absolute path, or may be relative to the ServerRoot directory.

@@ -1576,6 +1586,15 @@ Include conf/ssl.conf
Include conf/vhosts/*.conf + +

Wildcards may be included in the directory or file portion of the + path:

+ + + Include conf/vhosts/*/vhost.conf + Include conf/vhosts/*/*.conf + +
apachectl Index: server/config.c =================================================================== --- server/config.c (revision 909869) +++ server/config.c (working copy) @@ -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; + apr_status_t status; + const char *rootpath, *filepath = fname; - pattern = ap_strrchr(path, '/'); + /* locate the start of the directories proper */ + status = apr_filepath_root(&rootpath, &filepath, APR_FILEPATH_TRUENAME, ptemp); - AP_DEBUG_ASSERT(pattern != NULL); /* path must be absolute. */ - - *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); - } + /* walk the filepath */ + return process_resource_config_fnmatch(s, rootpath, filepath, 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, 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); - - /* - * 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;