#34 实现HTTP解析层的Suspend/Resume操作

This commit is contained in:
Lu Qiuwen
2018-10-11 10:41:27 +08:00
committed by zhengchao
parent adb469395c
commit b8342e5358
9 changed files with 132 additions and 29 deletions

View File

@@ -11,6 +11,7 @@
#include <tfe_utils.h>
#include <http_half.h>
#include <http_convert.h>
#include <event.h>
#define __PARSER_TO_HF_PRIVATE(_parser) ((struct http_half_private *)(_parser->data))
@@ -285,6 +286,7 @@ static int __parser_callback_on_headers_complete(http_parser * parser)
{
struct http_half_private * hf_private = __PARSER_TO_HF_PRIVATE(parser);
enum tfe_http_direction hf_direction = hf_private->hf_public.direction;
struct http_session_private * hs_private = hf_private->session;
if (evbuffer_get_length(hf_private->evbuf_header_field) != 0)
{
@@ -296,10 +298,10 @@ static int __parser_callback_on_headers_complete(http_parser * parser)
hf_public->minor_version = parser->http_minor;
/* Copy version to session */
if (hf_private->session != NULL)
if (hs_private != NULL)
{
to_hs_public(hf_private->session)->major_version = hf_public->major_version;
to_hs_public(hf_private->session)->minor_version = hf_public->minor_version;
to_hs_public(hs_private)->major_version = hf_public->major_version;
to_hs_public(hs_private)->minor_version = hf_public->minor_version;
}
if (hf_direction == TFE_HTTP_REQUEST)
@@ -311,20 +313,37 @@ static int __parser_callback_on_headers_complete(http_parser * parser)
__hf_public_resp_fill_from_private(hf_private, parser);
}
if (hf_private->event_cb && hf_direction == TFE_HTTP_REQUEST)
tfe_http_event event = (hf_direction == TFE_HTTP_REQUEST) ? EV_HTTP_REQ_HDR : EV_HTTP_RESP_HDR;
if (hf_private->event_cb)
{
hf_private->event_cb(hf_private, EV_HTTP_REQ_HDR, NULL, 0, hf_private->event_cb_user);
}
if (hf_private->event_cb && hf_direction == TFE_HTTP_RESPONSE)
{
hf_private->event_cb(hf_private, EV_HTTP_RESP_HDR, NULL, 0, hf_private->event_cb_user);
}
/* The setup of user stream option indicates that the way to handle the request/response has
* been decided, we should conform the resolution */
if (hf_private->is_user_stream_action_set)
{
assert(hf_private->stream_action == ACTION_DEFER_DATA);
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 */
else if (hs_private && hs_private->suspend_tag_user)
{
/* Pause parser, prevent to parse request/response body,
* The body should be parsed after resume() */
http_parser_pause(parser, 1);
/* Record the event, this event will be trigger again at resume() */
hs_private->suspend_event = event;
/* Suspend must be setup at DEFER status.
* The request/response cannot be suspend once any bytes has been forwarded to upstream */
assert(hf_private->stream_action == ACTION_DEFER_DATA);
}
/* Otherwise, forward the request/response */
else
{
hf_private->stream_action = ACTION_FORWARD_DATA;
@@ -468,23 +487,24 @@ int hf_ops_field_write(struct tfe_http_half * half, const struct http_field_name
TAILQ_FOREACH(__header_iter, &hf_private->header_list, next)
{
if (http_field_name_compare(__header_iter->field, field) != 0) continue;
__header_found = __header_iter; break;
__header_found = __header_iter;
break;
}
/* Update the value */
if(__header_found != NULL && value != NULL)
if (__header_found != NULL && value != NULL)
{
free(__header_found->value);
__header_found->value = tfe_strdup(value);
}
/* Delete the key and value */
/* Delete the key and value */
else if (__header_found != NULL && value == NULL)
{
TAILQ_REMOVE(&hf_private->header_list, __header_found, next);
free(__header_found->value);
free(__header_found);
}
/* Insert a new header k-v in the tail of the header list */
/* Insert a new header k-v in the tail of the header list */
else if (__header_found == NULL && value != NULL)
{
struct http_header_private * __header = ALLOC(struct http_header_private, 1);
@@ -492,7 +512,7 @@ int hf_ops_field_write(struct tfe_http_half * half, const struct http_field_name
__header->value = tfe_strdup(value);
TAILQ_INSERT_TAIL(&hf_private->header_list, __header, next);
}
/* Nothing found, and delete nothing */
/* Nothing found, and delete nothing */
else
{
return -1;
@@ -648,18 +668,23 @@ int hf_private_parse(struct http_half_private * hf_private, const unsigned char
size_t sz_parsed = http_parser_execute(hf_private->parse_object,
&__http_half_parse_setting, __data_with_offset, __len_with_offset);
/* Nothing happended */
bool __is_paused = false;
if (HTTP_PARSER_ERRNO(hf_private->parse_object) == HPE_PAUSED)
{
http_parser_pause(hf_private->parse_object, 0);
__is_paused = true;
}
if (sz_parsed == __len_with_offset)
{
hf_private->parse_cursor += sz_parsed;
return HTTP_PARSER_ERRNO(hf_private->parse_object) == HPE_PAUSED ? 1 : 0;
return __is_paused ? 1 : 0;
}
/* The paused parsar indicate the message boundary has been touched, we should return.
* resume it to normal status */
if (HTTP_PARSER_ERRNO(hf_private->parse_object) == HPE_PAUSED)
if (__is_paused)
{
http_parser_pause(hf_private->parse_object, 0);
hf_private->parse_cursor += sz_parsed + 1;
return 1;
}
@@ -682,8 +707,18 @@ void hs_ops_detach(const struct tfe_http_session * session)
}
void hs_ops_drop(struct tfe_http_session * session)
{}
void hs_ops_suspend(struct tfe_http_session * session)
{
return;
struct http_session_private * hs_private = to_hs_private(session);
hs_private->suspend_tag_user = true;
}
void hs_ops_resume(struct tfe_http_session * session)
{
struct http_session_private * hs_private = to_hs_private(session);
hs_private->suspend_tag_user = false;
}
// TODO: change the return type to int, there is something happend where -1 returned.
@@ -781,6 +816,8 @@ struct tfe_http_session_ops __http_session_ops =
.ops_allow_write = hs_ops_allow_write,
.ops_detach = hs_ops_detach,
.ops_drop = hs_ops_drop,
.ops_suspend = hs_ops_suspend,
.ops_resume = hs_ops_resume,
.ops_request_set = hs_ops_request_set,
.ops_response_set = hs_ops_response_set,
.ops_request_create = hs_ops_request_create,