From 08a10df55e37436172a22b1cbcb7697deda96945 Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Thu, 17 Sep 2015 21:26:56 +0300 Subject: [PATCH 1/4] #257. Correct parsing of a splitted request --- tempesta_fw/http_msg.c | 28 ++++++------ tempesta_fw/http_msg.h | 3 +- tempesta_fw/http_parser.c | 94 ++++++++++++--------------------------- 3 files changed, 44 insertions(+), 81 deletions(-) diff --git a/tempesta_fw/http_msg.c b/tempesta_fw/http_msg.c index b764e822df..9c8fede6d5 100644 --- a/tempesta_fw/http_msg.c +++ b/tempesta_fw/http_msg.c @@ -169,47 +169,45 @@ tfw_http_msg_hdr_open(TfwHttpMsg *hm, unsigned char *hdr_start) } /** - * Fixup the new data chunk to currently parsed HTTP header. + * Fixup the new data chunk to currently parsed HTTP field. * * @len could be 0 if the header was fully read, but we realized this only * now by facinng CRLF at begin of current data chunk. */ void -tfw_http_msg_hdr_chunk_fixup(TfwHttpMsg *hm, char *data, int len) +tfw_http_msg_field_chunk_fixup(TfwHttpMsg *hm, TfwStr *field, char *data, int len) { - TfwStr *hdr = &hm->parser.hdr; - - BUG_ON(hdr->flags & TFW_STR_DUPLICATE); + BUG_ON(field->flags & TFW_STR_DUPLICATE); - TFW_DBG("store header chunk len=%d data=%p hdr=<%#x,%u,%p>\n", - len, data, hdr->flags, hdr->len, hdr->ptr); + TFW_DBG("store field chunk len=%d data=%p field=<%#x,%u,%p>\n", + len, data, field->flags, field->len, field->ptr); /* The header should be open before. */ - if (unlikely(!hdr->ptr)) + if (unlikely(!field->ptr)) return; - if (TFW_STR_EMPTY(hdr)) { + if (TFW_STR_EMPTY(field)) { /* * The first data chunk case. * The header chunk was explicitly opened at some data * position, so close the chunk by end of @data. */ - BUG_ON(!TFW_STR_PLAIN(hdr)); - hdr->len = data + len - (char *)hdr->ptr; + BUG_ON(!TFW_STR_PLAIN(field)); + field->len = data + len - (char *)field->ptr; } else if (len) { /* * The data chunk doesn't lay at the header bounds. * There is at least one finished chunk, add a new one. */ - TfwStr *h = tfw_str_add_compound(hm->pool, hdr); - if (unlikely(!h)) { + TfwStr *last = tfw_str_add_compound(hm->pool, field); + if (unlikely(!last)) { TFW_WARN("Cannot store chunk [%.*s]\n", min((int)len, 10), data); return; } - tfw_http_msg_set_data(hm, h, data); - tfw_str_updlen(hdr, data + len); + tfw_http_msg_set_data(hm, last, data); + tfw_str_updlen(field, data + len); } } diff --git a/tempesta_fw/http_msg.h b/tempesta_fw/http_msg.h index 5063328041..7ed2aff098 100644 --- a/tempesta_fw/http_msg.h +++ b/tempesta_fw/http_msg.h @@ -54,7 +54,8 @@ TfwHttpMsg *tfw_http_msg_create(TfwMsgIter *it, int type, size_t data_len); int tfw_http_msg_write(TfwMsgIter *it, TfwHttpMsg *hm, const TfwStr *data); void tfw_http_msg_hdr_open(TfwHttpMsg *hm, unsigned char *hdr_start); -void tfw_http_msg_hdr_chunk_fixup(TfwHttpMsg *hm, char *data, int len); +void tfw_http_msg_field_chunk_fixup(TfwHttpMsg *hm, TfwStr *field, + char *data, int len); int tfw_http_msg_hdr_close(TfwHttpMsg *hm, int id); int tfw_http_msg_grow_hdr_tbl(TfwHttpMsg *hm); diff --git a/tempesta_fw/http_parser.c b/tempesta_fw/http_parser.c index d3c284bfa0..976e93d9ee 100644 --- a/tempesta_fw/http_parser.c +++ b/tempesta_fw/http_parser.c @@ -47,33 +47,6 @@ enum { RGen_LF, }; -/** - * Set final field length and mark it as finished. - */ -static inline void -__field_finish(TfwStr *field, unsigned char *begin, unsigned char *end) -{ - if (unlikely(!TFW_STR_PLAIN(field))) { - if (unlikely(begin == end)) { - tfw_str_del_chunk(field, TFW_STR_CHUNKN(field) - 1); - } else { - TfwStr *last = (TfwStr *)field->ptr - + TFW_STR_CHUNKN(field) - 1; - /* - * This is not the first data segment, - * so current data starts at @begin. - */ - last->ptr = begin; - tfw_str_updlen(field, end); - } - } else { - /* field->ptr must be set before reaching current state. */ - BUG_ON(!field->ptr); - field->len = end - (unsigned char *)field->ptr; - } - field->flags |= TFW_STR_COMPLETE; -} - /** * GCC 4.8 (CentOS 7) does a poor work on memory reusage of automatic local * variables in nested blocks, so we declare all required temporal variables @@ -101,15 +74,7 @@ st: __attribute__((unused)) \ TFW_DBG("parser: " #st "(%d:%d): c=%#x(%c), r=%d\n", \ st, parser->_i_st, c, isprint(c) ? c : '.', r); -#define __FSM_EXIT(field) \ -do { \ - if (field) { /* staticaly resolved */ \ - tfw_str_updlen(field, data + len); \ - if (unlikely(!tfw_str_add_compound(msg->pool, field))) \ - return TFW_BLOCK; \ - } \ - goto done; \ -} while (0) +#define __FSM_EXIT() goto done; #define FSM_EXIT() \ do { \ @@ -123,25 +88,25 @@ done: \ /* Remaining number of bytes to process in the data chunk. */ \ parser->to_go = len - (size_t)(p - data); -#define ____FSM_MOVE_LAMBDA(to, n, code) \ +#define ____FSM_MOVE_LAMBDA(to, n, field) \ do { \ p += n; \ if (unlikely(p >= data + len || !*p)) { \ r = TFW_POSTPONE; /* postpone to more data available */ \ __fsm_const_state = to; /* start from state @to nest time */\ - /* Close currently parsed header chunk. */ \ - tfw_http_msg_hdr_chunk_fixup(msg, data, len); \ - code; \ + /* Close currently parsed field chunk. */ \ + tfw_http_msg_field_chunk_fixup(msg, field, data, len); \ + __FSM_EXIT() \ } \ c = *p; \ goto to; \ } while (0) #define __FSM_MOVE_nf(to, n, field) \ - ____FSM_MOVE_LAMBDA(to, n, __FSM_EXIT(field)) -#define __FSM_MOVE_n(to, n) __FSM_MOVE_nf(to, n, NULL) + ____FSM_MOVE_LAMBDA(to, n, field) +#define __FSM_MOVE_n(to, n) __FSM_MOVE_nf(to, n, &msg->parser.hdr) #define __FSM_MOVE_f(to, field) __FSM_MOVE_nf(to, 1, field) -#define __FSM_MOVE(to) __FSM_MOVE_nf(to, 1, NULL) +#define __FSM_MOVE(to) __FSM_MOVE_nf(to, 1, &msg->parser.hdr) /* The same as __FSM_MOVE_n(), but exactly for jumps w/o data moving. */ #define __FSM_JMP(to) do { goto to; } while (0) @@ -154,7 +119,7 @@ do { \ #define __FSM_I_MOVE_n(to, n) \ do { \ parser->_i_st = to; \ - ____FSM_MOVE_LAMBDA(to, n, __FSM_I_EXIT()); \ + ____FSM_MOVE_LAMBDA(to, n, &msg->parser.hdr); \ } while (0) #define __FSM_I_MOVE(to) __FSM_I_MOVE_n(to, 1) #define __FSM_I_MOVE_str(to, str) __FSM_I_MOVE_n(to, sizeof(str) - 1) @@ -390,7 +355,7 @@ enum { lambda; \ __FSM_I_MOVE_n(state, sizeof(str) - 1 - __fsm_sz); \ case CSTR_POSTPONE: \ - tfw_http_msg_hdr_chunk_fixup(msg, data, len); \ + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, len); \ case CSTR_BADLEN: \ return r; \ case CSTR_NEQ: /* fall through */ \ @@ -421,7 +386,7 @@ __FSM_STATE(st_curr) { \ && unlikely(!TFW_STR_EMPTY(&(msg)->h_tbl->tbl[id]))) \ return TFW_BLOCK; \ /* Store header name and field in different chunks. */ \ - tfw_http_msg_hdr_chunk_fixup(msg, data, p - data); \ + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, p - data); \ __fsm_n = func(hm, p, __fsm_sz); \ TFW_DBG("parse special header " #func ": ret=%d data_len=%lu id=%d\n", \ __fsm_n, __fsm_sz, id); \ @@ -437,7 +402,7 @@ __FSM_STATE(st_curr) { \ default: \ BUG_ON(__fsm_n < 0); \ /* The header value is fully parsed, move forward. */ \ - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_n); \ + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_n); \ if (tfw_http_msg_hdr_close(msg, id)) \ return TFW_BLOCK; \ parser->_i_st = I_0; \ @@ -466,7 +431,7 @@ __FSM_STATE(st_curr) { \ default: \ BUG_ON(__fsm_n < 0); \ /* The header value is fully parsed, move forward. */ \ - tfw_http_msg_hdr_chunk_fixup(msg, data, p + __fsm_n - data);\ + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, p + __fsm_n - data);\ if (tfw_http_msg_hdr_close(msg, TFW_HTTP_HDR_RAW)) \ return TFW_BLOCK; \ parser->_i_st = I_0; \ @@ -490,7 +455,7 @@ __FSM_STATE(prefix ## _HdrOther) { \ __fsm_ch = memchr(p, '\r', __fsm_sz); \ if (__fsm_ch) { \ /* Get length of the header. */ \ - tfw_http_msg_hdr_chunk_fixup(msg, data, __fsm_ch - data);\ + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, __fsm_ch - data);\ if (tfw_http_msg_hdr_close(msg, TFW_HTTP_HDR_RAW)) \ return TFW_BLOCK; \ __FSM_MOVE_n(RGen_LF, __fsm_ch - p + 1); \ @@ -731,7 +696,7 @@ __parse_content_length(TfwHttpMsg *msg, unsigned char *data, size_t len) r = parse_int_ws(data, len, &msg->content_length); if (r == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, data, len); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, len); return r; } @@ -1082,7 +1047,7 @@ __req_parse_cache_control(TfwHttpReq *req, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; req->cache_ctl.max_age = parser->_tmp_acc; @@ -1094,7 +1059,7 @@ __req_parse_cache_control(TfwHttpReq *req, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; req->cache_ctl.max_fresh = parser->_tmp_acc; @@ -1357,7 +1322,7 @@ tfw_http_parse_req(void *req_data, unsigned char *data, size_t len) /* Host is read, start to read port or abs_path. */ __FSM_STATE(Req_UriHostEnd) { - __field_finish(&req->host, data, p); + tfw_http_msg_field_chunk_fixup(msg, &req->host, data, p - data); if (likely(c == '/')) { tfw_http_msg_set_data(msg, &req->uri_path, p); @@ -1396,11 +1361,10 @@ tfw_http_parse_req(void *req_data, unsigned char *data, size_t len) __FSM_STATE(Req_UriAbsPath) { if (likely(IN_ALPHABET(c, uap_a))) /* Move forward through possibly segmented data. */ - ____FSM_MOVE_LAMBDA(TFW_HTTP_URI_HOOK, 1, - __FSM_EXIT(&req->uri_path)); + __FSM_MOVE_f(TFW_HTTP_URI_HOOK, &req->uri_path); if (likely(c == ' ')) { - __field_finish(&req->uri_path, data, p); + tfw_http_msg_field_chunk_fixup(msg, &req->uri_path, data, p - data); __FSM_MOVE(Req_HttpVer); } @@ -1870,7 +1834,7 @@ __resp_parse_cache_control(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->cache_ctl.max_age = parser->_tmp_acc; @@ -1882,7 +1846,7 @@ __resp_parse_cache_control(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->cache_ctl.s_maxage = parser->_tmp_acc; @@ -2005,7 +1969,7 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) /* Parse a 2-digit day. */ __fsm_n = parse_int_ws(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; if (parser->_tmp_acc < 1) @@ -2077,12 +2041,12 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_ws(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; __fsm_n = __year_day_secs(parser->_tmp_acc, resp->expires); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->expires = __fsm_n; @@ -2095,7 +2059,7 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_a(p, __fsm_sz, colon_a, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->expires = parser->_tmp_acc * 3600; @@ -2108,7 +2072,7 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_a(p, __fsm_sz, colon_a, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->expires = parser->_tmp_acc * 60; @@ -2121,7 +2085,7 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_ws(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->expires = parser->_tmp_acc; @@ -2167,7 +2131,7 @@ __resp_parse_keep_alive(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); + tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->keep_alive = parser->_tmp_acc; From 62b25ff34b3d1b0b5049b8b1e702eb7f4fd36019 Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Fri, 18 Sep 2015 23:53:54 +0300 Subject: [PATCH 2/4] #257. Correct parsing of a splitted request --- tempesta_fw/http_msg.c | 14 +++++++++++++- tempesta_fw/http_msg.h | 1 + tempesta_fw/http_parser.c | 34 +++++++++++++++++----------------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/tempesta_fw/http_msg.c b/tempesta_fw/http_msg.c index 9c8fede6d5..80e9ea2bf6 100644 --- a/tempesta_fw/http_msg.c +++ b/tempesta_fw/http_msg.c @@ -169,12 +169,24 @@ tfw_http_msg_hdr_open(TfwHttpMsg *hm, unsigned char *hdr_start) } /** - * Fixup the new data chunk to currently parsed HTTP field. + * Fixup the new data chunk to currently parsed HTTP header. * * @len could be 0 if the header was fully read, but we realized this only * now by facinng CRLF at begin of current data chunk. */ void +tfw_http_msg_hdr_chunk_fixup(TfwHttpMsg *hm, char *data, int len) +{ + tfw_http_msg_field_chunk_fixup(hm, &hm->parser.hdr, data, len); +} + +/** + * Fixup the new data chunk to currently parsed HTTP field. + * + * @len could be 0 if the field was fully read, but we realized this only + * now by facinng CRLF at begin of current data chunk. + */ +void tfw_http_msg_field_chunk_fixup(TfwHttpMsg *hm, TfwStr *field, char *data, int len) { BUG_ON(field->flags & TFW_STR_DUPLICATE); diff --git a/tempesta_fw/http_msg.h b/tempesta_fw/http_msg.h index 7ed2aff098..f4bc66e605 100644 --- a/tempesta_fw/http_msg.h +++ b/tempesta_fw/http_msg.h @@ -54,6 +54,7 @@ TfwHttpMsg *tfw_http_msg_create(TfwMsgIter *it, int type, size_t data_len); int tfw_http_msg_write(TfwMsgIter *it, TfwHttpMsg *hm, const TfwStr *data); void tfw_http_msg_hdr_open(TfwHttpMsg *hm, unsigned char *hdr_start); +void tfw_http_msg_hdr_chunk_fixup(TfwHttpMsg *hm, char *data, int len); void tfw_http_msg_field_chunk_fixup(TfwHttpMsg *hm, TfwStr *field, char *data, int len); int tfw_http_msg_hdr_close(TfwHttpMsg *hm, int id); diff --git a/tempesta_fw/http_parser.c b/tempesta_fw/http_parser.c index 976e93d9ee..4906d9a4da 100644 --- a/tempesta_fw/http_parser.c +++ b/tempesta_fw/http_parser.c @@ -355,7 +355,7 @@ enum { lambda; \ __FSM_I_MOVE_n(state, sizeof(str) - 1 - __fsm_sz); \ case CSTR_POSTPONE: \ - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, len); \ + tfw_http_msg_hdr_chunk_fixup(msg, data, len); \ case CSTR_BADLEN: \ return r; \ case CSTR_NEQ: /* fall through */ \ @@ -386,7 +386,7 @@ __FSM_STATE(st_curr) { \ && unlikely(!TFW_STR_EMPTY(&(msg)->h_tbl->tbl[id]))) \ return TFW_BLOCK; \ /* Store header name and field in different chunks. */ \ - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, p - data); \ + tfw_http_msg_hdr_chunk_fixup(msg, data, p - data); \ __fsm_n = func(hm, p, __fsm_sz); \ TFW_DBG("parse special header " #func ": ret=%d data_len=%lu id=%d\n", \ __fsm_n, __fsm_sz, id); \ @@ -402,7 +402,7 @@ __FSM_STATE(st_curr) { \ default: \ BUG_ON(__fsm_n < 0); \ /* The header value is fully parsed, move forward. */ \ - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_n); \ + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_n); \ if (tfw_http_msg_hdr_close(msg, id)) \ return TFW_BLOCK; \ parser->_i_st = I_0; \ @@ -431,7 +431,7 @@ __FSM_STATE(st_curr) { \ default: \ BUG_ON(__fsm_n < 0); \ /* The header value is fully parsed, move forward. */ \ - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, p + __fsm_n - data);\ + tfw_http_msg_hdr_chunk_fixup(msg, data, p + __fsm_n - data);\ if (tfw_http_msg_hdr_close(msg, TFW_HTTP_HDR_RAW)) \ return TFW_BLOCK; \ parser->_i_st = I_0; \ @@ -455,7 +455,7 @@ __FSM_STATE(prefix ## _HdrOther) { \ __fsm_ch = memchr(p, '\r', __fsm_sz); \ if (__fsm_ch) { \ /* Get length of the header. */ \ - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, __fsm_ch - data);\ + tfw_http_msg_hdr_chunk_fixup(msg, data, __fsm_ch - data);\ if (tfw_http_msg_hdr_close(msg, TFW_HTTP_HDR_RAW)) \ return TFW_BLOCK; \ __FSM_MOVE_n(RGen_LF, __fsm_ch - p + 1); \ @@ -696,7 +696,7 @@ __parse_content_length(TfwHttpMsg *msg, unsigned char *data, size_t len) r = parse_int_ws(data, len, &msg->content_length); if (r == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, data, len); + tfw_http_msg_hdr_chunk_fixup(msg, data, len); return r; } @@ -1047,7 +1047,7 @@ __req_parse_cache_control(TfwHttpReq *req, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; req->cache_ctl.max_age = parser->_tmp_acc; @@ -1059,7 +1059,7 @@ __req_parse_cache_control(TfwHttpReq *req, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; req->cache_ctl.max_fresh = parser->_tmp_acc; @@ -1834,7 +1834,7 @@ __resp_parse_cache_control(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->cache_ctl.max_age = parser->_tmp_acc; @@ -1846,7 +1846,7 @@ __resp_parse_cache_control(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->cache_ctl.s_maxage = parser->_tmp_acc; @@ -1969,7 +1969,7 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) /* Parse a 2-digit day. */ __fsm_n = parse_int_ws(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; if (parser->_tmp_acc < 1) @@ -2041,12 +2041,12 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_ws(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; __fsm_n = __year_day_secs(parser->_tmp_acc, resp->expires); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->expires = __fsm_n; @@ -2059,7 +2059,7 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_a(p, __fsm_sz, colon_a, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->expires = parser->_tmp_acc * 3600; @@ -2072,7 +2072,7 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_a(p, __fsm_sz, colon_a, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->expires = parser->_tmp_acc * 60; @@ -2085,7 +2085,7 @@ __resp_parse_expires(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_ws(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->expires = parser->_tmp_acc; @@ -2131,7 +2131,7 @@ __resp_parse_keep_alive(TfwHttpResp *resp, unsigned char *data, size_t len) __fsm_sz = len - (size_t)(p - data); __fsm_n = parse_int_list(p, __fsm_sz, &parser->_tmp_acc); if (__fsm_n == CSTR_POSTPONE) - tfw_http_msg_field_chunk_fixup(msg, &msg->parser.hdr, p, __fsm_sz); + tfw_http_msg_hdr_chunk_fixup(msg, p, __fsm_sz); if (__fsm_n < 0) return __fsm_n; resp->keep_alive = parser->_tmp_acc; From 70371c6bb76fa75828f522fa8ef36a80e7555427 Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Tue, 22 Sep 2015 16:37:09 +0300 Subject: [PATCH 3/4] Refactoring --- tempesta_fw/http_msg.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/tempesta_fw/http_msg.c b/tempesta_fw/http_msg.c index 80e9ea2bf6..20800caaab 100644 --- a/tempesta_fw/http_msg.c +++ b/tempesta_fw/http_msg.c @@ -168,18 +168,6 @@ tfw_http_msg_hdr_open(TfwHttpMsg *hm, unsigned char *hdr_start) TFW_DBG("open header at char [%c], skb=%p\n", *hdr_start, hdr->skb); } -/** - * Fixup the new data chunk to currently parsed HTTP header. - * - * @len could be 0 if the header was fully read, but we realized this only - * now by facinng CRLF at begin of current data chunk. - */ -void -tfw_http_msg_hdr_chunk_fixup(TfwHttpMsg *hm, char *data, int len) -{ - tfw_http_msg_field_chunk_fixup(hm, &hm->parser.hdr, data, len); -} - /** * Fixup the new data chunk to currently parsed HTTP field. * @@ -187,7 +175,8 @@ tfw_http_msg_hdr_chunk_fixup(TfwHttpMsg *hm, char *data, int len) * now by facinng CRLF at begin of current data chunk. */ void -tfw_http_msg_field_chunk_fixup(TfwHttpMsg *hm, TfwStr *field, char *data, int len) +tfw_http_msg_field_chunk_fixup(TfwHttpMsg *hm, TfwStr *field, + char *data, int len) { BUG_ON(field->flags & TFW_STR_DUPLICATE); @@ -223,6 +212,18 @@ tfw_http_msg_field_chunk_fixup(TfwHttpMsg *hm, TfwStr *field, char *data, int le } } +/** + * Fixup the new data chunk to currently parsed HTTP header. + * + * @len could be 0 if the header was fully read, but we realized this only + * now by facinng CRLF at begin of current data chunk. + */ +void +tfw_http_msg_hdr_chunk_fixup(TfwHttpMsg *hm, char *data, int len) +{ + tfw_http_msg_field_chunk_fixup(hm, &hm->parser.hdr, data, len); +} + /** * Store fully parsed, probably compound, header (i.e. close it) to * HTTP message headers list. From 59d245d657e0c4ed74c34f57845025c3f8fc407d Mon Sep 17 00:00:00 2001 From: Artyom Belov Date: Tue, 22 Sep 2015 21:03:47 +0300 Subject: [PATCH 4/4] #257. A field finishing fix --- tempesta_fw/http_parser.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tempesta_fw/http_parser.c b/tempesta_fw/http_parser.c index 4906d9a4da..7b9df84916 100644 --- a/tempesta_fw/http_parser.c +++ b/tempesta_fw/http_parser.c @@ -47,6 +47,17 @@ enum { RGen_LF, }; +/** + * Set final field length and mark it as finished. + */ +static inline void +__field_finish(TfwHttpMsg *hm, TfwStr *field, + unsigned char *begin, unsigned char *end) +{ + tfw_http_msg_field_chunk_fixup(hm, field, begin, end - begin); + field->flags |= TFW_STR_COMPLETE; +} + /** * GCC 4.8 (CentOS 7) does a poor work on memory reusage of automatic local * variables in nested blocks, so we declare all required temporal variables @@ -1322,7 +1333,7 @@ tfw_http_parse_req(void *req_data, unsigned char *data, size_t len) /* Host is read, start to read port or abs_path. */ __FSM_STATE(Req_UriHostEnd) { - tfw_http_msg_field_chunk_fixup(msg, &req->host, data, p - data); + __field_finish(msg, &req->host, data, p); if (likely(c == '/')) { tfw_http_msg_set_data(msg, &req->uri_path, p); @@ -1364,7 +1375,7 @@ tfw_http_parse_req(void *req_data, unsigned char *data, size_t len) __FSM_MOVE_f(TFW_HTTP_URI_HOOK, &req->uri_path); if (likely(c == ' ')) { - tfw_http_msg_field_chunk_fixup(msg, &req->uri_path, data, p - data); + __field_finish(msg, &req->uri_path, data, p); __FSM_MOVE(Req_HttpVer); }