]> granicus.if.org Git - apache/commitdiff
Merge r1554300, r1554301, r1554994, r1555266 from trunk:
authorJim Jagielski <jim@apache.org>
Sun, 5 Jan 2014 16:14:26 +0000 (16:14 +0000)
committerJim Jagielski <jim@apache.org>
Sun, 5 Jan 2014 16:14:26 +0000 (16:14 +0000)
core: Support named groups and backreferences within the LocationMatch,
DirectoryMatch, FilesMatch and ProxyMatch directives.

Documentation for the support of named groups and backreferences.

c89 fix

Add a "MATCH_" prefix to variables set within
LocationMatch/DirectoryMatch/FilesMatch.

Submitted by: minfrin, covener, minfrin
Reviewed/backported by: jim

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/2.4.x@1555551 13f79535-47bb-0310-9956-ffa450edef68

12 files changed:
STATUS
docs/manual/mod/core.xml
docs/manual/mod/mod_proxy.xml
docs/manual/sections.xml
include/ap_mmn.h
include/ap_regex.h
include/http_core.h
modules/proxy/mod_proxy.c
modules/proxy/mod_proxy.h
server/core.c
server/request.c
server/util_pcre.c

diff --git a/STATUS b/STATUS
index 158d4e17bfccf491df0852ee51120773c95aff39..c4e874f0a5722a3a7ed3d52d3f60fc95832865af 100644 (file)
--- a/STATUS
+++ b/STATUS
@@ -98,15 +98,6 @@ RELEASE SHOWSTOPPERS:
 PATCHES ACCEPTED TO BACKPORT FROM TRUNK:
   [ start all new proposals below, under PATCHES PROPOSED. ]
 
-  * core: Support named groups and backreferences within the LocationMatch,
-    DirectoryMatch, FilesMatch and ProxyMatch directives.
-    trunk patch: http://svn.apache.org/r1554300
-                 http://svn.apache.org/r1554301
-                 http://svn.apache.org/r1554994
-                 http://svn.apache.org/r1555266
-    2.4.x patch: http://people.apache.org/~minfrin/httpd-match-backref7.patch
-    +1: minfrin, covener, jim
-
   * mod_proxy: Remove <Proxy ~ wildcard-url> syntax 
     trunk patch: http://svn.apache.org/r1552227
     2.4.x patch: trunk works, except for CHANGES
index e16a009367e59374cb828578d9a4413aa14dc9c0..315a3b5f965d6d2556b011a8af8b4c7f892982a2 100644 (file)
@@ -880,6 +880,19 @@ the contents of file-system directories matching a regular expression.</descript
       not end in a trailing slash, so expressions that are anchored to the
       end of line ($) must be written with care.
     </note>
+
+    <p>From 2.5.0 onwards, named groups and backreferences are captured and
+    written to the environment with the corresponding name prefixed with
+    "MATCH_" and in upper case. This allows elements of paths to be referenced
+    from within <a href="expr.html">expressions</a> and modules like
+    <module>mod_rewrite</module>. In order to prevent confusion, numbered
+    (unnamed) backreferences are ignored. Use named groups instead.</p>
+
+<highlight language="config">
+&lt;DirectoryMatch ^/var/www/combined/(?&lt;sitename&gt;[^/]+)&gt;
+    require ldap-group cn=%{env:MATCH_SITENAME},ou=combined,o=Example
+&lt;/DirectoryMatch&gt;
+</highlight>
 </usage>
 <seealso><directive type="section" module="core">Directory</directive> for
 a description of how regular expressions are mixed in with normal
@@ -1727,6 +1740,19 @@ filenames</description>
 </highlight>
 
     <p>would match most common Internet graphics formats.</p>
+
+    <p>From 2.5.0 onwards, named groups and backreferences are captured and
+    written to the environment with the corresponding name prefixed with
+    "MATCH_" and in upper case. This allows elements of files to be referenced
+    from within <a href="expr.html">expressions</a> and modules like
+    <module>mod_rewrite</module>. In order to prevent confusion, numbered
+    (unnamed) backreferences are ignored. Use named groups instead.</p>
+
+<highlight language="config">
+&lt;FileMatch ^(?&lt;sitename&gt;[^/]+)&gt;
+    require ldap-group cn=%{env:MATCH_SITENAME},ou=combined,o=Example
+&lt;/FileMatch&gt;
+</highlight>
 </usage>
 
 <seealso><a href="../sections.html">How &lt;Directory&gt;, &lt;Location&gt;
