Close #60 修正POST请求无Content-Length字段时无法转发请求的问题

* 部分HTTP POST请求中无有Content-Length字段,导致无法确定请求的边界。
* 现修正为,当发现Content-Length字段缺失时,Passthrough整个TCP连接。
* TODO: 解析POST编码或回应411应答。
This commit is contained in:
Lu Qiuwen
2018-10-25 16:47:19 +08:00
parent 5525e5a8e6
commit 0cd191b9e6
3 changed files with 34 additions and 4 deletions

View File

@@ -95,6 +95,8 @@ struct http_half_private
/* UPGRADE */
bool is_upgrade;
/* PASSTHROUGH */
bool is_passthrough;
};
struct http_half_private * hf_private_create(tfe_http_direction ht_dir, short major, short minor);

View File

@@ -362,6 +362,11 @@ enum tfe_stream_action __http_connection_entry_on_request(const struct tfe_strea
}
/* Some kind of error happened, write log and detach the stream */
if (ret == -1 && hf_private_req_in->is_passthrough)
{
goto __errout;
}
if (ret == -1)
{
TFE_STREAM_LOG_ERROR(stream, "Failed at parsing stream as HTTP: %u, %s, %s",
@@ -475,6 +480,12 @@ enum tfe_stream_action __http_connection_entry_on_response(const struct tfe_stre
return hf_private_resp_in->stream_action;
}
/* Need to passthrough */
if (ret == -1 && hf_private_resp_in->is_passthrough)
{
goto __errout;
}
/* Some kind of error happened, write log and detach the stream */
if (ret == -1)
{

View File

@@ -172,6 +172,8 @@ 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;
hf_private->method_or_status = (enum tfe_http_std_method) parser->method;
const static struct http_field_name __host_field_name = {TFE_HTTP_HOST, NULL};
hf_req_spec->host = (char *) tfe_http_field_read(hf_public, &__host_field_name);
@@ -320,6 +322,16 @@ static int __parser_callback_on_headers_complete(http_parser * parser)
__hf_public_resp_fill_from_private(hf_private, parser);
}
/* for POST, must contains 'content-length' */
if (hf_direction == TFE_HTTP_REQUEST && hf_private->method_or_status == TFE_HTTP_METHOD_POST)
{
const static struct http_field_name __cont_encoding_field_name = {TFE_HTTP_CONT_LENGTH, NULL};
char * __str_content_length = (char *) tfe_http_field_read(hf_public, &__cont_encoding_field_name);
/* Does not contain a content-length, passthrough the whole TCP connection */
if (unlikely(__str_content_length == NULL)) { hf_private->is_passthrough = true; return -1;}
}
tfe_http_event event = (hf_direction == TFE_HTTP_REQUEST) ? EV_HTTP_REQ_HDR : EV_HTTP_RESP_HDR;
if (hf_private->event_cb)
{
@@ -334,8 +346,8 @@ static int __parser_callback_on_headers_complete(http_parser * parser)
hf_private->stream_action = hf_private->user_stream_action;
}
/* user's suspend tag is set, which indicate that the way to handle request/response
* cannot be determinate at now, need to defer */
/* user's suspend tag is set, which indicate that the way to handle request/response
* cannot be determinate at now, need to defer */
else if (hs_private && hs_private->suspend_tag_user)
{
/* Pause parser, prevent to parse request/response body,
@@ -1095,9 +1107,14 @@ void __write_access_log(struct http_session_private * hs_private)
/* Upgrade Tag */
const char * __str_upgrade = response ? response->is_upgrade ? "UPGRADE" : "-" : "-";
/* PASSTHROUGH */
const char * __str_req_passthrough = request ? request->is_passthrough ? "PASS-THROUGH/REQ" : "-" : "-";
const char * __str_resp_passthrough = response ? response->is_passthrough ? "PASS-THROUGH/REP" : "-" : "-";
char * __access_log;
asprintf(&__access_log, "%d %s %s HTTP/%d.%d %s %s %s %s", hs_private->hs_public.session_id, __str_method,
__str_url, request->major, request->minor, __str_resp_code, __str_cont_type, __str_cont_encoding, __str_upgrade);
asprintf(&__access_log, "%d %s %s HTTP/%d.%d %s %s %s %s %s %s", hs_private->hs_public.session_id, __str_method,
__str_url, request->major, request->minor, __str_resp_code, __str_cont_type, __str_cont_encoding,
__str_upgrade, __str_req_passthrough, __str_resp_passthrough);
const struct tfe_stream * stream = hs_private->hc_private->stream;
tfe_stream_write_access_log(stream, RLOG_LV_INFO, "%s", __access_log);