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