@@ -2682,6 +2708,19 @@ matching URLs</description>
 
     <p>would match URLs that contained the substring <code>/extra/data</code>
     or <code>/special/data</code>.</p>
+
+    <p>From 2.5.0 onwards, named groups and backreferences are captured and
+    written to the environment with the corresponding name prefixed with
+    "MATCH_" and in upper case. This allows elements of URLs to be referenced
+    from within <a href="expr.html">expressions</a> and modules like
+    <module>mod_rewrite</module>. In order to prevent confusion, numbered
+    (unnamed) backreferences are ignored. Use named groups instead.</p>
+
+<highlight language="config">
+&lt;LocationMatch ^/combined/(?&lt;sitename&gt;[^/]+)&gt;
+    require ldap-group cn=%{env:MATCH_SITENAME},ou=combined,o=Example
+&lt;/LocationMatch&gt;
+</highlight>
 </usage>
 
 <seealso><a href="../sections.html">How &lt;Directory&gt;, &lt;Location&gt;
index 0cdbc47231eedbb03044cc53f7954912ecde35d1..f043cb328c4b711a41253d3eee02bdf626e1af69 100644 (file)
@@ -514,6 +514,19 @@ proxied resources</description>
     identical to the <directive module="mod_proxy"
     type="section">Proxy</directive> directive, except it matches URLs
     using <glossary ref="regex">regular expressions</glossary>.</p>
+
+    <p>From 2.5.0 onwards, named groups and backreferences are captured and
+    written to the environment with the corresponding name prefixed with
+    "MATCH_" and in upper case. This allows elements of URLs to be referenced
+    from within <a href="expr.html">expressions</a> and modules like
+    <module>mod_rewrite</module>. In order to prevent confusion, numbered
+    (unnamed) backreferences are ignored. Use named groups instead.</p>
+
+<highlight language="config">
+&lt;ProxyMatch ^http://(?&lt;sitename&gt;[^/]+)&gt;
+    require ldap-group cn=%{env:MATCH_SITENAME},ou=combined,o=Example
+&lt;/ProxyMatch&gt;
+</highlight>
 </usage>
 <seealso><directive type="section" module="mod_proxy">Proxy</directive></seealso>
 </directivesynopsis>
index b3c93b75746e8c3ac753a7bb9150863bd952d78e..76eeb53d32a5900367be3eba3e2acacbe690c146 100644 (file)
@@ -296,6 +296,18 @@ at once:</p>
 &lt;/FilesMatch&gt;
 </highlight>
 
+<p>Regular expressions containing <strong>named groups and
+backreferences</strong> are added to the environment with the
+corresponding name in uppercase. This allows elements of filename paths
+and URLs to be referenced from within <a href="expr.html">expressions</a>
+and modules like <module>mod_rewrite</module>.</p>
+
+<highlight language="config">
+&lt;DirectoryMatch ^/var/www/combined/(?&lt;SITENAME&gt;[^/]+)&gt;
+    require ldap-group cn=%{env:SITENAME},ou=combined,o=Example
+&lt;/DirectoryMatch&gt;
+</highlight>
+
 </section>
 
 <section id="expressions"><title>Boolean expressions</title>
index 965483f0ea218f6c859efe087e00d30d4fafb1a6..115e769fd7ca48cb11887aa84a147f1589cc6f46 100644 (file)
  * 20120211.25 (2.4.7-dev) Add conn_sense_e
  * 20120211.26 (2.4.7-dev) Add util_fcgi.h, FastCGI protocol support
  * 20120211.27 (2.4.7-dev) Add ap_podx_restart_t and ap_mpm_podx_*
