summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
authorJim Jagielski <jim@apache.org>2014-01-05 16:14:26 +0000
committerJim Jagielski <jim@apache.org>2014-01-05 16:14:26 +0000
commit858b4b4cbe770fd771d3906143aa27cf667f61e1 (patch)
tree0e942fc5c7c111ee8e4ed18a7742bc2ca05db0fd /server
parent38856d02536cc9d5d528cfba4f2e5e43bcf02511 (diff)
downloadhttpd-858b4b4cbe770fd771d3906143aa27cf667f61e1.tar.gz
Merge r1554300, r1554301, r1554994, r1555266 from trunk:
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
Diffstat (limited to 'server')
-rw-r--r--server/core.c16
-rw-r--r--server/request.c122
-rw-r--r--server/util_pcre.c42
3 files changed, 168 insertions, 12 deletions
diff --git a/server/core.c b/server/core.c
index 936bf47fc3..da895ab034 100644
--- a/server/core.c
+++ b/server/core.c
@@ -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') {
diff --git a/server/request.c b/server/request.c
index 1f4d99270c..af0a697a9f 100644
--- a/server/request.c
+++ b/server/request.c
@@ -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.
diff --git a/server/util_pcre.c b/server/util_pcre.c
index 1e83cad080..4d2adef25b 100644
--- a/server/util_pcre.c
+++ b/server/util_pcre.c
@@ -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 */