[mod_ajp13,mod_fastcgi] check resp w/ content len
limit response body from mod_ajp13 and mod_fastcgi to Content-Length, if Content-Length is provided in response headers; discard excesspersonal/stbuehler/tests-path
parent
e78cd76511
commit
1acf9db7d3
|
@ -729,7 +729,7 @@ static int http_response_append_buffer(request_st * const r, buffer * const mem,
|
|||
}
|
||||
else { /* (r->resp_body_scratchpad <= 0) */
|
||||
r->resp_body_finished = 1;
|
||||
if (r->resp_body_scratchpad < 0) {
|
||||
if (__builtin_expect( (r->resp_body_scratchpad < 0), 0)) {
|
||||
/*(silently truncate if data exceeds Content-Length)*/
|
||||
len += r->resp_body_scratchpad;
|
||||
r->resp_body_scratchpad = 0;
|
||||
|
@ -794,7 +794,7 @@ static int http_response_append_mem(request_st * const r, const char * const mem
|
|||
r->resp_body_scratchpad -= (off_t)len;
|
||||
if (r->resp_body_scratchpad <= 0) {
|
||||
r->resp_body_finished = 1;
|
||||
if (r->resp_body_scratchpad < 0) {
|
||||
if (__builtin_expect( (r->resp_body_scratchpad < 0), 0)) {
|
||||
/*(silently truncate if data exceeds Content-Length)*/
|
||||
len = (size_t)(r->resp_body_scratchpad + (off_t)len);
|
||||
r->resp_body_scratchpad = 0;
|
||||
|
@ -809,6 +809,46 @@ static int http_response_append_mem(request_st * const r, const char * const mem
|
|||
}
|
||||
|
||||
|
||||
int http_response_transfer_cqlen(request_st * const r, chunkqueue * const cq, size_t len) {
|
||||
/*(intended for use as callback from modules setting opts->parse(),
|
||||
* e.g. mod_fastcgi and mod_ajp13)
|
||||
*(do not set r->resp_body_finished here since those protocols handle it)*/
|
||||
if (0 == len) return 0;
|
||||
if (__builtin_expect( (!r->resp_decode_chunked), 1)) {
|
||||
const size_t olen = len;
|
||||
if (r->resp_body_scratchpad >= 0) {
|
||||
r->resp_body_scratchpad -= (off_t)len;
|
||||
if (__builtin_expect( (r->resp_body_scratchpad < 0), 0)) {
|
||||
/*(silently truncate if data exceeds Content-Length)*/
|
||||
len = (size_t)(r->resp_body_scratchpad + (off_t)len);
|
||||
r->resp_body_scratchpad = 0;
|
||||
}
|
||||
}
|
||||
int rc = http_chunk_transfer_cqlen(r, cq, len);
|
||||
if (__builtin_expect( (0 != rc), 0))
|
||||
return -1;
|
||||
if (__builtin_expect( (olen != len), 0)) /*discard excess data, if any*/
|
||||
chunkqueue_mark_written(cq, (off_t)(olen - len));
|
||||
}
|
||||
else {
|
||||
/* specialized use by opts->parse() to decode chunked encoding;
|
||||
* FastCGI, AJP13 packet data is all type MEM_CHUNK
|
||||
* (This extra copy can be avoided if FastCGI backend does not send
|
||||
* Transfer-Encoding: chunked, which FastCGI is not supposed to do) */
|
||||
uint32_t remain = (uint32_t)len, wr;
|
||||
for (const chunk *c = cq->first; c && remain; c=c->next, remain-=wr) {
|
||||
/*assert(c->type == MEM_CHUNK);*/
|
||||
wr = buffer_clen(c->mem) - c->offset;
|
||||
if (wr > remain) wr = remain;
|
||||
if (0 != http_chunk_decode_append_mem(r, c->mem->ptr+c->offset, wr))
|
||||
return -1;
|
||||
}
|
||||
chunkqueue_mark_written(cq, len);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int http_response_process_headers(request_st * const restrict r, http_response_opts * const restrict opts, char * const restrict s, const unsigned short hoff[8192], const int is_nph) {
|
||||
int i = 1;
|
||||
|
||||
|
|
|
@ -888,7 +888,7 @@ ajp13_recv_parse (request_st * const r, struct http_response_opts_t * const opts
|
|||
return HANDLER_FINISHED;
|
||||
}
|
||||
chunkqueue_mark_written(hctx->rb, 7);
|
||||
if (0 == http_chunk_transfer_cqlen(r, hctx->rb, len)) {
|
||||
if (0 == http_response_transfer_cqlen(r, hctx->rb, len)) {
|
||||
if (len != plen - 3)
|
||||
chunkqueue_mark_written(hctx->rb, plen - 3 - len);
|
||||
continue;
|
||||
|
@ -896,6 +896,7 @@ ajp13_recv_parse (request_st * const r, struct http_response_opts_t * const opts
|
|||
else {
|
||||
/* error writing to tempfile;
|
||||
* truncate response or send 500 if nothing sent yet */
|
||||
hctx->send_content_body = 0;
|
||||
return HANDLER_FINISHED;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -353,38 +353,6 @@ static void fastcgi_get_packet_body(buffer * const b, handler_ctx * const hctx,
|
|||
buffer_truncate(b, blen + packet->len - packet->padding);
|
||||
}
|
||||
|
||||
__attribute_cold__
|
||||
__attribute_noinline__
|
||||
static int
|
||||
mod_fastcgi_chunk_decode_transfer_cqlen (request_st * const r, chunkqueue * const src, const unsigned int len)
|
||||
{
|
||||
if (0 == len) return 0;
|
||||
|
||||
/* specialized for mod_fastcgi to decode chunked encoding;
|
||||
* FastCGI packet data is all type MEM_CHUNK
|
||||
* entire src cq is processed, minus packet.padding at end
|
||||
* (This extra work can be avoided if FastCGI backend does not send
|
||||
* Transfer-Encoding: chunked, which FastCGI is not supposed to do) */
|
||||
uint32_t remain = len, wr;
|
||||
for (const chunk *c = src->first; c && remain; c = c->next, remain -= wr) {
|
||||
/*assert(c->type == MEM_CHUNK);*/
|
||||
wr = buffer_clen(c->mem) - c->offset;
|
||||
if (wr > remain) wr = remain;
|
||||
if (0 != http_chunk_decode_append_mem(r, c->mem->ptr+c->offset, wr))
|
||||
return -1;
|
||||
}
|
||||
chunkqueue_mark_written(src, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
mod_fastcgi_transfer_cqlen (request_st * const r, chunkqueue * const src, const unsigned int len)
|
||||
{
|
||||
return (!r->resp_decode_chunked)
|
||||
? http_chunk_transfer_cqlen(r, src, len)
|
||||
: mod_fastcgi_chunk_decode_transfer_cqlen(r, src, len);
|
||||
}
|
||||
|
||||
static handler_t fcgi_recv_parse(request_st * const r, struct http_response_opts_t *opts, buffer *b, size_t n) {
|
||||
handler_ctx *hctx = (handler_ctx *)opts->pdata;
|
||||
int fin = 0;
|
||||
|
@ -468,9 +436,10 @@ static handler_t fcgi_recv_parse(request_st * const r, struct http_response_opts
|
|||
}
|
||||
#endif
|
||||
} else if (hctx->send_content_body) {
|
||||
if (0 != mod_fastcgi_transfer_cqlen(r, hctx->rb, packet.len - packet.padding)) {
|
||||
if (0 != http_response_transfer_cqlen(r, hctx->rb, (size_t)(packet.len - packet.padding))) {
|
||||
/* error writing to tempfile;
|
||||
* truncate response or send 500 if nothing sent yet */
|
||||
hctx->send_content_body = 0;
|
||||
fin = 1;
|
||||
}
|
||||
if (packet.padding) chunkqueue_mark_written(hctx->rb, packet.padding);
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "array.h"
|
||||
|
||||
struct stat_cache_entry;/* declaration */
|
||||
struct chunkqueue; /* declaration */
|
||||
|
||||
int http_response_parse(server *srv, request_st *r);
|
||||
|
||||
|
@ -55,6 +56,7 @@ void http_response_send_file (request_st *r, buffer *path, struct stat_cache_ent
|
|||
void http_response_backend_done (request_st *r);
|
||||
void http_response_backend_error (request_st *r);
|
||||
void http_response_upgrade_read_body_unknown(request_st *r);
|
||||
int http_response_transfer_cqlen(request_st *r, struct chunkqueue *cq, size_t len);
|
||||
|
||||
__attribute_cold__
|
||||
int http_response_omit_header(request_st *r, const data_string *ds);
|
||||
|
|
Loading…
Reference in New Issue