Re: расширение return

Igor Sysoev igor на sysoev.ru
Пт Июн 18 14:05:17 MSD 2010


On Thu, Jun 17, 2010 at 02:20:52PM +0400, Igor Sysoev wrote:

> On Thu, Jun 17, 2010 at 02:15:22PM +0400, Igor Sysoev wrote:
> 
> > On Thu, Jun 17, 2010 at 11:07:12AM +0100, Valery Kholodkov wrote:
> > 
> > > О, можно будет сделать более универсальный eval:
> > > 
> > > eval $a {
> > >     return 200 "blah";
> > > }
> > 
> > А какая семантика ?
> > 
> > Вообще-то я не хочу ничего добавлять в этот мерзкий rewrite модуль,
> > но return мне нравится. Да и понадобилось по работе.
> 
> Я бы ещё сделал
> 
>   location /old/ {
>       location ~ ^/old(.+)$ {
>           return  http://site.com$1;
>       }
> 
> или
> 
>   location /old/ {
>       location ~ ^/old(.+)$ {
>           return  301  http://site.com$1;
>       }
> 
> Вот такую личную неприязнь я испытываю к rewrite, что кушать не могу!

Итак, патч. Варианты использования:

    # старые
    return  204;
    return  404;
    return  500;

    # новые
    return  200;
    return  200  "OK\n";
    return  404  "not found\n";      # не перехватывается error_page
    return  301  http://site.ru$request_uri;
    return  302  http://site.ru$request_uri;
    return  303  http://site.ru$request_uri;
    return       http://site.ru$request_uri;     # по умолчанию 302
    return       https://site.ru$request_uri;    # по умолчанию 302
    return       $scheme://site.ru$request_uri;  # по умолчанию 302


-- 
Игорь Сысоев
http://sysoev.ru
-------------- next part --------------
Index: src/http/ngx_http_core_module.c
===================================================================
--- src/http/ngx_http_core_module.c	(revision 2950)
+++ src/http/ngx_http_core_module.c	(working copy)
@@ -865,7 +865,7 @@
 
     /*
      * generic phase checker,
-     * used by the post read, server rewrite, rewrite, and pre-access phases
+     * used by the post read and pre-access phases
      */
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -896,6 +896,29 @@
 
 
 ngx_int_t
+ngx_http_core_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
+{
+    ngx_int_t  rc;
+
+    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                   "rewrite phase: %ui", r->phase_handler);
+
+    rc = ph->handler(r);
+
+    if (rc == NGX_DECLINED) {
+        r->phase_handler++;
+        return NGX_AGAIN;
+    }
+
+    /* rc == NGX_OK || rc == NGX_ERROR || rc == NGX_HTTP_...  */
+
+    ngx_http_finalize_request(r, rc);
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_http_core_find_config_phase(ngx_http_request_t *r,
     ngx_http_phase_handler_t *ph)
 {
@@ -1709,6 +1732,79 @@
 
 
 ngx_int_t
+ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status,
+    ngx_str_t *ct, ngx_http_complex_value_t *cv)
+{
+    ngx_int_t     rc;
+    ngx_str_t     val;
+    ngx_buf_t    *b;
+    ngx_chain_t   out;
+
+    r->headers_out.status = status;
+
+    if (status == NGX_HTTP_NO_CONTENT) {
+        return ngx_http_send_header(r);
+    }
+
+    if (ngx_http_complex_value(r, cv, &val) != NGX_OK) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    if (status >= NGX_HTTP_MOVED_PERMANENTLY && status <= NGX_HTTP_SEE_OTHER) {
+
+        r->headers_out.location = ngx_list_push(&r->headers_out.headers);
+        if (r->headers_out.location == NULL) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+
+        r->headers_out.location->hash = 1;
+        ngx_str_set(&r->headers_out.location->key, "Location");
+        r->headers_out.location->value = val;
+
+        return status;
+    }
+
+    r->headers_out.content_length_n = val.len;
+
+    if (ct) {
+        r->headers_out.content_type_len = ct->len;
+        r->headers_out.content_type = *ct;
+
+    } else {
+        if (ngx_http_set_content_type(r) != NGX_OK) {
+            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        }
+    }
+
+    if (r->method == NGX_HTTP_HEAD) {
+        return ngx_http_send_header(r);
+    }
+
+    b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
+    if (b == NULL) {
+        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+    }
+
+    b->pos = val.data;
+    b->last = val.data + val.len;
+    b->memory = val.len ? 1 : 0;
+    b->last_buf = (r == r->main) ? 1: 0;
+    b->last_in_chain = 1;
+
+    out.buf = b;
+    out.next = NULL;
+
+    rc = ngx_http_send_header(r);
+
+    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
+        return rc;
+    }
+
+    return ngx_http_output_filter(r, &out);
+}
+
+
+ngx_int_t
 ngx_http_send_header(ngx_http_request_t *r)
 {
     if (r->err_status) {
Index: src/http/ngx_http_request.h
===================================================================
--- src/http/ngx_http_request.h	(revision 2950)
+++ src/http/ngx_http_request.h	(working copy)
@@ -72,6 +72,7 @@
 #define NGX_HTTP_SPECIAL_RESPONSE          300
 #define NGX_HTTP_MOVED_PERMANENTLY         301
 #define NGX_HTTP_MOVED_TEMPORARILY         302
+#define NGX_HTTP_SEE_OTHER                 303
 #define NGX_HTTP_NOT_MODIFIED              304
 
 #define NGX_HTTP_BAD_REQUEST               400
Index: src/http/ngx_http_special_response.c
===================================================================
--- src/http/ngx_http_special_response.c	(revision 2950)
+++ src/http/ngx_http_special_response.c	(working copy)
@@ -65,6 +65,14 @@
 ;
 
 
+static char ngx_http_error_303_page[] =
+"<html>" CRLF
+"<head><title>303 See Other</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>303 See Other</h1></center>" CRLF
+;
+
+
 static char ngx_http_error_400_page[] =
 "<html>" CRLF
 "<head><title>400 Bad Request</title></head>" CRLF
@@ -281,7 +289,7 @@
     /* ngx_null_string, */               /* 300 */
     ngx_string(ngx_http_error_301_page),
     ngx_string(ngx_http_error_302_page),
-    ngx_null_string,                     /* 303 */
+    ngx_string(ngx_http_error_303_page),
 
 #define NGX_HTTP_LAST_LEVEL_300  304
 #define NGX_HTTP_LEVEL_300       (NGX_HTTP_LAST_LEVEL_300 - 301)
Index: src/http/ngx_http_header_filter_module.c
===================================================================
--- src/http/ngx_http_header_filter_module.c	(revision 2950)
+++ src/http/ngx_http_header_filter_module.c	(working copy)
@@ -68,7 +68,7 @@
 
     ngx_string("301 Moved Permanently"),
     ngx_string("302 Moved Temporarily"),
-    ngx_null_string,  /* "303 See Other" */
+    ngx_string("303 See Other"),
     ngx_string("304 Not Modified"),
 
     /* ngx_null_string, */  /* "305 Use Proxy" */
Index: src/http/ngx_http_core_module.h
===================================================================
--- src/http/ngx_http_core_module.h	(revision 2950)
+++ src/http/ngx_http_core_module.h	(working copy)
@@ -429,6 +429,8 @@
 void ngx_http_core_run_phases(ngx_http_request_t *r);
 ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r,
     ngx_http_phase_handler_t *ph);
+ngx_int_t ngx_http_core_rewrite_phase(ngx_http_request_t *r,
+    ngx_http_phase_handler_t *ph);
 ngx_int_t ngx_http_core_find_config_phase(ngx_http_request_t *r,
     ngx_http_phase_handler_t *ph);
 ngx_int_t ngx_http_core_post_rewrite_phase(ngx_http_request_t *r,
@@ -446,6 +448,8 @@
 void *ngx_http_test_content_type(ngx_http_request_t *r, ngx_hash_t *types_hash);
 ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r);
 void ngx_http_set_exten(ngx_http_request_t *r);
+ngx_int_t ngx_http_send_response(ngx_http_request_t *r, ngx_uint_t status,
+    ngx_str_t *ct, ngx_http_complex_value_t *cv);
 u_char *ngx_http_map_uri_to_path(ngx_http_request_t *r, ngx_str_t *name,
     size_t *root_length, size_t reserved);
 ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r);
Index: src/http/ngx_http_script.c
===================================================================
--- src/http/ngx_http_script.c	(revision 2950)
+++ src/http/ngx_http_script.c	(working copy)
@@ -1254,14 +1254,17 @@
 
     code = (ngx_http_script_return_code_t *) e->ip;
 
-    e->status = code->status;
-
-    if (code->status == NGX_HTTP_NO_CONTENT) {
-        e->request->header_only = 1;
-        e->request->zero_body = 1;
+    if (code->status < NGX_HTTP_BAD_REQUEST
+        || code->text.value.len
+        || code->text.lengths)
+    {
+        e->status = ngx_http_send_response(e->request, code->status, NULL,
+                                           &code->text);
+    } else {
+        e->status = code->status;
     }
 
-    e->ip += sizeof(ngx_http_script_return_code_t) - sizeof(uintptr_t);
+    e->ip = ngx_http_script_exit;
 }
 
 
Index: src/http/ngx_http_script.h
===================================================================
--- src/http/ngx_http_script.h	(revision 2950)
+++ src/http/ngx_http_script.h	(working copy)
@@ -159,7 +159,7 @@
 typedef struct {
     ngx_http_script_code_pt     code;
     uintptr_t                   status;
-    uintptr_t                   null;
+    ngx_http_complex_value_t    text;
 } ngx_http_script_return_code_t;
 
 
Index: src/http/modules/ngx_http_rewrite_module.c
===================================================================
--- src/http/modules/ngx_http_rewrite_module.c	(revision 2950)
+++ src/http/modules/ngx_http_rewrite_module.c	(working copy)
@@ -52,7 +52,7 @@
 
     { ngx_string("return"),
       NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
-                       |NGX_CONF_TAKE1,
+                       |NGX_CONF_TAKE12,
       ngx_http_rewrite_return,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -433,8 +433,10 @@
 {
     ngx_http_rewrite_loc_conf_t  *lcf = conf;
 
-    ngx_str_t                      *value;
-    ngx_http_script_return_code_t  *ret;
+    u_char                            *p;
+    ngx_str_t                         *value, *v;
+    ngx_http_script_return_code_t     *ret;
+    ngx_http_compile_complex_value_t   ccv;
 
     ret = ngx_http_script_start_code(cf->pool, &lcf->codes,
                                      sizeof(ngx_http_script_return_code_t));
@@ -444,12 +446,46 @@
 
     value = cf->args->elts;
 
+    ngx_memzero(ret, sizeof(ngx_http_script_return_code_t));
+
     ret->code = ngx_http_script_return_code;
-    ret->null = (uintptr_t) NULL;
 
-    ret->status = ngx_atoi(value[1].data, value[1].len);
+    p = value[1].data;
 
+    ret->status = ngx_atoi(p, value[1].len);
+
     if (ret->status == (uintptr_t) NGX_ERROR) {
+
+        if (cf->args->nelts == 2
+            && (ngx_strncmp(p, "http://", sizeof("http://") - 1) == 0
+                || ngx_strncmp(p, "https://", sizeof("https://") - 1) == 0
+                || ngx_strncmp(p, "$scheme", sizeof("$scheme") - 1) == 0))
+        {
+            ret->status = NGX_HTTP_MOVED_TEMPORARILY;
+            v = &value[1];
+
+        } else {
+            ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                               "invalid return code \"%V\"", &value[1]);
+            return NGX_CONF_ERROR;
+        }
+
+    } else {
+
+        if (cf->args->nelts == 2) {
+            return NGX_CONF_OK;
+        }
+
+        v = &value[2];
+    }
+
+    ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
+
+    ccv.cf = cf;
+    ccv.value = v;
+    ccv.complex_value = &ret->text;
+
+    if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
         return NGX_CONF_ERROR;
     }
 
Index: src/http/ngx_http.c
===================================================================
--- src/http/ngx_http.c	(revision 2950)
+++ src/http/ngx_http.c	(working copy)
@@ -509,7 +509,7 @@
             if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
                 cmcf->phase_engine.server_rewrite_index = n;
             }
-            checker = ngx_http_core_generic_phase;
+            checker = ngx_http_core_rewrite_phase;
 
             break;
 
@@ -526,7 +526,7 @@
             if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
                 cmcf->phase_engine.location_rewrite_index = n;
             }
-            checker = ngx_http_core_generic_phase;
+            checker = ngx_http_core_rewrite_phase;
 
             break;
 


Подробная информация о списке рассылки nginx-ru