Skip to content

Commit

Permalink
lib-http: message parser: Don't allocate a pool for the next message …
Browse files Browse the repository at this point in the history
…until it is needed.

This prevents wasting memory when no message is being parsed.
  • Loading branch information
stephanbosch authored and GitLab committed Feb 15, 2017
1 parent b04dfad commit 1ec26e0
Show file tree
Hide file tree
Showing 4 changed files with 34 additions and 16 deletions.
33 changes: 21 additions & 12 deletions src/lib-http/http-message-parser.c
Expand Up @@ -54,15 +54,20 @@ void http_message_parser_restart(struct http_message_parser *parser,
if (parser->msg.pool != NULL)
pool_unref(&parser->msg.pool);
i_zero(&parser->msg);
if (pool == NULL) {
parser->msg.pool = pool_alloconly_create("http_message", 4096);
} else {
if (pool != NULL) {
parser->msg.pool = pool;
pool_ref(pool);
}
parser->msg.date = (time_t)-1;
}

pool_t http_message_parser_get_pool(struct http_message_parser *parser)
{
if (parser->msg.pool == NULL)
parser->msg.pool = pool_alloconly_create("http_message", 4096);
return parser->msg.pool;
}

int http_message_parse_version(struct http_message_parser *parser)
{
const unsigned char *p = parser->cur;
Expand Down Expand Up @@ -130,9 +135,11 @@ http_message_parse_header(struct http_message_parser *parser,
{
const struct http_header_field *hdr;
struct http_parser hparser;
pool_t pool;

pool = http_message_parser_get_pool(parser);
if (parser->msg.header == NULL)
parser->msg.header = http_header_create(parser->msg.pool, 32);
parser->msg.header = http_header_create(pool, 32);
hdr = http_header_field_add(parser->msg.header, name, data, size);

/* RFC 7230, Section 3.2.2: Field Order
Expand Down Expand Up @@ -166,9 +173,9 @@ http_message_parse_header(struct http_message_parser *parser,
if (strcasecmp(option, "close") == 0)
parser->msg.connection_close = TRUE;
if (!array_is_created(&parser->msg.connection_options))
p_array_init(&parser->msg.connection_options, parser->msg.pool, 4);
p_array_init(&parser->msg.connection_options, pool, 4);
opt_idx = array_append_space(&parser->msg.connection_options);
*opt_idx = p_strdup(parser->msg.pool, option);
*opt_idx = p_strdup(pool, option);
}

if (hparser.cur < hparser.end || num_tokens == 0) {
Expand Down Expand Up @@ -238,7 +245,7 @@ http_message_parse_header(struct http_message_parser *parser,

/* Multiple Transfer-Encoding headers are allowed and combined into one */
if (!array_is_created(&parser->msg.transfer_encoding))
p_array_init(&parser->msg.transfer_encoding, parser->msg.pool, 4);
p_array_init(&parser->msg.transfer_encoding, pool, 4);

/* RFC 7230, Section 3.3.1: Transfer-Encoding
Expand All @@ -262,7 +269,7 @@ http_message_parse_header(struct http_message_parser *parser,
bool parse_error;

coding = array_append_space(&parser->msg.transfer_encoding);
coding->name = p_strdup(parser->msg.pool, trenc);
coding->name = p_strdup(pool, trenc);

/* *( OWS ";" OWS transfer-parameter ) */
parse_error = FALSE;
Expand Down Expand Up @@ -299,10 +306,10 @@ http_message_parse_header(struct http_message_parser *parser,
}

if (!array_is_created(&coding->parameters))
p_array_init(&coding->parameters, parser->msg.pool, 2);
p_array_init(&coding->parameters, pool, 2);
param = array_append_space(&coding->parameters);
param->attribute = p_strdup(parser->msg.pool, attribute);
param->value = p_strdup(parser->msg.pool, value);
param->attribute = p_strdup(pool, attribute);
param->value = p_strdup(pool, value);
}
if (parse_error)
break;
Expand Down Expand Up @@ -355,11 +362,13 @@ int http_message_parse_headers(struct http_message_parser *parser)
while ((ret=http_header_parse_next_field(parser->header_parser,
&field_name, &field_data, &field_size, &error)) > 0) {
if (field_name == NULL) {
pool_t pool;
/* EOH */

/* Create empty header if there is none */
pool = http_message_parser_get_pool(parser);
if (parser->msg.header == NULL)
parser->msg.header = http_header_create(parser->msg.pool, 1);
parser->msg.header = http_header_create(pool, 1);

/* handle HTTP/1.0 persistence */
if (msg->version_major == 1 && msg->version_minor == 0 &&
Expand Down
2 changes: 2 additions & 0 deletions src/lib-http/http-message-parser.h
Expand Up @@ -62,6 +62,8 @@ void http_message_parser_deinit(struct http_message_parser *parser);
void http_message_parser_restart(struct http_message_parser *parser,
pool_t pool);

pool_t http_message_parser_get_pool(struct http_message_parser *parser);

int http_message_parse_finish_payload(struct http_message_parser *parser);
int http_message_parse_version(struct http_message_parser *parser);
int http_message_parse_headers(struct http_message_parser *parser);
Expand Down
11 changes: 8 additions & 3 deletions src/lib-http/http-request-parser.c
Expand Up @@ -92,6 +92,7 @@ http_request_parser_restart(struct http_request_parser *parser,
static int http_request_parse_method(struct http_request_parser *parser)
{
const unsigned char *p = parser->parser.cur;
pool_t pool;

/* method = token
*/
Expand All @@ -105,8 +106,9 @@ static int http_request_parse_method(struct http_request_parser *parser)
}
if (p == parser->parser.end)
return 0;
pool = http_message_parser_get_pool(&parser->parser);
parser->request_method =
p_strdup_until(parser->parser.msg.pool, parser->parser.cur, p);
p_strdup_until(pool, parser->parser.cur, p);
parser->parser.cur = p;
return 1;
}
Expand All @@ -115,6 +117,7 @@ static int http_request_parse_target(struct http_request_parser *parser)
{
struct http_message_parser *_parser = &parser->parser;
const unsigned char *p = parser->parser.cur;
pool_t pool;

/* We'll just parse anything up to the first SP or a control char.
We could also implement workarounds for buggy HTTP clients and
Expand All @@ -138,7 +141,8 @@ static int http_request_parse_target(struct http_request_parser *parser)
}
if (p == _parser->end)
return 0;
parser->request_target = p_strdup_until(_parser->msg.pool, _parser->cur, p);
pool = http_message_parser_get_pool(_parser);
parser->request_target = p_strdup_until(pool, _parser->cur, p);
parser->parser.cur = p;
return 1;
}
Expand Down Expand Up @@ -574,8 +578,9 @@ int http_request_parse_next(struct http_request_parser *parser,

i_zero(request);

pool = http_message_parser_get_pool(&parser->parser);
if (http_url_request_target_parse(parser->request_target, hdr->value,
parser->parser.msg.pool, &request->target, &error) < 0) {
pool, &request->target, &error) < 0) {
*error_code_r = HTTP_REQUEST_PARSE_ERROR_BAD_REQUEST;
*error_r = t_strdup_printf("Bad request target `%s': %s",
parser->request_target, error);
Expand Down
4 changes: 3 additions & 1 deletion src/lib-http/http-response-parser.c
Expand Up @@ -83,6 +83,7 @@ static int http_response_parse_status(struct http_response_parser *parser)
static int http_response_parse_reason(struct http_response_parser *parser)
{
const unsigned char *p = parser->parser.cur;
pool_t pool;

/* reason-phrase = *( HTAB / SP / VCHAR / obs-text )
*/
Expand All @@ -92,8 +93,9 @@ static int http_response_parse_reason(struct http_response_parser *parser)

if (p == parser->parser.end)
return 0;
pool = http_message_parser_get_pool(&parser->parser);
parser->response_reason =
p_strdup_until(parser->parser.msg.pool, parser->parser.cur, p);
p_strdup_until(pool, parser->parser.cur, p);
parser->parser.cur = p;
return 1;
}
Expand Down

0 comments on commit 1ec26e0

Please sign in to comment.