Skip to content

Commit 0938d15

Browse files
committed
Handle redirect on response status for nginx
1 parent 042df2b commit 0938d15

File tree

3 files changed

+66
-4
lines changed

3 files changed

+66
-4
lines changed

src/ngx_http_redirectionio_module.c

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ static ngx_int_t ngx_http_redirectionio_pool_available_log_handler(ngx_reslist_t
5151

5252
static void ngx_http_redirectionio_release_resource(ngx_reslist_t *reslist, ngx_http_redirectionio_resource_t *resource, ngx_uint_t in_error);
5353

54+
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
55+
static ngx_int_t ngx_http_redirectionio_match_on_response_status_header_filter(ngx_http_request_t *r);
56+
5457
/**
5558
* Commands definitions
5659
*/
@@ -134,6 +137,7 @@ static ngx_int_t ngx_http_redirectionio_postconfiguration(ngx_conf_t *cf) {
134137

135138
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
136139

140+
// Log handler -> log phase
137141
log_handler = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers);
138142

139143
if (log_handler == NULL) {
@@ -156,6 +160,7 @@ static ngx_int_t ngx_http_redirectionio_postconfiguration(ngx_conf_t *cf) {
156160

157161
*redirect_handler = ngx_http_redirectionio_redirect_handler;
158162

163+
// Create context handler -> pre access phase
159164
create_ctx_handler = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
160165

161166
if (create_ctx_handler == NULL) {
@@ -165,6 +170,10 @@ static ngx_int_t ngx_http_redirectionio_postconfiguration(ngx_conf_t *cf) {
165170

166171
*create_ctx_handler = ngx_http_redirectionio_create_ctx_handler;
167172

173+
// Filters
174+
ngx_http_next_header_filter = ngx_http_top_header_filter;
175+
ngx_http_top_header_filter = ngx_http_redirectionio_match_on_response_status_header_filter;
176+
168177
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->cycle->log, 0, "redirectionio: init(): return OK");
169178

170179
return NGX_OK;
@@ -186,13 +195,15 @@ static ngx_int_t ngx_http_redirectionio_create_ctx_handler(ngx_http_request_t *r
186195
ctx = (ngx_http_redirectionio_ctx_t *) ngx_pcalloc(r->pool, sizeof(ngx_http_redirectionio_ctx_t));
187196

188197
if (ctx == NULL) {
189-
return NGX_HTTP_INTERNAL_SERVER_ERROR;
198+
return NGX_DECLINED;
190199
}
191200

192201
ctx->status = 0;
193202
ctx->connection_error = 0;
194203
ctx->wait_for_connection = 0;
195204
ctx->wait_for_match = 0;
205+
ctx->match_on_response_status = 0;
206+
ctx->is_redirected = 0;
196207

197208
ngx_http_set_ctx(r, ctx, ngx_http_redirectionio_module);
198209
}
@@ -263,7 +274,7 @@ static ngx_int_t ngx_http_redirectionio_redirect_handler(ngx_http_request_t *r)
263274

264275
ngx_http_redirectionio_release_resource(conf->connection_pool, ctx->resource, 0);
265276

266-
if (ctx->status == 0) {
277+
if (ctx->status == 0 || ctx->match_on_response_status != 0) {
267278
return NGX_DECLINED;
268279
}
269280

@@ -282,6 +293,7 @@ static ngx_int_t ngx_http_redirectionio_redirect_handler(ngx_http_request_t *r)
282293
}
283294

284295
r->headers_out.status = ctx->status;
296+
ctx->is_redirected = 1;
285297

286298
return ctx->status;
287299
}
@@ -478,6 +490,7 @@ static void ngx_http_redirectionio_read_match_rule_handler(ngx_event_t *rev, cJS
478490
}
479491

480492
cJSON *status = cJSON_GetObjectItem(json, "status_code");
493+
cJSON *match_on_response_status = cJSON_GetObjectItem(json, "match_on_response_status");
481494
cJSON *location = cJSON_GetObjectItem(json, "location");
482495
cJSON *matched_rule = cJSON_GetObjectItem(json, "matched_rule");
483496
cJSON *rule_id = NULL;
@@ -490,6 +503,7 @@ static void ngx_http_redirectionio_read_match_rule_handler(ngx_event_t *rev, cJS
490503
ctx->matched_rule_id.data = (u_char *)"";
491504
ctx->matched_rule_id.len = 0;
492505
ctx->status = 0;
506+
ctx->match_on_response_status = 0;
493507

494508
ngx_http_core_run_phases(r);
495509

@@ -501,6 +515,11 @@ static void ngx_http_redirectionio_read_match_rule_handler(ngx_event_t *rev, cJS
501515
ctx->target.data = (u_char *)location->valuestring;
502516
ctx->target.len = strlen(location->valuestring);
503517
ctx->status = status->valueint;
518+
ctx->match_on_response_status = 0;
519+
520+
if (match_on_response_status != NULL && match_on_response_status->type != cJSON_NULL) {
521+
ctx->match_on_response_status = match_on_response_status->valueint;
522+
}
504523

505524
ngx_http_core_run_phases(r);
506525
}
@@ -725,3 +744,45 @@ static void ngx_http_redirectionio_release_resource(ngx_reslist_t *reslist, ngx_
725744

726745
ngx_reslist_release(reslist, resource);
727746
}
747+
748+
static ngx_int_t ngx_http_redirectionio_match_on_response_status_header_filter(ngx_http_request_t *r) {
749+
ngx_http_redirectionio_ctx_t *ctx;
750+
ngx_http_redirectionio_conf_t *conf;
751+
752+
conf = ngx_http_get_module_loc_conf(r, ngx_http_redirectionio_module);
753+
754+
if (conf->enable == NGX_HTTP_REDIRECTIONIO_OFF) {
755+
return ngx_http_next_header_filter(r);
756+
}
757+
758+
ctx = ngx_http_get_module_ctx(r, ngx_http_redirectionio_module);
759+
760+
// Skip if no need to redirect
761+
if (ctx == NULL || ctx->status == 0 || ctx->match_on_response_status == 0 || ctx->is_redirected) {
762+
return ngx_http_next_header_filter(r);
763+
}
764+
765+
if (r->headers_out.status != ctx->match_on_response_status) {
766+
return ngx_http_next_header_filter(r);
767+
}
768+
769+
if (ctx->status != 410) {
770+
// Set target
771+
r->headers_out.location = ngx_list_push(&r->headers_out.headers);
772+
773+
if (r->headers_out.location == NULL) {
774+
return NGX_HTTP_INTERNAL_SERVER_ERROR;
775+
}
776+
777+
r->headers_out.location->hash = 1;
778+
ngx_str_set(&r->headers_out.location->key, "Location");
779+
r->headers_out.location->value.len = ctx->target.len;
780+
r->headers_out.location->value.data = ctx->target.data;
781+
}
782+
783+
r->headers_out.status = ctx->status;
784+
// Avoid loop if we redirect on the same status as we match
785+
ctx->is_redirected = 1;
786+
787+
return ngx_http_special_response_handler(r, ctx->status);
788+
}

src/ngx_http_redirectionio_module.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@ typedef struct {
2828
ngx_str_t matched_rule_id;
2929
ngx_str_t target;
3030
ngx_uint_t status;
31+
ngx_uint_t match_on_response_status;
32+
ngx_uint_t is_redirected;
3133
ngx_uint_t connection_error;
3234
ngx_http_redirectionio_read_handler_t read_handler;
33-
ngx_http_request_t *subrequest;
3435
ngx_uint_t wait_for_connection;
3536
ngx_uint_t wait_for_match;
3637
} ngx_http_redirectionio_ctx_t;

src/ngx_http_redirectionio_protocol.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#include <ngx_http_redirectionio_protocol.h>
22

3-
const char COMMAND_MATCH_NAME[] = "MATCH";
3+
const char COMMAND_MATCH_NAME[] = "MATCH_WITH_RESPONSE";
44
const char COMMAND_MATCH_QUERY[] = "{ \"project_id\": \"%V\", \"request_uri\": \"%V\", \"host\": \"%V\" }";
55
const char COMMAND_LOG_NAME[] = "LOG";
66
const char COMMAND_LOG_QUERY[] = "{ \"project_id\": \"%V\", \"request_uri\": \"%V\", \"host\": \"%V\", \"rule_id\": \"%V\", \"target\": \"%V\", \"status_code\": %d, \"user_agent\": \"%V\", \"referer\": \"%V\" }";

0 commit comments

Comments
 (0)