修正HTTP解析层处理HTTP-Header的错误流程
* 原流程在解析同一个Field-Value对时,无法正确处理Header多次调用拼成完整字符串的情况,现修正; * 原流程在处理Field-Value底层Buffer时计算长度有误,导致清空buffer时剩余最后的'\0',现修正。
This commit is contained in:
@@ -51,8 +51,12 @@ struct http_half_private
|
||||
short minor;
|
||||
|
||||
struct evbuffer * evbuf_uri;
|
||||
|
||||
struct evbuffer * evbuf_header_field;
|
||||
struct evbuffer * evbuf_header_value;
|
||||
bool is_evbuf_header_field_set;
|
||||
bool is_evbuf_header_value_set;
|
||||
|
||||
struct evbuffer * evbuf_body;
|
||||
|
||||
enum hf_private_status body_status;
|
||||
@@ -64,6 +68,7 @@ struct http_half_private
|
||||
};
|
||||
|
||||
struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short major, short minor);
|
||||
|
||||
void hf_private_destory(struct http_half_private * hf_private);
|
||||
|
||||
/** Parse the raw tcp input for HTTP half structure
|
||||
@@ -83,5 +88,7 @@ int hf_private_parse(struct http_half_private * hf_private, const unsigned char
|
||||
void hf_private_set_callback(struct http_half_private * hf_private, hf_private_cb * cb,
|
||||
void * user, void (* fn_user_deleter)(void *));
|
||||
|
||||
void hf_private_set_session(struct http_half_private * hf_private, struct http_session_private * hs_private);
|
||||
|
||||
struct http_session_private * hs_private_create(struct http_connection_private * hc_private,
|
||||
struct http_half_private * hf_private_req, struct http_half_private * hf_private_resp);
|
||||
|
||||
@@ -67,6 +67,7 @@ enum tfe_stream_action __http_connection_entry_on_request(const struct tfe_strea
|
||||
/* HTTP Request and Session */
|
||||
hf_private_request = hf_private_create(TFE_HTTP_REQUEST, 1, 0);
|
||||
hs_private = hs_private_create(hc_private, hf_private_request, NULL);
|
||||
hf_private_set_session(hf_private_request, hs_private);
|
||||
|
||||
/* Closure, catch stream, session and thread_id */
|
||||
struct user_event_dispatch_closure * __closure = ALLOC(struct user_event_dispatch_closure, 1);
|
||||
@@ -139,13 +140,13 @@ enum tfe_stream_action __http_connection_entry_on_response(const struct tfe_stre
|
||||
int __http_connection_identify(const struct tfe_stream * stream,
|
||||
struct http_connection_private * ht_conn, const unsigned char * data, size_t len)
|
||||
{
|
||||
struct http_half_private * hf_private = hf_private_create(TFE_HTTP_RESPONSE, 1, 0);
|
||||
struct http_half_private * hf_private = hf_private_create(TFE_HTTP_REQUEST, 1, 0);
|
||||
int ret = hf_private_parse(hf_private, data, len);
|
||||
hf_private_destory(hf_private);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define HTTP_INDENTIFY_LENGTH 8
|
||||
#define HTTP_INDENTIFY_LENGTH 4
|
||||
|
||||
enum tfe_stream_action http_connection_entry_data(const struct tfe_stream * stream, unsigned int thread_id,
|
||||
enum tfe_conn_dir dir, const unsigned char * data, size_t len, void ** pme)
|
||||
@@ -159,12 +160,7 @@ enum tfe_stream_action http_connection_entry_data(const struct tfe_stream * stre
|
||||
goto __detach;
|
||||
|
||||
/* Protocol Identification, we need 8 bytes at least to tell it is HTTP or not */
|
||||
if (len < HTTP_INDENTIFY_LENGTH)
|
||||
{
|
||||
static const unsigned int __defer_bytes = HTTP_INDENTIFY_LENGTH;
|
||||
tfe_stream_action_set_opt(stream, ACTION_OPT_DEFER_BYTES, (void *) &__defer_bytes, sizeof(__defer_bytes));
|
||||
return ACTION_DEFER_DATA;
|
||||
}
|
||||
if (len < HTTP_INDENTIFY_LENGTH) goto __detach;
|
||||
|
||||
/* Now, we want to identify this stream */
|
||||
int ret = __http_connection_identify(stream, ht_conn, data, len);
|
||||
|
||||
@@ -84,6 +84,8 @@ static void __http_half_header_kv_complete(struct http_half_private * hf_private
|
||||
/* Write a '\0' for evbuffers */
|
||||
evbuffer_add(hf_private->evbuf_header_field, &__zero, sizeof(__zero));
|
||||
evbuffer_add(hf_private->evbuf_header_value, &__zero, sizeof(__zero));
|
||||
sz_evbuf_field = evbuffer_get_length(hf_private->evbuf_header_field);
|
||||
sz_evbuf_value = evbuffer_get_length(hf_private->evbuf_header_value);
|
||||
|
||||
/* Convert evbuffer to const char * pair */
|
||||
str_field = (const char *) evbuffer_pullup(hf_private->evbuf_header_field, sz_evbuf_field);
|
||||
@@ -107,6 +109,8 @@ static void __http_half_header_kv_complete(struct http_half_private * hf_private
|
||||
__clear_buffer:
|
||||
evbuffer_drain(hf_private->evbuf_header_field, sz_evbuf_field);
|
||||
evbuffer_drain(hf_private->evbuf_header_value, sz_evbuf_value);
|
||||
hf_private->is_evbuf_header_value_set = false;
|
||||
hf_private->is_evbuf_header_field_set = false;
|
||||
}
|
||||
|
||||
void __hf_public_req_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser)
|
||||
@@ -117,10 +121,10 @@ void __hf_public_req_fill_from_private(struct http_half_private * hf_private, st
|
||||
/* accept-encoding, host is located in header's K-V structure */
|
||||
hf_req_spec->method = (enum tfe_http_std_method) parser->method;
|
||||
const static struct http_field_name __host_field_name =
|
||||
{
|
||||
.field_id = TFE_HTTP_HOST,
|
||||
.field_name = NULL
|
||||
};
|
||||
{
|
||||
.field_id = TFE_HTTP_HOST,
|
||||
.field_name = NULL
|
||||
};
|
||||
|
||||
hf_req_spec->host = (char *) tfe_http_field_read(hf_public, &__host_field_name);
|
||||
|
||||
@@ -131,7 +135,7 @@ void __hf_public_req_fill_from_private(struct http_half_private * hf_private, st
|
||||
|
||||
/* TODO: URL
|
||||
* url is more complex. need to review RFC */
|
||||
hf_req_spec->url = NULL;
|
||||
hf_req_spec->url = hf_req_spec->uri;
|
||||
}
|
||||
|
||||
void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, struct http_parser * parser)
|
||||
@@ -142,10 +146,10 @@ void __hf_public_resp_fill_from_private(struct http_half_private * hf_private, s
|
||||
/* Status Code */
|
||||
hf_resp_spec->resp_code = parser->status_code;
|
||||
const static struct http_field_name __cont_encoding_field_name =
|
||||
{
|
||||
.field_id = TFE_HTTP_CONT_ENCODING,
|
||||
.field_name = NULL
|
||||
};
|
||||
{
|
||||
.field_id = TFE_HTTP_CONT_ENCODING,
|
||||
.field_name = NULL
|
||||
};
|
||||
|
||||
/* Content Encoding */
|
||||
hf_resp_spec->content_encoding = (char *) tfe_http_field_read(hf_public, &__cont_encoding_field_name);
|
||||
@@ -164,11 +168,13 @@ static int __parser_callback_on_message_begin(struct http_parser * parser)
|
||||
assert(hf_private->evbuf_uri == NULL && hf_private->evbuf_body == NULL);
|
||||
assert(hf_private->evbuf_header_field == NULL && hf_private->evbuf_header_value == NULL);
|
||||
|
||||
hf_private->evbuf_uri = evbuffer_new();
|
||||
hf_private->evbuf_header_field = evbuffer_new();
|
||||
hf_private->evbuf_header_value = evbuffer_new();
|
||||
hf_private->evbuf_body = evbuffer_new();
|
||||
hf_private->is_evbuf_header_field_set = false;
|
||||
hf_private->is_evbuf_header_value_set = false;
|
||||
|
||||
hf_private->evbuf_uri = evbuffer_new();
|
||||
hf_private->evbuf_body = evbuffer_new();
|
||||
hf_private->body_status = STATUS_INIT;
|
||||
hf_private->message_status = STATUS_READING;
|
||||
|
||||
@@ -186,19 +192,19 @@ static int __parser_callback_on_uri_field(struct http_parser * parser, const cha
|
||||
static int __parser_callback_on_header_field(struct http_parser * parser, const char * at, size_t length)
|
||||
{
|
||||
struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser);
|
||||
|
||||
/* Last field-value tuple doesn't push into hf_private, flush these */
|
||||
if (evbuffer_get_length(hf_private->evbuf_header_field) != 0)
|
||||
if (hf_private->is_evbuf_header_field_set && hf_private->is_evbuf_header_value_set)
|
||||
{
|
||||
__http_half_header_kv_complete(hf_private);
|
||||
}
|
||||
|
||||
hf_private->is_evbuf_header_field_set = true;
|
||||
return evbuffer_add(hf_private->evbuf_header_field, at, length);
|
||||
}
|
||||
|
||||
static int __parser_callback_on_header_value(struct http_parser * parser, const char * at, size_t length)
|
||||
{
|
||||
struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser);
|
||||
hf_private->is_evbuf_header_value_set = true;
|
||||
return evbuffer_add(hf_private->evbuf_header_value, at, length);
|
||||
}
|
||||
|
||||
@@ -429,6 +435,8 @@ struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short ma
|
||||
|
||||
hf_private->parse_settings = &__http_half_parse_setting;
|
||||
hf_private->parse_object->data = hf_private;
|
||||
|
||||
TAILQ_INIT(&hf_private->header_list);
|
||||
return hf_private;
|
||||
}
|
||||
|
||||
@@ -440,6 +448,11 @@ void hf_private_set_callback(struct http_half_private * hf_private, hf_private_c
|
||||
hf_private->event_cb_user_deleter = user_deleter;
|
||||
}
|
||||
|
||||
void hf_private_set_session(struct http_half_private * hf_private, struct http_session_private * hs_private)
|
||||
{
|
||||
hf_private->session = hs_private;
|
||||
}
|
||||
|
||||
int hf_private_parse(struct http_half_private * hf_private, const unsigned char * data, size_t len)
|
||||
{
|
||||
assert(hf_private->parse_cursor <= len);
|
||||
|
||||
Reference in New Issue
Block a user