diff --git a/src/ngx_http_modsecurity_body_filter.c b/src/ngx_http_modsecurity_body_filter.c index 77c144ad..86bccc74 100644 --- a/src/ngx_http_modsecurity_body_filter.c +++ b/src/ngx_http_modsecurity_body_filter.c @@ -33,14 +33,12 @@ ngx_http_modsecurity_body_filter_init(void) return NGX_OK; } + ngx_int_t ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in) { - ngx_http_modsecurity_ctx_t *ctx = NULL; ngx_chain_t *chain = in; - ngx_int_t ret; - ngx_pool_t *old_pool; - ngx_int_t is_request_processed = 0; + ngx_http_modsecurity_ctx_t *ctx = NULL; #if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS) ngx_http_modsecurity_conf_t *mcf; ngx_list_part_t *part = &r->headers_out.headers.part; @@ -49,18 +47,14 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in) #endif if (in == NULL) { - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "MDS input chain is null"); - return ngx_http_next_body_filter(r, in); } - /* get context for request */ - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); + dd("body filter, recovering ctx: %p", ctx); - if (ctx == NULL || r->filter_finalize || ctx->response_body_filtered) { - if (ctx && ctx->response_body_filtered) - r->filter_finalize = 1; + if (ctx == NULL) { return ngx_http_next_body_filter(r, in); } @@ -146,81 +140,47 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in) } #endif - for (chain = in; chain != NULL; chain = chain->next) { - - ngx_buf_t *copy_buf; - ngx_chain_t* copy_chain; - is_request_processed = chain->buf->last_buf; + int is_request_processed = 0; + for (; chain != NULL; chain = chain->next) + { u_char *data = chain->buf->pos; - msc_append_response_body(ctx->modsec_transaction, data, - chain->buf->last - data); - ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, - r, 0); + int ret; + + msc_append_response_body(ctx->modsec_transaction, data, chain->buf->last - data); + ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0); if (ret > 0) { return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity_module, ret); } - if (!chain->buf->last_buf){ - copy_chain = ngx_alloc_chain_link(r->pool); - if (copy_chain == NULL) { - return NGX_ERROR; - } - copy_buf = ngx_calloc_buf(r->pool); - if (copy_buf == NULL) { - return NGX_ERROR; - } - copy_buf->pos = chain->buf->pos ; - copy_buf->end = chain->buf->end; - copy_buf->last = chain->buf->last; - copy_buf->temporary = (chain->buf->temporary == 1) ? 1 : 0; - copy_buf->memory = (chain->buf->memory == 1) ? 1 : 0; - copy_chain->buf = copy_buf; - copy_chain->buf->last_buf = chain->buf->last_buf; - copy_chain->next = NULL; - chain->buf->pos = chain->buf->last; - } - else - copy_chain = chain; - if (ctx->temp_chain == NULL) { - ctx->temp_chain = copy_chain; - } else { - if (ctx->current_chain == NULL) { - ctx->temp_chain->next = copy_chain; - ctx->temp_chain->buf->last_buf = 0; - } else { - ctx->current_chain->next = copy_chain; - ctx->current_chain->buf->last_buf = 0; - } - ctx->current_chain = copy_chain; - } - } +/* XXX: chain->buf->last_buf || chain->buf->last_in_chain */ + is_request_processed = chain->buf->last_buf; - if (is_request_processed) { - old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool); - msc_process_response_body(ctx->modsec_transaction); - ngx_http_modsecurity_pcre_malloc_done(old_pool); - ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0); - if (ret > 0) { - if (ret < NGX_HTTP_BAD_REQUEST && ctx->header_pt != NULL){ - ctx->header_pt(r); - } - else { - ctx->response_body_filtered = 1; - return ngx_http_filter_finalize_request(r, - &ngx_http_modsecurity_module - , ret); - } - } else if (ret < 0) { - ctx->response_body_filtered = 1; - return ngx_http_filter_finalize_request(r, + if (is_request_processed) { + ngx_pool_t *old_pool; + + old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool); + msc_process_response_body(ctx->modsec_transaction); + ngx_http_modsecurity_pcre_malloc_done(old_pool); + +/* XXX: I don't get how body from modsec being transferred to nginx's buffer. If so - after adjusting of nginx's + XXX: body we can proceed to adjust body size (content-length). see xslt_body_filter() for example */ + ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0); + if (ret > 0) { + return ret; + } + else if (ret < 0) { + return ngx_http_filter_finalize_request(r, &ngx_http_modsecurity_module, NGX_HTTP_INTERNAL_SERVER_ERROR); + + } } - ctx->response_body_filtered = 1; - if (ctx->header_pt != NULL) - ctx->header_pt(r); - return ngx_http_next_body_filter(r, ctx->temp_chain); - } else { - return NGX_AGAIN; } + if (!is_request_processed) + { + dd("buffer was not fully loaded! ctx: %p", ctx); + } + +/* XXX: xflt_filter() -- return NGX_OK here */ + return ngx_http_next_body_filter(r, in); } diff --git a/src/ngx_http_modsecurity_common.h b/src/ngx_http_modsecurity_common.h index 1bb243bb..11fdc2d7 100644 --- a/src/ngx_http_modsecurity_common.h +++ b/src/ngx_http_modsecurity_common.h @@ -76,6 +76,7 @@ typedef struct { ngx_str_t value; } ngx_http_modsecurity_header_t; + typedef struct { ngx_http_request_t *r; Transaction *modsec_transaction; @@ -96,13 +97,8 @@ typedef struct { unsigned waiting_more_body:1; unsigned body_requested:1; unsigned processed:1; - ngx_http_output_header_filter_pt header_pt; - ngx_chain_t* temp_chain; - ngx_chain_t* current_chain; - unsigned response_body_filtered:1; unsigned logged:1; unsigned intervention_triggered:1; - unsigned request_body_processed:1; } ngx_http_modsecurity_ctx_t; @@ -143,7 +139,6 @@ extern ngx_module_t ngx_http_modsecurity_module; /* ngx_http_modsecurity_module.c */ int ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_request_t *r, ngx_int_t early_log); ngx_http_modsecurity_ctx_t *ngx_http_modsecurity_create_ctx(ngx_http_request_t *r); -ngx_http_modsecurity_ctx_t *ngx_http_modsecurity_get_module_ctx(ngx_http_request_t *r); char *ngx_str_to_char(ngx_str_t a, ngx_pool_t *p); #if (NGX_PCRE2) #define ngx_http_modsecurity_pcre_malloc_init(x) NULL diff --git a/src/ngx_http_modsecurity_header_filter.c b/src/ngx_http_modsecurity_header_filter.c index 129e633f..257e7fdb 100644 --- a/src/ngx_http_modsecurity_header_filter.c +++ b/src/ngx_http_modsecurity_header_filter.c @@ -109,7 +109,7 @@ ngx_http_modsecurity_store_ctx_header(ngx_http_request_t *r, ngx_str_t *name, ng ngx_http_modsecurity_conf_t *mcf; ngx_http_modsecurity_header_t *hdr; - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); if (ctx == NULL || ctx->sanity_headers_out == NULL) { return NGX_ERROR; } @@ -152,7 +152,7 @@ ngx_http_modsecurity_resolv_header_server(ngx_http_request_t *r, ngx_str_t name, ngx_str_t value; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); if (r->headers_out.server == NULL) { if (clcf->server_tokens) { @@ -186,7 +186,7 @@ ngx_http_modsecurity_resolv_header_date(ngx_http_request_t *r, ngx_str_t name, o ngx_http_modsecurity_ctx_t *ctx = NULL; ngx_str_t date; - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); if (r->headers_out.date == NULL) { date.data = ngx_cached_http_time.data; @@ -216,7 +216,7 @@ ngx_http_modsecurity_resolv_header_content_length(ngx_http_request_t *r, ngx_str ngx_str_t value; char buf[NGX_INT64_LEN+2]; - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); if (r->headers_out.content_length_n > 0) { @@ -243,7 +243,7 @@ ngx_http_modsecurity_resolv_header_content_type(ngx_http_request_t *r, ngx_str_t { ngx_http_modsecurity_ctx_t *ctx = NULL; - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); if (r->headers_out.content_type.len > 0) { @@ -270,7 +270,7 @@ ngx_http_modsecurity_resolv_header_last_modified(ngx_http_request_t *r, ngx_str_ u_char buf[1024], *p; ngx_str_t value; - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); if (r->headers_out.last_modified_time == -1) { return 1; @@ -302,7 +302,7 @@ ngx_http_modsecurity_resolv_header_connection(ngx_http_request_t *r, ngx_str_t n ngx_str_t value; clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); if (r->headers_out.status == NGX_HTTP_SWITCHING_PROTOCOLS) { connection = "upgrade"; @@ -353,7 +353,7 @@ ngx_http_modsecurity_resolv_header_transfer_encoding(ngx_http_request_t *r, ngx_ if (r->chunked) { ngx_str_t value = ngx_string("chunked"); - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); #if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS) ngx_http_modsecurity_store_ctx_header(r, &name, &value); @@ -380,7 +380,7 @@ ngx_http_modsecurity_resolv_header_vary(ngx_http_request_t *r, ngx_str_t name, o if (r->gzip_vary && clcf->gzip_vary) { ngx_str_t value = ngx_string("Accept-Encoding"); - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); #if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS) ngx_http_modsecurity_store_ctx_header(r, &name, &value); @@ -422,7 +422,7 @@ ngx_http_modsecurity_header_filter(ngx_http_request_t *r) /* XXX: if NOT_MODIFIED, do we need to process it at all? see xslt_header_filter() */ - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); dd("header filter, recovering ctx: %p", ctx); @@ -551,17 +551,10 @@ ngx_http_modsecurity_header_filter(ngx_http_request_t *r) * */ - /* - * The line below is commented to make the spdy test to work - */ - //r->headers_out.content_length_n = -1; - - if (ctx->response_body_filtered){ - return ngx_http_next_header_filter(r); - } - else { - ctx->header_pt = ngx_http_next_header_filter; - r->headers_out.content_length_n = -1; - return NGX_AGAIN; - } + /* + * The line below is commented to make the spdy test to work + */ + //r->headers_out.content_length_n = -1; + + return ngx_http_next_header_filter(r); } diff --git a/src/ngx_http_modsecurity_log.c b/src/ngx_http_modsecurity_log.c index 3223ed96..167b2d39 100644 --- a/src/ngx_http_modsecurity_log.c +++ b/src/ngx_http_modsecurity_log.c @@ -60,13 +60,13 @@ ngx_http_modsecurity_log_handler(ngx_http_request_t *r) return NGX_OK; } */ - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); dd("recovering ctx: %p", ctx); if (ctx == NULL) { - dd("ModSecurity not enabled or error occurred"); - return NGX_OK; + dd("something really bad happened here. returning NGX_ERROR"); + return NGX_ERROR; } if (ctx->logged) { diff --git a/src/ngx_http_modsecurity_module.c b/src/ngx_http_modsecurity_module.c index 00ee0636..c90b3f61 100644 --- a/src/ngx_http_modsecurity_module.c +++ b/src/ngx_http_modsecurity_module.c @@ -149,7 +149,7 @@ ngx_http_modsecurity_process_intervention (Transaction *transaction, ngx_http_re dd("processing intervention"); - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); if (ctx == NULL) { return NGX_HTTP_INTERNAL_SERVER_ERROR; @@ -292,7 +292,6 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r) dd("transaction created"); - ctx->response_body_filtered = 0; ngx_http_set_ctx(r, ctx, ngx_http_modsecurity_module); cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_modsecurity_ctx_t)); @@ -314,27 +313,6 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r) return ctx; } -ngx_inline ngx_http_modsecurity_ctx_t * -ngx_http_modsecurity_get_module_ctx(ngx_http_request_t *r) -{ - ngx_http_modsecurity_ctx_t *ctx; - ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); - if (ctx == NULL) { - /* - * refer /src/http/modules/ngx_http_realip_module.c - * if module context was reset, the original address - * can still be found in the cleanup handler - */ - ngx_pool_cleanup_t *cln; - for (cln = r->pool->cleanup; cln; cln = cln->next) { - if (cln->handler == ngx_http_modsecurity_cleanup) { - ctx = cln->data; - break; - } - } - } - return ctx; -} char * ngx_conf_set_rules(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) diff --git a/src/ngx_http_modsecurity_pre_access.c b/src/ngx_http_modsecurity_pre_access.c index 75ac45d4..ea5c0215 100644 --- a/src/ngx_http_modsecurity_pre_access.c +++ b/src/ngx_http_modsecurity_pre_access.c @@ -27,7 +27,7 @@ ngx_http_modsecurity_request_read(ngx_http_request_t *r) { ngx_http_modsecurity_ctx_t *ctx; - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); #if defined(nginx_version) && nginx_version >= 8011 r->main->count--; @@ -70,7 +70,7 @@ ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r) } */ - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); dd("recovering ctx: %p", ctx); @@ -80,11 +80,6 @@ ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r) return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (ctx->request_body_processed) { - // should we use r->internal or r->filter_finalize? - return NGX_DECLINED; - } - if (ctx->intervention_triggered) { return NGX_DECLINED; } @@ -217,7 +212,6 @@ ngx_http_modsecurity_pre_access_handler(ngx_http_request_t *r) old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool); msc_process_request_body(ctx->modsec_transaction); - ctx->request_body_processed = 1; ngx_http_modsecurity_pcre_malloc_done(old_pool); ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r, 0); diff --git a/src/ngx_http_modsecurity_rewrite.c b/src/ngx_http_modsecurity_rewrite.c index eaff1cc8..926cf701 100644 --- a/src/ngx_http_modsecurity_rewrite.c +++ b/src/ngx_http_modsecurity_rewrite.c @@ -46,7 +46,7 @@ ngx_http_modsecurity_rewrite_handler(ngx_http_request_t *r) dd("catching a new _rewrite_ phase handler"); - ctx = ngx_http_modsecurity_get_module_ctx(r); + ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module); dd("recovering ctx: %p", ctx); diff --git a/tests/modsecurity-proxy.t b/tests/modsecurity-proxy.t index e97800e2..a412f5ea 100644 --- a/tests/modsecurity-proxy.t +++ b/tests/modsecurity-proxy.t @@ -114,28 +114,28 @@ unlike(http_head('/'), qr/SEE-THIS/, 'proxy head request'); # Redirect (302) -like(http_get('/phase1?what=redirect302'), qr/302 Moved Temporarily/, 'redirect 302 - phase 1'); -like(http_get('/phase2?what=redirect302'), qr/302 Moved Temporarily/, 'redirect 302 - phase 2'); -like(http_get('/phase3?what=redirect302'), qr/302 Moved Temporarily/, 'redirect 302 - phase 3'); -like(http_get('/phase4?what=redirect302'), qr/404/, 'redirect 302 - phase 4'); +like(http_get('/phase1?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 1'); +like(http_get('/phase2?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 2'); +like(http_get('/phase3?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 3'); +is(http_get('/phase4?what=redirect302'), '', 'redirect 302 - phase 4'); # Redirect (301) -like(http_get('/phase1?what=redirect301'), qr/301 Moved Permanently/, 'redirect 301 - phase 1'); -like(http_get('/phase2?what=redirect301'), qr/301 Moved Permanently/, 'redirect 301 - phase 2'); -like(http_get('/phase3?what=redirect301'), qr/301 Moved Permanently/, 'redirect 301 - phase 3'); -like(http_get('/phase4?what=redirect301'), qr/404/, 'redirect 301 - phase 4'); +like(http_get('/phase1?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 1'); +like(http_get('/phase2?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 2'); +like(http_get('/phase3?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 3'); +is(http_get('/phase4?what=redirect301'), '', 'redirect 301 - phase 4'); # Block (401) -like(http_get('/phase1?what=block401'), qr/401 Unauthorized/, 'block 401 - phase 1'); -like(http_get('/phase2?what=block401'), qr/401 Unauthorized/, 'block 401 - phase 2'); -like(http_get('/phase3?what=block401'), qr/401 Unauthorized/, 'block 401 - phase 3'); -like(http_get('/phase4?what=block401'), qr/401 Unauthorized/, 'block 401 - phase 4'); +like(http_get('/phase1?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 1'); +like(http_get('/phase2?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 2'); +like(http_get('/phase3?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 3'); +is(http_get('/phase4?what=block401'), '', 'block 401 - phase 4'); # Block (403) -like(http_get('/phase1?what=block403'), qr/403 Forbidden/, 'block 403 - phase 1'); -like(http_get('/phase2?what=block403'), qr/403 Forbidden/, 'block 403 - phase 2'); -like(http_get('/phase3?what=block403'), qr/403 Forbidden/, 'block 403 - phase 3'); -like(http_get('/phase4?what=block403'), qr/403 Forbidden/, 'block 403 - phase 4'); +like(http_get('/phase1?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 1'); +like(http_get('/phase2?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 2'); +like(http_get('/phase3?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 3'); +is(http_get('/phase4?what=block403'), '', 'block 403 - phase 4'); # Nothing to detect like(http_get('/phase1?what=nothing'), qr/phase1\?what=nothing\' not found/, 'nothing phase 1'); diff --git a/tests/modsecurity-scoring.t b/tests/modsecurity-scoring.t index 5404c471..65fcb13d 100644 --- a/tests/modsecurity-scoring.t +++ b/tests/modsecurity-scoring.t @@ -46,7 +46,7 @@ http { SecRuleEngine On SecRule ARGS "@streq badarg1" "id:11,phase:2,setvar:tx.score=1" SecRule ARGS "@streq badarg2" "id:12,phase:2,setvar:tx.score=2" - SecRule tx:score "@ge 2" "id:199,phase:request,deny,log,status:403" + SecRule TX:SCORE "@ge 2" "id:199,phase:request,deny,log,status:403" '; } @@ -56,7 +56,7 @@ http { SecRule ARGS "@streq badarg1" "id:21,phase:2,setvar:tx.score=+1" SecRule ARGS "@streq badarg2" "id:22,phase:2,setvar:tx.score=+1" SecRule ARGS "@streq badarg3" "id:23,phase:2,setvar:tx.score=+1" - SecRule tx:score "@ge 3" "id:299,phase:request,deny,log,status:403" + SecRule TX:SCORE "@ge 3" "id:299,phase:request,deny,log,status:403" '; } } diff --git a/tests/modsecurity.t b/tests/modsecurity.t index cad4f092..fcb26f4f 100644 --- a/tests/modsecurity.t +++ b/tests/modsecurity.t @@ -139,28 +139,28 @@ $t->plan(21); # Redirect (302) -like(http_get('/phase1?what=redirect302'), qr/302 Moved Temporarily/, 'redirect 302 - phase 1'); -like(http_get('/phase2?what=redirect302'), qr/302 Moved Temporarily/, 'redirect 302 - phase 2'); -like(http_get('/phase3?what=redirect302'), qr/302 Moved Temporarily/, 'redirect 302 - phase 3'); -like(http_get('/phase4?what=redirect302'), qr/200/, 'redirect 302 - phase 4'); +like(http_get('/phase1?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 1'); +like(http_get('/phase2?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 2'); +like(http_get('/phase3?what=redirect302'), qr/^HTTP.*302/, 'redirect 302 - phase 3'); +is(http_get('/phase4?what=redirect302'), '', 'redirect 302 - phase 4'); # Redirect (301) -like(http_get('/phase1?what=redirect301'), qr/301 Moved Permanently/, 'redirect 301 - phase 1'); -like(http_get('/phase2?what=redirect301'), qr/301 Moved Permanently/, 'redirect 301 - phase 2'); -like(http_get('/phase3?what=redirect301'), qr/301 Moved Permanently/, 'redirect 301 - phase 3'); -like(http_get('/phase4?what=redirect301'), qr/200/, 'redirect 301 - phase 4'); +like(http_get('/phase1?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 1'); +like(http_get('/phase2?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 2'); +like(http_get('/phase3?what=redirect301'), qr/^HTTP.*301/, 'redirect 301 - phase 3'); +is(http_get('/phase4?what=redirect301'), '', 'redirect 301 - phase 4'); # Block (401) -like(http_get('/phase1?what=block401'), qr/401 Unauthorized/, 'block 401 - phase 1'); -like(http_get('/phase2?what=block401'), qr/401 Unauthorized/, 'block 401 - phase 2'); -like(http_get('/phase3?what=block401'), qr/401 Unauthorized/, 'block 401 - phase 3'); -like(http_get('/phase4?what=block401'), qr/401 Unauthorized/, 'block 401 - phase 4'); +like(http_get('/phase1?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 1'); +like(http_get('/phase2?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 2'); +like(http_get('/phase3?what=block401'), qr/^HTTP.*401/, 'block 401 - phase 3'); +is(http_get('/phase4?what=block401'), '', 'block 401 - phase 4'); # Block (403) -like(http_get('/phase1?what=block403'), qr/403 Forbidden/, 'block 403 - phase 1'); -like(http_get('/phase2?what=block403'), qr/403 Forbidden/, 'block 403 - phase 2'); -like(http_get('/phase3?what=block403'), qr/403 Forbidden/, 'block 403 - phase 3'); -like(http_get('/phase4?what=block403'), qr/403 Forbidden/, 'block 403 - phase 4'); +like(http_get('/phase1?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 1'); +like(http_get('/phase2?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 2'); +like(http_get('/phase3?what=block403'), qr/^HTTP.*403/, 'block 403 - phase 3'); +is(http_get('/phase4?what=block403'), '', 'block 403 - phase 4'); # Nothing to detect like(http_get('/phase1?what=nothing'), qr/should be moved\/blocked before this./, 'nothing phase 1');