Skip to content

Commit 2dc1f7d

Browse files
committed
fix response body filtering
1 parent a2a5858 commit 2dc1f7d

4 files changed

+86
-48
lines changed

Diff for: src/ngx_http_modsecurity_body_filter.c

+68-40
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ ngx_http_modsecurity_body_filter_init(void)
3131

3232
return NGX_OK;
3333
}
34-
3534
ngx_int_t
3635
ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
3736
{
38-
int buffer_fully_loadead = 0;
39-
ngx_chain_t *chain = in;
37+
4038
ngx_http_modsecurity_ctx_t *ctx = NULL;
39+
ngx_chain_t *chain = in;
40+
ngx_int_t ret;
41+
ngx_pool_t *old_pool;
42+
ngx_int_t is_request_processed = 0;
4143
#if defined(MODSECURITY_SANITY_CHECKS) && (MODSECURITY_SANITY_CHECKS)
4244
ngx_http_modsecurity_conf_t *loc_cf = NULL;
4345
ngx_list_part_t *part = &r->headers_out.headers.part;
@@ -49,11 +51,11 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
4951
return ngx_http_next_body_filter(r, in);
5052
}
5153

54+
/* get context for request */
5255
ctx = ngx_http_get_module_ctx(r, ngx_http_modsecurity_module);
53-
5456
dd("body filter, recovering ctx: %p", ctx);
55-
56-
if (ctx == NULL) {
57+
58+
if (ctx == NULL || r->filter_finalize) {
5759
return ngx_http_next_body_filter(r, in);
5860
}
5961

@@ -130,56 +132,82 @@ ngx_http_modsecurity_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
130132
{
131133
dd("%d header(s) were not inspected by ModSecurity, so exiting", worth_to_fail);
132134
return ngx_http_filter_finalize_request(r,
133-
&ngx_http_modsecurity_module, NGX_HTTP_INTERNAL_SERVER_ERROR);
135+
&ngx_http_modsecurity_module, NGX_HTTP_INTERNAL_SERVER_ERROR);
134136
}
135137
}
136138
#endif
137139

138-
for (; chain != NULL; chain = chain->next)
139-
{
140-
/* XXX: chain->buf->last_buf || chain->buf->last_in_chain */
141-
if (chain->buf->last_buf) {
142-
buffer_fully_loadead = 1;
140+
for (chain = in; chain != NULL; chain = chain->next) {
141+
142+
ngx_buf_t *copy_buf;
143+
ngx_chain_t* copy_chain;
144+
is_request_processed = chain->buf->last_buf;
145+
ngx_int_t data_size = chain->buf->end - chain->buf->start;
146+
ngx_int_t data_offset = chain->buf->pos - chain->buf->start;
147+
u_char *data = chain->buf->start;
148+
msc_append_response_body(ctx->modsec_transaction, data,
149+
chain->buf->end - data);
150+
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction,
151+
r);
152+
if (ret > 0) {
153+
return ngx_http_filter_finalize_request(r,
154+
&ngx_http_modsecurity_module, ret);
143155
}
144-
}
145156

146-
if (buffer_fully_loadead == 1)
147-
{
148-
int ret;
149-
ngx_pool_t *old_pool;
150-
151-
for (chain = in; chain != NULL; chain = chain->next)
152-
{
153-
u_char *data = chain->buf->start;
157+
copy_chain = ngx_alloc_chain_link(r->pool);
158+
if (copy_chain == NULL) {
159+
return NGX_ERROR;
160+
}
154161

155-
msc_append_response_body(ctx->modsec_transaction, data, chain->buf->end - data);
156-
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r);
157-
if (ret > 0) {
158-
return ngx_http_filter_finalize_request(r,
159-
&ngx_http_modsecurity_module, ret);
162+
copy_buf = ngx_calloc_buf(r->pool);
163+
if (copy_buf == NULL) {
164+
return NGX_ERROR;
165+
}
166+
copy_buf->start = ngx_pcalloc(r->pool, data_size);
167+
if (copy_buf->start == NULL) {
168+
return NGX_ERROR;
169+
}
170+
ngx_memcpy(copy_buf->start, chain->buf->start, data_size);
171+
copy_buf->pos = copy_buf->start + data_offset;
172+
copy_buf->end = copy_buf->start + data_size;
173+
copy_buf->last = copy_buf->pos + ngx_buf_size(chain->buf);
174+
copy_buf->temporary = (chain->buf->temporary == 1) ? 1 : 0;
175+
copy_buf->memory = (chain->buf->memory == 1) ? 1 : 0;
176+
copy_chain->buf = copy_buf;
177+
copy_chain->buf->last_buf = 1;
178+
copy_chain->next = NULL;
179+
chain->buf->pos = chain->buf->last;
180+
181+
if (ctx->temp_chain == NULL) {
182+
ctx->temp_chain = copy_chain;
183+
} else {
184+
if (ctx->current_chain == NULL) {
185+
ctx->temp_chain->next = copy_chain;
186+
ctx->temp_chain->buf->last_buf = 0;
187+
} else {
188+
ctx->current_chain->next = copy_chain;
189+
ctx->current_chain->buf->last_buf = 0;
160190
}
191+
ctx->current_chain = copy_chain;
161192
}
193+
}
162194

195+
if (is_request_processed) {
163196
old_pool = ngx_http_modsecurity_pcre_malloc_init(r->pool);
164197
msc_process_response_body(ctx->modsec_transaction);
165198
ngx_http_modsecurity_pcre_malloc_done(old_pool);
166-
167-
/* XXX: I don't get how body from modsec being transferred to nginx's buffer. If so - after adjusting of nginx's
168-
XXX: body we can proceed to adjust body size (content-length). see xslt_body_filter() for example */
169199
ret = ngx_http_modsecurity_process_intervention(ctx->modsec_transaction, r);
170200
if (ret > 0) {
171-
return ret;
172-
}
173-
else if (ret < 0) {
174201
return ngx_http_filter_finalize_request(r,
175-
&ngx_http_modsecurity_module, NGX_HTTP_INTERNAL_SERVER_ERROR);
202+
&ngx_http_modsecurity_module, ret);
203+
} else if (ret < 0) {
204+
return ngx_http_filter_finalize_request(r,
205+
&ngx_http_modsecurity_module, ret);
176206
}
207+
ctx->response_body_filtered = 1;
208+
ctx->header_pt(r);
209+
return ngx_http_next_body_filter(r, ctx->temp_chain);
210+
} else {
211+
return NGX_AGAIN;
177212
}
178-
else
179-
{
180-
dd("buffer was not fully loaded! ctx: %p", ctx);
181-
}
182-
183-
/* XXX: xflt_filter() -- return NGX_OK here */
184-
return ngx_http_next_body_filter(r, in);
185213
}

