@@ -51,6 +51,9 @@ static ngx_int_t ngx_http_redirectionio_pool_available_log_handler(ngx_reslist_t
5151
5252static 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+ }
0 commit comments