mirror of
https://github.com/nginx/nginx.git
synced 2026-10-25 07:07:42 -05:00
Predicate locations
A predicate location name starts with '$' and is interpreted as a
string evaluated at runtime, and its value is used to route the
request into the location. A predicate location matches if the
string evaluates to a non-empty value not equal to "0". At each
nesting level, the first matching predicate location in the
configuration order is chosen. Predicate locations are matched
after prefix and regex locations. They are not matched if an exact
or a regex location matched, or if the longest matching prefix location
has the "^~" modifier. Predicate locations can be nested inside
other location types and can contain nested locations of their own.
Example:
map $arg_foo $pred {
bar 1;
qux 1;
}
location $pred {
root html;
}
This commit is contained in:
1 parent
8fa349cef4
commit
5f54125dde
4 files changed
+121
-20
No files matched your search
@@ -4473,12 +4473,14 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
#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");
|
||||
|
||||
+62
-4
@@ -671,8 +671,8 @@ static ngx_int_t
|
||||
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;
|
||||
@@ -695,6 +695,8 @@ ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
|
||||
regex = NULL;
|
||||
r = 0;
|
||||
#endif
|
||||
predicate = NULL;
|
||||
p = 0;
|
||||
|
||||
for (q = ngx_queue_head(locations);
|
||||
q != ngx_queue_sentinel(locations);
|
||||
@@ -722,6 +724,16 @@ ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
|
||||
|
||||
#endif
|
||||
|
||||
if (clcf->predicate) {
|
||||
p++;
|
||||
|
||||
if (predicate == NULL) {
|
||||
predicate = q;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clcf->named) {
|
||||
n++;
|
||||
|
||||
@@ -764,6 +776,29 @@ ngx_http_init_locations(ngx_conf_t *cf, ngx_http_core_srv_conf_t *cscf,
|
||||
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) {
|
||||
@@ -801,9 +836,17 @@ ngx_http_init_static_location_trees(ngx_conf_t *cf,
|
||||
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) {
|
||||
@@ -867,7 +910,7 @@ ngx_http_add_location(ngx_conf_t *cf, ngx_queue_t **locations,
|
||||
#if (NGX_PCRE)
|
||||
|| clcf->regex
|
||||
#endif
|
||||
|| clcf->named || clcf->noname)
|
||||
|| clcf->predicate || clcf->named || clcf->noname)
|
||||
{
|
||||
lq->exact = clcf;
|
||||
lq->inclusive = NULL;
|
||||
@@ -966,6 +1009,21 @@ ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two)
|
||||
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) {
|
||||
|
||||
@@ -1435,25 +1435,25 @@ ngx_http_update_location_config(ngx_http_request_t *r)
|
||||
|
||||
|
||||
/*
|
||||
* 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);
|
||||
|
||||
@@ -1461,11 +1461,9 @@ ngx_http_core_find_location(ngx_http_request_t *r)
|
||||
|
||||
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 */
|
||||
|
||||
@@ -1508,6 +1506,27 @@ ngx_http_core_find_location(ngx_http_request_t *r)
|
||||
}
|
||||
#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;
|
||||
}
|
||||
|
||||
@@ -3136,6 +3155,7 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
|
||||
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;
|
||||
@@ -3247,6 +3267,20 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
|
||||
}
|
||||
}
|
||||
|
||||
} 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;
|
||||
@@ -3293,12 +3327,11 @@ ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
|
||||
|
||||
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\"",
|
||||
@@ -3667,6 +3700,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
|
||||
* 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;
|
||||
@@ -4685,12 +4719,16 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
|
||||
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;
|
||||
|
||||
@@ -319,6 +319,8 @@ struct ngx_http_core_loc_conf_s {
|
||||
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;
|
||||
@@ -336,6 +338,7 @@ struct ngx_http_core_loc_conf_s {
|
||||
#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;
|
||||
|
||||
Reference in new issue
Block a user