rewrite POST into GET?

Igor Sysoev is at rambler-co.ru
Thu Feb 14 17:01:22 MSK 2008


On Thu, Feb 14, 2008 at 02:12:35AM -0800, Mark Slater wrote:

> I'm working on a facebook application built using Rails. This is my  
> first time deploying a Rails site, and I'm setting up Capistrano to do  
> the heavy lifting. I've got it creating a "down for maintenance" file  
> that I would like served to all facebook requests when I'm updating  
> things, but facebook always sends a POST request. This causes Nginx to  
> respond with a 405 and report "client sent invalid method...";  
> obviously you can't really POST to a static page.
> 
> Is there a way I can re-direct POST requests to GET requests or force  
> Nginx to return the static page regardless of the method used to  
> access it? My backup plan is to deploy a second app on a different set  
> of ports that always returns the "down for maintenance" message....  
> but it seems silly to run one app to report you're upgrading another.

The attached patch adds the "post_to_static" directive:

         location / {
              post_to_static  on;
         }

or         

     server {

          if ( maintaince  ) {

              ...
              break;

              post_to_static  on;
          }


-- 
Igor Sysoev
http://sysoev.ru/en/
-------------- next part --------------
Index: src/http/modules/ngx_http_static_module.c
===================================================================
--- src/http/modules/ngx_http_static_module.c	(revision 1212)
+++ src/http/modules/ngx_http_static_module.c	(working copy)
@@ -9,10 +9,33 @@
 #include <ngx_http.h>
 
 
+typedef struct {
+    ngx_flag_t  post_to_static;
+} ngx_http_static_loc_conf_t;
+
+
 static ngx_int_t ngx_http_static_handler(ngx_http_request_t *r);
+static void ngx_http_static_request(ngx_http_request_t *r);
+static void *ngx_http_static_create_loc_conf(ngx_conf_t *cf);
+static char *ngx_http_static_merge_loc_conf(ngx_conf_t *cf, void *parent,
+    void *child);
 static ngx_int_t ngx_http_static_init(ngx_conf_t *cf);
 
 
+static ngx_command_t  ngx_http_static_commands[] = {
+
+    { ngx_string("post_to_static"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_SIF_CONF
+                        |NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_static_loc_conf_t, post_to_static),
+      NULL },
+
+      ngx_null_command
+};
+
+
 ngx_http_module_t  ngx_http_static_module_ctx = {
     NULL,                                  /* preconfiguration */
     ngx_http_static_init,                  /* postconfiguration */
@@ -23,15 +46,15 @@
     NULL,                                  /* create server configuration */
     NULL,                                  /* merge server configuration */
 
-    NULL,                                  /* create location configuration */
-    NULL                                   /* merge location configuration */
+    ngx_http_static_create_loc_conf,       /* create location configuration */
+    ngx_http_static_merge_loc_conf         /* merge location configuration */
 };
 
 
 ngx_module_t  ngx_http_static_module = {
     NGX_MODULE_V1,
     &ngx_http_static_module_ctx,           /* module context */
-    NULL,                                  /* module directives */
+    ngx_http_static_commands,              /* module directives */
     NGX_HTTP_MODULE,                       /* module type */
     NULL,                                  /* init master */
     NULL,                                  /* init module */
@@ -47,38 +70,63 @@
 static ngx_int_t
 ngx_http_static_handler(ngx_http_request_t *r)
 {
-    u_char                    *last, *location;
-    size_t                     root;
-    ngx_str_t                  path;
-    ngx_int_t                  rc;
-    ngx_uint_t                 level;
-    ngx_log_t                 *log;
-    ngx_buf_t                 *b;
-    ngx_chain_t                out;
-    ngx_open_file_info_t       of;
-    ngx_http_core_loc_conf_t  *clcf;
+    ngx_int_t                    rc;
+    ngx_http_static_loc_conf_t  *lcf;
 
-    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
-        return NGX_HTTP_NOT_ALLOWED;
-    }
-
     if (r->uri.data[r->uri.len - 1] == '/') {
         return NGX_DECLINED;
     }
 
-    /* TODO: Win32 */
     if (r->zero_in_uri) {
         return NGX_DECLINED;
     }
 
-    rc = ngx_http_discard_request_body(r);
+    if (r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD)) {
 
-    if (rc != NGX_OK) {
-        return rc;
+        rc = ngx_http_discard_request_body(r);
+
+        if (rc != NGX_OK) {
+            return rc;
+        }
+
+        ngx_http_static_request(r);
+
+        return NGX_DONE;
+
+    } else if (r->method & NGX_HTTP_POST) {
+
+        lcf = ngx_http_get_module_loc_conf(r, ngx_http_static_module);
+
+        if (lcf->post_to_static) {
+
+            rc = ngx_http_read_client_request_body(r, ngx_http_static_request);
+
+            if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
+                return rc;
+            }
+
+            return NGX_DONE;
+        }
     }
 
-    log = r->connection->log;
+    return NGX_HTTP_NOT_ALLOWED;
+}
 
