Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#257. Correct parsing of a splitted request #273

Merged
merged 4 commits into from
Sep 22, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 27 additions & 16 deletions tempesta_fw/http_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -169,50 +169,61 @@ 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
* @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_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(field->flags & TFW_STR_DUPLICATE);

BUG_ON(hdr->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);
}
}

/**
* 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.
Expand Down
2 changes: 2 additions & 0 deletions tempesta_fw/http_msg.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ 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);

Expand Down
55 changes: 15 additions & 40 deletions tempesta_fw/http_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,10 @@ enum {
* Set final field length and mark it as finished.
*/
static inline void
__field_finish(TfwStr *field, unsigned char *begin, unsigned char *end)
__field_finish(TfwHttpMsg *hm, 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;
}
tfw_http_msg_field_chunk_fixup(hm, field, begin, end - begin);
field->flags |= TFW_STR_COMPLETE;
}

Expand Down Expand Up @@ -101,15 +85,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 { \
Expand All @@ -123,25 +99,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)

Expand All @@ -154,7 +130,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)
Expand Down Expand Up @@ -1357,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) {
__field_finish(&req->host, data, p);
__field_finish(msg, &req->host, data, p);

if (likely(c == '/')) {
tfw_http_msg_set_data(msg, &req->uri_path, p);
Expand Down Expand Up @@ -1396,11 +1372,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);
__field_finish(msg, &req->uri_path, data, p);
__FSM_MOVE(Req_HttpVer);
}

Expand Down