#34 实现HTTP解析层的Suspend/Resume操作
This commit is contained in:
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user