+
+static void
+ngx_http_static_request(ngx_http_request_t *r)
+{
+    u_char                    *last, *location;
+    size_t                     root;
+    ngx_str_t                  path;
+    ngx_int_t                  rc;
+    ngx_uint_t                 level;
+    ngx_log_t                 *log;
+    ngx_buf_t                 *b;
+    ngx_chain_t                out;
+    ngx_open_file_info_t       of;
+    ngx_http_core_loc_conf_t  *clcf;
+
     /*
      * ngx_http_map_uri_to_path() allocates memory for terminating '\0'
      * so we do not need to reserve memory for '/' for possible redirect
@@ -86,11 +134,14 @@
 
     last = ngx_http_map_uri_to_path(r, &path, &root, 0);
     if (last == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
     }
 
     path.len = last - path.data;
 
+    log = r->connection->log;
+
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http filename: \"%s\"", path.data);
 
@@ -108,7 +159,8 @@
         switch (of.err) {
 
         case 0:
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
 
         case NGX_ENOENT:
         case NGX_ENOTDIR:
@@ -136,7 +188,8 @@
                           ngx_open_file_n " \"%s\" failed", path.data);
         }
 
-        return rc;
+        ngx_http_finalize_request(r, rc);
+        return;
     }
 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0, "http static fd: %d", of.fd);
@@ -147,7 +200,8 @@
 
         r->headers_out.location = ngx_palloc(r->pool, sizeof(ngx_table_elt_t));
         if (r->headers_out.location == NULL) {
-            return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+            return;
         }
 
         if (!clcf->alias && clcf->root_lengths == NULL) {
@@ -156,7 +210,8 @@
         } else {
             location = ngx_palloc(r->pool, r->uri.len + 1);
             if (location == NULL) {
-                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+                return;
             }
 
             last = ngx_copy(location, r->uri.data, r->uri.len);
@@ -172,7 +227,8 @@
         r->headers_out.location->value.len = r->uri.len + 1;
         r->headers_out.location->value.data = location;
 
-        return NGX_HTTP_MOVED_PERMANENTLY;
+        ngx_http_finalize_request(r, NGX_HTTP_MOVED_PERMANENTLY);
+        return;
     }
 
 #if !(NGX_WIN32) /* the not regular files are probably Unix specific */
@@ -181,7 +237,8 @@
         ngx_log_error(NGX_LOG_CRIT, log, ngx_errno,
                       "\"%s\" is not a regular file", path.data);
 
-        return NGX_HTTP_NOT_FOUND;
+        ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
+        return;
     }
 
 #endif
@@ -193,11 +250,13 @@
     r->headers_out.last_modified_time = of.mtime;
 
     if (ngx_http_set_content_type(r) != NGX_OK) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
     }
 
     if (r != r->main && of.size == 0) {
-        return ngx_http_send_header(r);
+        ngx_http_finalize_request(r, ngx_http_send_header(r));
+        return;
     }
 
     r->allow_ranges = 1;
@@ -206,18 +265,21 @@
 
     b = ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
     if (b == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
     }
 
     b->file = ngx_pcalloc(r->pool, sizeof(ngx_file_t));
     if (b->file == NULL) {
-        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+        ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+        return;
     }
 
     rc = ngx_http_send_header(r);
 
     if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) {
-        return rc;
+        ngx_http_finalize_request(r, rc);
+        return;
     }
 
     b->file_pos = 0;
@@ -234,10 +296,38 @@
     out.buf = b;
     out.next = NULL;
 
-    return ngx_http_output_filter(r, &out);
+    ngx_http_finalize_request(r, ngx_http_output_filter(r, &out));
 }
 
 
+static void *
+ngx_http_static_create_loc_conf(ngx_conf_t *cf)
+{
+    ngx_http_static_loc_conf_t  *lcf;
+
+    lcf = ngx_palloc(cf->pool, sizeof(ngx_http_static_loc_conf_t));
+    if (lcf == NULL) {
+        return NGX_CONF_ERROR;
+    }
+
+    lcf->post_to_static = NGX_CONF_UNSET;
+
+    return lcf;
+}
+
+
+static char *
+ngx_http_static_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
+{
+    ngx_http_static_loc_conf_t *prev = parent;
+    ngx_http_static_loc_conf_t *conf = child;
+
+    ngx_conf_merge_value(conf->post_to_static, prev->post_to_static, 0);
+
+    return NGX_CONF_OK;
+}
+
+
 static ngx_int_t
 ngx_http_static_init(ngx_conf_t *cf)
 {


More information about the nginx mailing list