+ * 20120211.28 (2.4.7-dev) Add ap_regname
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503234UL /* "AP24" */
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20120211
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 27                   /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 28                   /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a
index 5122154d90f4b11de43c666b8f9797e3ab7ebe4a..be41226beef768d5702d641bfed04389db4f0b0f 100644 (file)
@@ -77,6 +77,8 @@ extern "C" {
 #define AP_REG_NOMEM 0x20    /* nomem in our code */
 #define AP_REG_DOTALL 0x40   /* perl's /s flag */
 
+#define AP_REG_MATCH "MATCH_" /** suggested prefix for ap_regname */
+
 /* Error values: */
 enum {
   AP_REG_ASSERT = 1,  /** internal error ? */
@@ -149,6 +151,16 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff,
 AP_DECLARE(apr_size_t) ap_regerror(int errcode, const ap_regex_t *preg,
                                    char *errbuf, apr_size_t errbuf_size);
 
+/**
+ * Return an array of named regex backreferences
+ * @param preg The precompiled regex
+ * @param names The array to which the names will be added
+ * @param upper If non zero, uppercase the names
+ */
+AP_DECLARE(int) ap_regname(const ap_regex_t *preg,
+                           apr_array_header_t *names, const char *prefix,
+                           int upper);
+
 /** Destroy a pre-compiled regex.
  * @param preg The pre-compiled regex to free.
  */
index 3c47989cb43ae971dc3b8baaec91368a5422b3c7..8730d1fde94269d39cb502b9d502afc22f833fb5 100644 (file)
@@ -617,6 +617,10 @@ typedef struct {
     /** Max number of Range reversals (eg: 200-300, 100-125) allowed **/
     int max_reversals;
 
+
+    /** Named back references */
+    apr_array_header_t *refs;
+
 } core_dir_config;
 
 /* macro to implement off by default behaviour */
index 88ddb899890eb550ab49c3fac95f98676ec14431..f2f3a8de74470565a955be7bbec9648c05d7e887 100644 (file)
@@ -744,22 +744,52 @@ static int proxy_walk(request_rec *r)
      */
     const char *proxyname = r->filename + 6;
     int j;
+    apr_pool_t *rxpool = NULL;
 
     for (j = 0; j < num_sec; ++j)
     {
+        int nmatch = 0;
+        int i;
+        ap_regmatch_t *pmatch = NULL;
+
         entry_config = sec_proxy[j];
         entry_proxy = ap_get_module_config(entry_config, &proxy_module);
 
-        /* XXX: What about case insensitive matching ???
-         * Compare regex, fnmatch or string as appropriate
-         * If the entry doesn't relate, then continue
-         */
-        if (entry_proxy->r
-              ? ap_regexec(entry_proxy->r, proxyname, 0, NULL, 0)
-              : (entry_proxy->p_is_fnmatch
-                   ? apr_fnmatch(entry_proxy->p, proxyname, 0)
-                   : strncmp(proxyname, entry_proxy->p,
-                                        strlen(entry_proxy->p)))) {
+        if (entry_proxy->r) {
+
+            if (entry_proxy->refs && entry_proxy->refs->nelts) {
+                if (!rxpool) {
+                    apr_pool_create(&rxpool, r->pool);
+                }
+                nmatch = entry_proxy->refs->nelts;
+                pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
+            }
+
+            if (ap_regexec(entry_proxy->r, proxyname, nmatch, pmatch, 0)) {
+                continue;
+            }
+
+            for (i = 0; i < nmatch; i++) {
+                if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 &&
+                        ((const char **)entry_proxy->refs->elts)[i]) {
+                    apr_table_setn(r->subprocess_env,
+                            ((const char **)entry_proxy->refs->elts)[i],
+                            apr_pstrndup(r->pool,
+                                    proxyname + pmatch[i].rm_so,
+                                    pmatch[i].rm_eo - pmatch[i].rm_so));
+                }
+            }
+        }
+
+        else if (
+            /* XXX: What about case insensitive matching ???
+             * Compare regex, fnmatch or string as appropriate
+             * If the entry doesn't relate, then continue
+             */
+            entry_proxy->p_is_fnmatch ? apr_fnmatch(entry_proxy->p,
+                    proxyname, 0) :
+                    strncmp(proxyname, entry_proxy->p,
+                            strlen(entry_proxy->p))) {
             continue;
         }
         per_dir_defaults = ap_merge_per_dir_configs(r->pool, per_dir_defaults,
@@ -768,6 +798,10 @@ static int proxy_walk(request_rec *r)
 
     r->per_dir_config = per_dir_defaults;
 
+    if (rxpool) {
+        apr_pool_destroy(rxpool);
+    }
+
     return OK;
 }
 
@@ -1314,6 +1348,7 @@ static void *merge_proxy_dir_config(apr_pool_t *p, void *basev, void *addv)
     new->p = add->p;
     new->p_is_fnmatch = add->p_is_fnmatch;
     new->r = add->r;
+    new->refs = add->refs;
 
     /* Put these in the dir config so they work inside <Location> */
     new->raliases = apr_array_append(p, base->raliases, add->raliases);
@@ -2220,6 +2255,11 @@ static const char *proxysection(cmd_parms *cmd, void *mconfig, const char *arg)
     conf->p = cmd->path;
     conf->p_is_fnmatch = apr_fnmatch_test(conf->p);
 
+    if (r) {
+        conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
+        ap_regname(r, conf->refs, AP_REG_MATCH, 1);
+    }
+
     ap_add_per_proxy_conf(cmd->server, new_dir_conf);
 
     if (*arg != '\0') {
index aef8b2097471269e92e0443fb1853a0162bec351..0afa8543f516e0336a5b94eed5c87e1a20dfbd4a 100644 (file)
@@ -219,6 +219,10 @@ typedef struct {
     unsigned int error_override_set:1;
     unsigned int alias_set:1;
     unsigned int add_forwarded_headers:1;
+
+    /** Named back references */
+    apr_array_header_t *refs;
+
 } proxy_dir_conf;
 
 /* if we interpolate env vars per-request, we'll need a per-request
index 936bf47fc3655a64d242d835600ab28087d2d072..da895ab0346d7bc9e3833f49412c830863e58488 100644 (file)
@@ -209,6 +209,7 @@ static void *merge_core_dir_configs(apr_pool_t *a, void *basev, void *newv)
     conf->d_is_fnmatch = new->d_is_fnmatch;
     conf->d_components = new->d_components;
     conf->r = new->r;
+    conf->refs = new->refs;
     conf->condition = new->condition;
 
     if (new->opts & OPT_UNSET) {
@@ -2159,6 +2160,11 @@ static const char *dirsection(cmd_parms *cmd, void *mconfig, const char *arg)
     conf->d = cmd->path;
     conf->d_is_fnmatch = (apr_fnmatch_test(conf->d) != 0);
 
+    if (r) {
+        conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
+        ap_regname(r, conf->refs, AP_REG_MATCH, 1);
+    }
+
     /* Make this explicit - the "/" root has 0 elements, that is, we
      * will always merge it, and it will always sort and merge first.
      * All others are sorted and tested by the number of slashes.
@@ -2235,6 +2241,11 @@ static const char *urlsection(cmd_parms *cmd, void *mconfig, const char *arg)
     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
     conf->r = r;
 
+    if (r) {
+        conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
+        ap_regname(r, conf->refs, AP_REG_MATCH, 1);
+    }
+
     ap_add_per_url_conf(cmd->server, new_url_conf);
 
     if (*arg != '\0') {
@@ -2317,6 +2328,11 @@ static const char *filesection(cmd_parms *cmd, void *mconfig, const char *arg)
     conf->d_is_fnmatch = apr_fnmatch_test(conf->d) != 0;
     conf->r = r;
 
+    if (r) {
+        conf->refs = apr_array_make(cmd->pool, 8, sizeof(char *));
+        ap_regname(r, conf->refs, AP_REG_MATCH, 1);
+    }
+
     ap_add_file_conf(cmd->pool, (core_dir_config *)mconfig, new_file_conf);
 
     if (*arg != '\0') {
index 1f4d99270ce56868a4f31d07f63da0ae892b1c9f..af0a697a9f42b4e41d3eb1a47b3308cdda4bcd66 100644 (file)
@@ -737,6 +737,7 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r)
         apr_size_t buflen;
         char *buf;
         unsigned int seg, startseg;
+        apr_pool_t *rxpool = NULL;
 
         /* Invariant: from the first time filename_len is set until
          * it goes out of scope, filename_len==strlen(r->filename)
@@ -1192,6 +1193,10 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r)
          */
         for (; sec_idx < num_sec; ++sec_idx) {
 
+            int nmatch = 0;
+            int i;
+            ap_regmatch_t *pmatch = NULL;
+
             core_dir_config *entry_core;
             entry_core = ap_get_core_module_config(sec_ent[sec_idx]);
 
@@ -1199,10 +1204,29 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r)
                 continue;
             }
 
-            if (ap_regexec(entry_core->r, r->filename, 0, NULL, 0)) {
+            if (entry_core->refs && entry_core->refs->nelts) {
+                if (!rxpool) {
+                    apr_pool_create(&rxpool, r->pool);
+                }
+                nmatch = entry_core->refs->nelts;
+                pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
+            }
+
+            if (ap_regexec(entry_core->r, r->filename, nmatch, pmatch, 0)) {
                 continue;
             }
 
+            for (i = 0; i < nmatch; i++) {
+                if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 &&
+                    ((const char **)entry_core->refs->elts)[i]) {
+                    apr_table_setn(r->subprocess_env, 
+                                   ((const char **)entry_core->refs->elts)[i],
+                                   apr_pstrndup(r->pool,
+                                   r->filename + pmatch[i].rm_so,
+                                   pmatch[i].rm_eo - pmatch[i].rm_so));
+                }
+            }
+
             /* If we haven't already continue'd above, we have a match.
              *
              * Calculate our full-context core opts & override.
@@ -1241,6 +1265,10 @@ AP_DECLARE(int) ap_directory_walk(request_rec *r)
             last_walk->merged = now_merged;
         }
 
+        if (rxpool) {
+            apr_pool_destroy(rxpool);
+        }
+
         /* Whoops - everything matched in sequence, but either the original
          * walk found some additional matches (which we need to truncate), or
          * this walk found some additional matches.
@@ -1378,6 +1406,7 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
         int matches = cache->walked->nelts;
         int cached_matches = matches;
         walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts;
+        apr_pool_t *rxpool = NULL;
 
         cached &= auth_internal_per_conf;
         cache->cached = entry_uri;
@@ -1399,16 +1428,48 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
              * not slash terminated, then this uri must be slash
              * terminated (or at the end of the string) to match.
              */
-            if (entry_core->r
-                ? ap_regexec(entry_core->r, r->uri, 0, NULL, 0)
-                : (entry_core->d_is_fnmatch
+            if (entry_core->r) {
+
+                int nmatch = 0;
+                int i;
+                ap_regmatch_t *pmatch = NULL;
+
+                if (entry_core->refs && entry_core->refs->nelts) {
+                    if (!rxpool) {
+                        apr_pool_create(&rxpool, r->pool);
+                    }
+                    nmatch = entry_core->refs->nelts;
+                    pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
+                }
+
+                if (ap_regexec(entry_core->r, r->uri, nmatch, pmatch, 0)) {
+                    continue;
+                }
+
+                for (i = 0; i < nmatch; i++) {
+                    if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && 
+                        ((const char **)entry_core->refs->elts)[i]) {
+                        apr_table_setn(r->subprocess_env,
+                                       ((const char **)entry_core->refs->elts)[i],
+                                       apr_pstrndup(r->pool,
+                                       r->uri + pmatch[i].rm_so,
+                                       pmatch[i].rm_eo - pmatch[i].rm_so));
+                    }
+                }
+
+            }
+            else {
+
+                if ((entry_core->d_is_fnmatch
                    ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME)
                    : (strncmp(entry_core->d, cache->cached, len)
                       || (len > 0
                           && entry_core->d[len - 1] != '/'
                           && cache->cached[len] != '/'
                           && cache->cached[len] != '\0')))) {
-                continue;
+                    continue;
+                }
+
             }
 
             /* If we merged this same section last time, reuse it
@@ -1443,6 +1504,10 @@ AP_DECLARE(int) ap_location_walk(request_rec *r)
             last_walk->merged = now_merged;
         }
 
+        if (rxpool) {
+            apr_pool_destroy(rxpool);
+        }
+
         /* Whoops - everything matched in sequence, but either the original
          * walk found some additional matches (which we need to truncate), or
          * this walk found some additional matches.
@@ -1552,6 +1617,7 @@ AP_DECLARE(int) ap_file_walk(request_rec *r)
         int matches = cache->walked->nelts;
         int cached_matches = matches;
         walk_walked_t *last_walk = (walk_walked_t*)cache->walked->elts;
+        apr_pool_t *rxpool = NULL;
 
         cached &= auth_internal_per_conf;
         cache->cached = test_file;
@@ -1564,12 +1630,42 @@ AP_DECLARE(int) ap_file_walk(request_rec *r)
             core_dir_config *entry_core;
             entry_core = ap_get_core_module_config(sec_ent[sec_idx]);
 
-            if (entry_core->r
-                ? ap_regexec(entry_core->r, cache->cached , 0, NULL, 0)
-                : (entry_core->d_is_fnmatch
-                   ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME)
-                   : strcmp(entry_core->d, cache->cached))) {
-                continue;
+            if (entry_core->r) {
+
+                int nmatch = 0;
+                int i;
+                ap_regmatch_t *pmatch = NULL;
+
+                if (entry_core->refs && entry_core->refs->nelts) {
+                    if (!rxpool) {
+                        apr_pool_create(&rxpool, r->pool);
+                    }
+                    nmatch = entry_core->refs->nelts;
+                    pmatch = apr_palloc(rxpool, nmatch*sizeof(ap_regmatch_t));
+                }
+
+                if (ap_regexec(entry_core->r, cache->cached, nmatch, pmatch, 0)) {
+                    continue;
+                }
+
+                for (i = 0; i < nmatch; i++) {
+                    if (pmatch[i].rm_so >= 0 && pmatch[i].rm_eo >= 0 && 
+                        ((const char **)entry_core->refs->elts)[i]) {
+                        apr_table_setn(r->subprocess_env,
+                                       ((const char **)entry_core->refs->elts)[i],
+                                       apr_pstrndup(r->pool,
+                                       cache->cached + pmatch[i].rm_so,
+                                       pmatch[i].rm_eo - pmatch[i].rm_so));
+                    }
+                }
+
+            }
+            else {
+                if ((entry_core->d_is_fnmatch
+                       ? apr_fnmatch(entry_core->d, cache->cached, APR_FNM_PATHNAME)
+                       : strcmp(entry_core->d, cache->cached))) {
+                    continue;
+                }
             }
 
             /* If we merged this same section last time, reuse it
@@ -1604,6 +1700,10 @@ AP_DECLARE(int) ap_file_walk(request_rec *r)
             last_walk->merged = now_merged;
         }
 
+        if (rxpool) {
+            apr_pool_destroy(rxpool);
+        }
+
         /* Whoops - everything matched in sequence, but either the original
          * walk found some additional matches (which we need to truncate), or
          * this walk found some additional matches.
index 1e83cad080591c96f89f0c3f6e2941db968e301a..4d2adef25b67d20f430a568808d2d5eca5ccbd5c 100644 (file)
@@ -45,6 +45,7 @@ POSSIBILITY OF SUCH DAMAGE.
 
 #include "httpd.h"
 #include "apr_strings.h"
+#include "apr_tables.h"
 #include "pcre.h"
 
 #define APR_WANT_STRFUNC
@@ -124,7 +125,7 @@ AP_DECLARE(int) ap_regcomp(ap_regex_t * preg, const char *pattern, int cflags)
     const char *errorptr;
     int erroffset;
     int errcode = 0;
-    int options = 0;
+    int options = PCRE_DUPNAMES;
 
     if ((cflags & AP_REG_ICASE) != 0)
         options |= PCRE_CASELESS;
@@ -256,4 +257,43 @@ AP_DECLARE(int) ap_regexec_len(const ap_regex_t *preg, const char *buff,
     }
 }
 
+AP_DECLARE(int) ap_regname(const ap_regex_t *preg,
+                           apr_array_header_t *names, const char *prefix,
+                           int upper)
+{
+    int namecount;
+    int nameentrysize;
+    int i;
+    char *nametable;
+
+    pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
+                       PCRE_INFO_NAMECOUNT, &namecount);
+    pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
+                       PCRE_INFO_NAMEENTRYSIZE, &nameentrysize);
+    pcre_fullinfo((const pcre *)preg->re_pcre, NULL,
+                       PCRE_INFO_NAMETABLE, &nametable);
+
+    for (i = 0; i < namecount; i++) {
+        const char *offset = nametable + i * nameentrysize;
+        int capture = ((offset[0] << 8) + offset[1]);
+        while (names->nelts <= capture) {
+            apr_array_push(names);
+        }
+        if (upper || prefix) {
+            char *name = ((char **) names->elts)[capture] =
+                    prefix ? apr_pstrcat(names->pool, prefix, offset + 2,
+                            NULL) :
+                            apr_pstrdup(names->pool, offset + 2);
+            if (upper) {
+                ap_str_toupper(name);
+            }
+        }
+        else {
+            ((const char **)names->elts)[capture] = offset + 2;
+        }
+    }
+
+    return namecount;
+}
+
 /* End of pcreposix.c */