changeset 1395:bf5b86d5f00e stable-0.5

r1354 merge: named location
author Igor Sysoev <igor@sysoev.ru>
date Tue, 14 Aug 2007 20:02:09 +0000
parents 6485121a080d
children ec4d58ab30ea
files src/http/modules/ngx_http_proxy_module.c src/http/ngx_http.c src/http/ngx_http_core_module.c src/http/ngx_http_core_module.h src/http/ngx_http_special_response.c
diffstat 5 files changed, 124 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -2275,13 +2275,17 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
 
     plcf->upstream.location = clcf->name;
 
+    if (clcf->named
 #if (NGX_PCRE)
-
-    if (clcf->regex || clcf->noname) {
+        || clcf->regex
+#endif
+        || clcf->noname)
+    {
         if (plcf->upstream.uri.len) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
                                "\"proxy_pass\" may not have URI part in "
                                "location given by regular expression, "
+                               "or inside named location, "
                                "or inside the \"if\" statement, "
                                "or inside the \"limit_except\" block");
             return NGX_CONF_ERROR;
@@ -2290,8 +2294,6 @@ ngx_http_proxy_pass(ngx_conf_t *cf, ngx_
         plcf->upstream.location.len = 0;
     }
 
-#endif
-
     plcf->upstream.url = *url;
 
     if (clcf->name.data[clcf->name.len - 1] == '/') {
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -402,6 +402,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 
 
     cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
+    cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
     find_config_index = 0;
     use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
     use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;
@@ -443,6 +444,14 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma
 
             continue;
 
+        case NGX_HTTP_REWRITE_PHASE:
+            if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
+                cmcf->phase_engine.location_rewrite_index = n;
+            }
+            checker = ngx_http_core_generic_phase;
+
+            break;
+
         case NGX_HTTP_POST_REWRITE_PHASE:
             if (use_rewrite) {
                 ph->checker = ngx_http_core_post_rewrite_phase;
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -945,13 +945,12 @@ ngx_http_core_find_location(ngx_http_req
     clcfp = locations->elts;
     for (i = 0; i < locations->nelts; i++) {
 
+        if (clcfp[i]->noname
 #if (NGX_PCRE)
-        if (clcfp[i]->regex) {
-            break;
-        }
+            || clcfp[i]->regex
 #endif
-
-        if (clcfp[i]->noname) {
+            || clcfp[i]->named)
+        {
             break;
         }
 
@@ -1028,7 +1027,7 @@ ngx_http_core_find_location(ngx_http_req
 
     for (i = regex_start; i < locations->nelts; i++) {
 
-        if (clcfp[i]->noname) {
+        if (!clcfp[i]->regex) {
             break;
         }
 
@@ -1513,6 +1512,51 @@ ngx_http_internal_redirect(ngx_http_requ
 }
 
 
+ngx_int_t
+ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name)
+{
+    ngx_uint_t                   i;
+    ngx_http_core_srv_conf_t    *cscf;
+    ngx_http_core_loc_conf_t   **clcfp;
+    ngx_http_core_main_conf_t   *cmcf;
+
+    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
+
+    clcfp = cscf->locations.elts;
+
+    for (i = cscf->named_start; i < cscf->locations.nelts; i++) {
+
+        if (name->len != clcfp[i]->name.len
+            || ngx_strncmp(name->data, clcfp[i]->name.data, name->len) != 0)
+        {
+            continue;
+        }
+
+        ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "named location: %V \"%V?%V\"", name, &r->uri, &r->args);
+
+        r->internal = 1;
+
+        r->loc_conf = clcfp[i]->loc_conf;
+
+        ngx_http_update_location_config(r);
+
+        cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
+
+        r->phase_handler = cmcf->phase_engine.location_rewrite_index;
+        ngx_http_core_run_phases(r);
+
+        return NGX_DONE;
+    }
+
+    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
+                  "could not find name location \"%V\"", name);
+
+    ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+    return NGX_DONE;
+}
+
+
 ngx_http_cleanup_t *
 ngx_http_cleanup_add(ngx_http_request_t *r, size_t size)
 {
@@ -1557,10 +1601,8 @@ ngx_http_core_server(ngx_conf_t *cf, ngx
     ngx_http_module_t           *module;
     ngx_http_conf_ctx_t         *ctx, *http_ctx;
     ngx_http_core_srv_conf_t    *cscf, **cscfp;
+    ngx_http_core_loc_conf_t   **clcfp;
     ngx_http_core_main_conf_t   *cmcf;
-#if (NGX_PCRE)
-    ngx_http_core_loc_conf_t   **clcfp;
-#endif
 
     ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
     if (ctx == NULL) {
@@ -1644,10 +1686,11 @@ ngx_http_core_server(ngx_conf_t *cf, ngx
     ngx_sort(cscf->locations.elts, (size_t) cscf->locations.nelts,
              sizeof(ngx_http_core_loc_conf_t *), ngx_http_core_cmp_locations);
 
+    clcfp = cscf->locations.elts;
+
 #if (NGX_PCRE)
 
     cscf->regex_start = cscf->locations.nelts;
-    clcfp = cscf->locations.elts;
 
     for (i = 0; i < cscf->locations.nelts; i++) {
         if (clcfp[i]->regex) {
@@ -1658,6 +1701,15 @@ ngx_http_core_server(ngx_conf_t *cf, ngx
 
 #endif
 
+    cscf->named_start = cscf->locations.nelts;
+
+    for (i = 0; i < cscf->locations.nelts; i++) {
+        if (clcfp[i]->named) {
+            cscf->named_start = i;
+            break;
+        }
+    }
+
     return rv;
 }
 
@@ -1758,7 +1810,12 @@ ngx_http_core_location(ngx_conf_t *cf, n
         }
 
     } else {
+
         clcf->name = value[1];
+
+        if (value[1].data[0] == '@') {
+            clcf->named = 1;
+        }
     }
 
     pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
@@ -1784,6 +1841,14 @@ ngx_http_core_location(ngx_conf_t *cf, n
             return NGX_CONF_ERROR;
         }
 
+        if (pclcf->named) {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "location \"%V\" could not be inside "
+                               "the named location \"%V\"",
+                               &clcf->name, &pclcf->name);
+            return NGX_CONF_ERROR;
+        }
+
 #if (NGX_PCRE)
         if (clcf->regex == NULL
             && ngx_strncmp(clcf->name.data, pclcf->name.data, pclcf->name.len)
@@ -1861,6 +1926,20 @@ ngx_http_core_cmp_locations(const void *
     first = *(ngx_http_core_loc_conf_t **) one;
     second = *(ngx_http_core_loc_conf_t **) two;
 
+    if (first->named && !second->named) {
+        /* shift named locations to the end */
+        return 1;
+    }
+
+    if (!first->named && second->named) {
+        /* shift named locations to the end */
+        return -1;
+    }
+
+    if (first->named && second->named) {
+        return ngx_strcmp(first->name.data, second->name.data);
+    }
+
     if (first->noname && !second->noname) {
         /* shift no named locations to the end */
         return 1;
@@ -2706,6 +2785,14 @@ ngx_http_core_root(ngx_conf_t *cf, ngx_c
         return NGX_CONF_ERROR;
     }
 
+    if (lcf->named && alias) {
+        ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                           "the \"alias\" directive may not be used "
+                           "inside named location");
+
+        return NGX_CONF_ERROR;
+    }
+
 #if (NGX_PCRE)
 
     if (lcf->regex && alias) {
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -79,6 +79,7 @@ struct ngx_http_phase_handler_s {
 typedef struct {
     ngx_http_phase_handler_t  *handlers;
     ngx_uint_t                 server_rewrite_index;
+    ngx_uint_t                 location_rewrite_index;
 } ngx_http_phase_engine_t;
 
 
@@ -117,7 +118,8 @@ typedef struct {
      */
     ngx_array_t                locations;
 
-    unsigned                   regex_start:16;
+    unsigned                   regex_start:15;
+    unsigned                   named_start:15;
     unsigned                   wildcard:1;
 
     /* array of the ngx_http_listen_t, "listen" directive */
@@ -211,9 +213,10 @@ struct ngx_http_core_loc_conf_s {
     ngx_regex_t  *regex;
 #endif
 
-    unsigned      regex_start:16;
+    unsigned      regex_start:15;
 
-    unsigned      noname:1;   /* "if () {}" block */
+    unsigned      noname:1;   /* "if () {}" block or limit_except */
+    unsigned      named:1;
 
     unsigned      exact_match:1;
     unsigned      noregex:1;
@@ -313,6 +316,8 @@ ngx_int_t ngx_http_subrequest(ngx_http_r
     ngx_http_post_subrequest_t *psr, ngx_uint_t flags);
 ngx_int_t ngx_http_internal_redirect(ngx_http_request_t *r,
     ngx_str_t *uri, ngx_str_t *args);
+ngx_int_t ngx_http_named_location(ngx_http_request_t *r, ngx_str_t *name);
+
 
 ngx_http_cleanup_t *ngx_http_cleanup_add(ngx_http_request_t *r, size_t size);
 
--- a/src/http/ngx_http_special_response.c
+++ b/src/http/ngx_http_special_response.c
@@ -409,6 +409,10 @@ ngx_http_special_response_handler(ngx_ht
                     return ngx_http_internal_redirect(r, uri, NULL);
                 }
 
+                if (uri->data[0] == '@') {
+                    return ngx_http_named_location(r, uri);
+                }
+
                 r->headers_out.location =
                                         ngx_list_push(&r->headers_out.headers);