Diff for: src/ngx_http_modsecurity_common.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@ typedef struct {
3131
ngx_str_t value;
3232
} ngx_http_modsecurity_header_t;
3333

34-
3534
typedef struct {
3635
ngx_http_request_t *r;
3736
Transaction *modsec_transaction;
@@ -52,6 +51,10 @@ typedef struct {
5251
unsigned waiting_more_body:1;
5352
unsigned body_requested:1;
5453
unsigned processed:1;
54+
ngx_http_output_header_filter_pt header_pt;
55+
ngx_chain_t* temp_chain;
56+
ngx_chain_t* current_chain;
57+
unsigned response_body_filtered:1;
5558
} ngx_http_modsecurity_ctx_t;
5659

5760

Diff for: src/ngx_http_modsecurity_header_filter.c

+12-6
Original file line numberDiff line numberDiff line change
@@ -542,10 +542,16 @@ ngx_http_modsecurity_header_filter(ngx_http_request_t *r)
542542
*
543543
*/
544544

545-
/*
546-
* The line below is commented to make the spdy test to work
547-
*/
548-
//r->headers_out.content_length_n = -1;
549-
550-
return ngx_http_next_header_filter(r);
545+
/*
546+
* The line below is commented to make the spdy test to work
547+
*/
548+
//r->headers_out.content_length_n = -1;
549+
550+
if (ctx->response_body_filtered){
551+
return ngx_http_next_header_filter(r);
552+
}
553+
else {
554+
ctx->header_pt = ngx_http_next_header_filter;
555+
return NGX_AGAIN;
556+
}
551557
}

Diff for: src/ngx_http_modsecurity_module.c

+2-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,8 @@ ngx_http_modsecurity_create_ctx(ngx_http_request_t *r)
247247
ctx->modsec_transaction = msc_new_transaction(cf->modsec, loc_cf->rules_set, r->connection->log);
248248

249249
dd("transaction created");
250-
250+
251+
ctx->response_body_filtered = 0;
251252
ngx_http_set_ctx(r, ctx, ngx_http_modsecurity_module);
252253

253254
cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_modsecurity_ctx_t));

0 commit comments

Comments
 (0)