#if (NGX_PCRE)
|| clcf->regex
#endif
+ || clcf->predicate
|| clcf->noname)
{
if (plcf->vars.uri.len) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"proxy_pass\" cannot have URI part in "
"location given by regular expression, "
+ "or inside predicate location, "
"or inside named location, "
"or inside \"if\" statement, "
"or inside \"limit_except\" block");
ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
ngx_http_core_loc_conf_t *pclcf)
{
- ngx_uint_t n;
- ngx_queue_t *q, *locations, *named, tail;
+ ngx_uint_t n, p;
+ ngx_queue_t *q, *locations, *named, *predicate, tail;
ngx_http_core_loc_conf_t *clcf;
ngx_http_location_queue_t *lq;
ngx_http_core_loc_conf_t **clcfp;
regex = NULL;
r = 0;
#endif
+ predicate = NULL;
+ p = 0;
for (q = ngx_queue_head(locations);
q != ngx_queue_sentinel(locations);
#endif
+ if (clcf->predicate) {
+ p++;
+
+ if (predicate == NULL) {
+ predicate = q;
+ }
+
+ continue;
+ }
+
if (clcf->named) {
n++;
ngx_queue_split(locations, named, &tail);
}
+ if (predicate) {
+ clcfp = ngx_palloc(cf->pool,
+ (p + 1) * sizeof(ngx_http_core_loc_conf_t *));
+ if (clcfp == NULL) {
+ return NGX_ERROR;
+ }
+
+ pclcf->predicate_locations = clcfp;
+
+ for (q = predicate;
+ q != ngx_queue_sentinel(locations);
+ q = ngx_queue_next(q))
+ {
+ lq = (ngx_http_location_queue_t *) q;
+
+ *(clcfp++) = lq->exact;
+ }
+
+ *clcfp = NULL;
+
+ ngx_queue_split(locations, predicate, &tail);
+ }
+
#if (NGX_PCRE)
if (regex) {
ngx_http_core_loc_conf_t *pclcf)
{
ngx_queue_t *q, *locations;
- ngx_http_core_loc_conf_t *clcf;
+ ngx_http_core_loc_conf_t *clcf, **clcfp;
ngx_http_location_queue_t *lq;
+ if (pclcf->predicate_locations) {
+ for (clcfp = pclcf->predicate_locations; *clcfp; clcfp++) {
+ if (ngx_http_init_static_location_trees(cf, *clcfp) != NGX_OK) {
+ return NGX_ERROR;
+ }
+ }
+ }
+
locations = pclcf->locations;
if (locations == NULL) {
#if (NGX_PCRE)
|| clcf->regex
#endif
- || clcf->named || clcf->noname)
+ || clcf->predicate || clcf->named || clcf->noname)
{
lq->exact = clcf;
lq->inclusive = NULL;
return ngx_strcmp(first->name.data, second->name.data);
}
+ if (first->predicate && !second->predicate) {
+ /* shift predicate locations to the end */
+ return 1;
+ }
+
+ if (!first->predicate && second->predicate) {
+ /* shift predicate locations to the end */
+ return -1;
+ }
+
+ if (first->predicate || second->predicate) {
+ /* do not sort the predicate locations */
+ return 0;
+ }
+
#if (NGX_PCRE)
if (first->regex && !second->regex) {
/*
- * NGX_OK - exact or regex match
+ * NGX_OK - exact, regex or predicate match
* NGX_DONE - auto redirect
* NGX_AGAIN - inclusive match
- * NGX_ERROR - regex error
+ * NGX_ERROR - regex or predicate error
* NGX_DECLINED - no match
*/
static ngx_int_t
ngx_http_core_find_location(ngx_http_request_t *r)
{
- ngx_int_t rc;
- ngx_http_core_loc_conf_t *pclcf;
+ ngx_int_t rc;
+ ngx_uint_t noregex;
+ ngx_http_core_loc_conf_t *clcf, *pclcf, **clcfp;
+ ngx_http_variable_value_t *vv;
#if (NGX_PCRE)
- ngx_int_t n;
- ngx_uint_t noregex;
- ngx_http_core_loc_conf_t *clcf, **clcfp;
+ ngx_int_t n;
+#endif
noregex = 0;
-#endif
pclcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (rc == NGX_AGAIN) {
-#if (NGX_PCRE)
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
noregex = clcf->noregex;
-#endif
/* look up nested locations */
}
#endif
+ if (noregex == 0 && pclcf->predicate_locations) {
+
+ for (clcfp = pclcf->predicate_locations; *clcfp; clcfp++) {
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "test location: \"%V\"", &(*clcfp)->name);
+
+ vv = ngx_http_get_flushed_variable(r, (*clcfp)->predicate - 1);
+
+ if (vv && vv->len && (vv->len != 1 || vv->data[0] != '0')) {
+ r->loc_conf = (*clcfp)->loc_conf;
+
+ /* look up nested locations */
+
+ rc = ngx_http_core_find_location(r);
+
+ return (rc == NGX_ERROR || rc == NGX_DONE) ? rc : NGX_OK;
+ }
+ }
+ }
+
return rc;
}
u_char *mod;
size_t len;
ngx_str_t *value, *name;
+ ngx_int_t index;
ngx_uint_t i;
ngx_conf_t save;
ngx_http_module_t *module;
}
}
+ } else if (name->data[0] == '$') {
+
+ clcf->name = *name;
+
+ name->len--;
+ name->data++;
+
+ index = ngx_http_get_variable_index(cf, name);
+ if (index == NGX_ERROR) {
+ return NGX_CONF_ERROR;
+ }
+
+ clcf->predicate = index + 1;
+
} else {
clcf->name = *name;
len = pclcf->name.len;
+ if (!clcf->predicate && !pclcf->predicate
#if (NGX_PCRE)
- if (clcf->regex == NULL
- && ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
-#else
- if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
+ && clcf->regex == NULL
#endif
+ && ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"location \"%V\" is outside location \"%V\"",
* clcf->error_pages = NULL;
* clcf->client_body_path = NULL;
* clcf->regex = NULL;
+ * clcf->predicate = 0;
* clcf->exact_match = 0;
* clcf->auto_redirect = 0;
* clcf->alias = 0;
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.variables = n;
+ if (alias
+ && (clcf->predicate
#if (NGX_PCRE)
- if (alias && clcf->regex) {
+ || clcf->regex
+#endif
+ ))
+ {
clcf->alias = NGX_MAX_SIZE_T_VALUE;
n = 1;
}
-#endif
if (n) {
sc.cf = cf;
ngx_http_regex_t *regex;
#endif
+ ngx_uint_t predicate; /* variable index + 1 */
+
unsigned noname:1; /* "if () {}" block or limit_except */
unsigned lmt_excpt:1;
unsigned named:1;
#if (NGX_PCRE)
ngx_http_core_loc_conf_t **regex_locations;
#endif
+ ngx_http_core_loc_conf_t **predicate_locations;
/* pointer to the modules' loc_conf */
void **loc_conf;