支持缓存校验。
This commit is contained in:
@@ -282,6 +282,7 @@ error_out:
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
struct replace_ctx
|
||||
{
|
||||
struct replace_rule * rule;
|
||||
@@ -304,17 +305,24 @@ struct pangu_http_ctx
|
||||
char * enforce_para;
|
||||
|
||||
struct replace_ctx * rep_ctx;
|
||||
|
||||
int resume_from_cache_query;
|
||||
|
||||
int (* resumed_cb)(const struct tfe_stream * stream,
|
||||
const struct tfe_http_session * session, enum tfe_http_event event, const unsigned char * data,
|
||||
size_t datalen, unsigned int thread_id, struct pangu_http_ctx* ctx);
|
||||
|
||||
enum cache_pending_result pending_result;
|
||||
enum cache_query_status cache_query_status;
|
||||
struct future* f_cache_query;
|
||||
struct future *f_cache_pending, *f_cache_query;
|
||||
struct tfe_http_session * ref_session;
|
||||
struct tfe_http_half* cache_revalidate_req;
|
||||
struct tfe_http_half* cached_response;
|
||||
size_t cache_result_declared_sz, cache_result_actual_sz;
|
||||
struct cache_update_context* cache_update_ctx;
|
||||
|
||||
int thread_id;
|
||||
};
|
||||
|
||||
|
||||
void http_repl_ctx_free(struct replace_ctx* rep_ctx)
|
||||
{
|
||||
for (size_t i = 0; i < rep_ctx->n_rule; i++)
|
||||
@@ -501,81 +509,7 @@ static void html_free(char ** page_buff)
|
||||
FREE(page_buff);
|
||||
return;
|
||||
}
|
||||
static void cache_query_on_succ(future_result_t * result, void * user)
|
||||
{
|
||||
struct pangu_http_ctx * ctx = (struct pangu_http_ctx *)user;
|
||||
struct cached_meta* meta=NULL;
|
||||
enum cache_query_result_type type=cache_query_result_get_type(result);
|
||||
const unsigned char* data=NULL;
|
||||
size_t data_sz=0;
|
||||
char temp[TFE_STRING_MAX];
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case CACHE_QUERY_RESULT_META:
|
||||
meta=cache_query_result_get_header(result);
|
||||
ctx->cache_result_declared_sz=meta->content_length;
|
||||
ctx->resume_from_cache_query=1;
|
||||
tfe_http_session_resume(ctx->ref_session);
|
||||
|
||||
ctx->cached_response=tfe_http_session_response_create(ctx->ref_session, 200);
|
||||
tfe_http_nonstd_field_write(ctx->cached_response, "X-Cache-Lookup", "Hit From TFE");
|
||||
tfe_http_std_field_write(ctx->cached_response, TFE_HTTP_CONT_TYPE, meta->content_type);
|
||||
snprintf(temp, sizeof(temp), "%lu", meta->content_length);
|
||||
tfe_http_std_field_write(ctx->cached_response, TFE_HTTP_CONT_LENGTH, temp);
|
||||
|
||||
tfe_http_session_response_set(ctx->ref_session, ctx->cached_response);
|
||||
tfe_http_half_write_body_begin(ctx->cached_response, 1);
|
||||
|
||||
cache_query_free_meta(meta);
|
||||
meta=NULL;
|
||||
break;
|
||||
case CACHE_QUERY_RESULT_DATA:
|
||||
data_sz=cache_query_result_get_data(result, &data);
|
||||
tfe_http_half_write_body_data(ctx->cached_response, data, data_sz);
|
||||
ctx->cache_result_actual_sz+=data_sz;
|
||||
break;
|
||||
case CACHE_QUERY_RESULT_END:
|
||||
assert(ctx->cached_response!=NULL);
|
||||
ctx->cache_query_status=WEB_CACHE_HIT;
|
||||
tfe_http_half_write_body_end(ctx->cached_response);
|
||||
//ownership has been transferred to http session, set to NULL.
|
||||
ctx->cached_response=NULL;
|
||||
assert(ctx->cache_result_actual_sz==ctx->cache_result_declared_sz);
|
||||
future_destroy(ctx->f_cache_query);
|
||||
ctx->f_cache_query=NULL;
|
||||
break;
|
||||
case CACHE_QUERY_RESULT_MISS:
|
||||
ctx->cache_query_status=WEB_CACHE_NOT_HIT;
|
||||
ctx->resume_from_cache_query=1;
|
||||
tfe_http_session_resume(ctx->ref_session);
|
||||
future_destroy(ctx->f_cache_query);
|
||||
ctx->f_cache_query=NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
static void cache_query_on_fail(enum e_future_error err, const char * what, void * user)
|
||||
{
|
||||
struct pangu_http_ctx * ctx = (struct pangu_http_ctx *)user;
|
||||
future_destroy(ctx->f_cache_query);
|
||||
ctx->f_cache_query=NULL;
|
||||
ctx->cache_query_status=WEB_CACHE_NOT_HIT;
|
||||
ctx->resume_from_cache_query=1;
|
||||
if(!ctx->cached_response)
|
||||
{
|
||||
tfe_http_session_resume(ctx->ref_session);
|
||||
}
|
||||
else
|
||||
{
|
||||
tfe_http_half_write_body_end(ctx->cached_response);
|
||||
ctx->cached_response=NULL;
|
||||
}
|
||||
|
||||
printf("cache query failed: %s %s\n", ctx->ref_session->req->req_spec.url, what);
|
||||
}
|
||||
void http_replace(const struct tfe_stream * stream, const struct tfe_http_session * session,
|
||||
enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, struct pangu_http_ctx * ctx)
|
||||
{
|
||||
@@ -950,27 +884,201 @@ void enforce_control_policy(const struct tfe_stream * stream, const struct tfe_h
|
||||
}
|
||||
return;
|
||||
}
|
||||
void cache_query(const struct tfe_http_session * session, unsigned int thread_id, struct pangu_http_ctx * ctx)
|
||||
#define RESUMED_CB_NO_MORE_CALLS 0
|
||||
#define RESUMED_CB_MORE_CALLS 1
|
||||
int make_revalidate_request(const struct tfe_stream * stream, const struct tfe_http_session * session,
|
||||
enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, unsigned int thread_id, struct pangu_http_ctx * ctx)
|
||||
{
|
||||
ctx->f_cache_query=future_create("cache_get", cache_query_on_succ, cache_query_on_fail, ctx);
|
||||
ctx->cache_query_status=async_web_cache_query(g_pangu_rt->cache, thread_id, session->req, ctx->f_cache_query);
|
||||
if(ctx->cache_query_status==WEB_CACHE_QUERING)
|
||||
assert(ctx->cache_revalidate_req);
|
||||
if(events & EV_HTTP_REQ_BODY_BEGIN)
|
||||
{
|
||||
ctx->ref_session=tfe_http_session_allow_write(session);
|
||||
tfe_http_session_suspend(ctx->ref_session);
|
||||
tfe_http_half_write_body_begin(ctx->cache_revalidate_req, 1);
|
||||
}
|
||||
if(events & EV_HTTP_REQ_BODY_CONT)
|
||||
{
|
||||
tfe_http_half_write_body_data(ctx->cache_revalidate_req, body_frag, frag_size);
|
||||
}
|
||||
if(events & EV_HTTP_REQ_BODY_END)
|
||||
{
|
||||
tfe_http_half_write_body_end(ctx->cache_revalidate_req);
|
||||
ctx->cache_revalidate_req=NULL;
|
||||
return RESUMED_CB_NO_MORE_CALLS;
|
||||
}
|
||||
return RESUMED_CB_MORE_CALLS;
|
||||
}
|
||||
int dummy_resume(const struct tfe_stream * stream, const struct tfe_http_session * session,
|
||||
enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, unsigned int thread_id, struct pangu_http_ctx * ctx)
|
||||
{
|
||||
return RESUMED_CB_NO_MORE_CALLS;
|
||||
}
|
||||
|
||||
static void cache_query_on_succ(future_result_t * result, void * user)
|
||||
{
|
||||
struct pangu_http_ctx * ctx = (struct pangu_http_ctx *)user;
|
||||
const struct cached_meta* meta=NULL;
|
||||
enum cache_query_result_type type=cache_query_result_get_type(result);
|
||||
const unsigned char* data=NULL;
|
||||
size_t data_sz=0;
|
||||
char temp[TFE_STRING_MAX];
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case CACHE_QUERY_RESULT_META:
|
||||
meta=cache_query_result_read_meta(result);
|
||||
ctx->cache_result_declared_sz=meta->content_length;
|
||||
ctx->resumed_cb=dummy_resume;
|
||||
tfe_http_session_resume(ctx->ref_session);
|
||||
|
||||
ctx->cached_response=tfe_http_session_response_create(ctx->ref_session, 200);
|
||||
tfe_http_nonstd_field_write(ctx->cached_response, "X-Cache-Lookup", "Hit From TFE");
|
||||
tfe_http_std_field_write(ctx->cached_response, TFE_HTTP_CONT_TYPE, meta->content_type);
|
||||
snprintf(temp, sizeof(temp), "%lu", meta->content_length);
|
||||
tfe_http_std_field_write(ctx->cached_response, TFE_HTTP_CONT_LENGTH, temp);
|
||||
|
||||
tfe_http_session_response_set(ctx->ref_session, ctx->cached_response);
|
||||
tfe_http_half_write_body_begin(ctx->cached_response, 1);
|
||||
|
||||
meta=NULL;
|
||||
break;
|
||||
case CACHE_QUERY_RESULT_DATA:
|
||||
data_sz=cache_query_result_get_data(result, &data);
|
||||
tfe_http_half_write_body_data(ctx->cached_response, data, data_sz);
|
||||
ctx->cache_result_actual_sz+=data_sz;
|
||||
break;
|
||||
case CACHE_QUERY_RESULT_END:
|
||||
assert(ctx->cached_response!=NULL);
|
||||
ctx->cache_query_status=WEB_CACHE_HIT;
|
||||
tfe_http_half_write_body_end(ctx->cached_response);
|
||||
//ownership has been transferred to http session, set to NULL.
|
||||
ctx->cached_response=NULL;
|
||||
assert(ctx->cache_result_actual_sz==ctx->cache_result_declared_sz);
|
||||
future_destroy(ctx->f_cache_query);
|
||||
ctx->f_cache_query=NULL;
|
||||
break;
|
||||
case CACHE_QUERY_RESULT_MISS:
|
||||
ctx->cache_query_status=WEB_CACHE_MISS;
|
||||
ctx->resumed_cb=dummy_resume;
|
||||
tfe_http_session_resume(ctx->ref_session);
|
||||
future_destroy(ctx->f_cache_query);
|
||||
ctx->f_cache_query=NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
static void cache_query_on_fail(enum e_future_error err, const char * what, void * user)
|
||||
{
|
||||
struct pangu_http_ctx * ctx = (struct pangu_http_ctx *)user;
|
||||
future_destroy(ctx->f_cache_query);
|
||||
ctx->f_cache_query=NULL;
|
||||
ctx->cache_query_status=WEB_CACHE_MISS;
|
||||
if(!ctx->cached_response)
|
||||
{
|
||||
tfe_http_session_resume(ctx->ref_session);
|
||||
ctx->resumed_cb=dummy_resume;
|
||||
}
|
||||
else
|
||||
{
|
||||
future_destroy(ctx->f_cache_query);
|
||||
ctx->f_cache_query=NULL;
|
||||
tfe_http_half_write_body_end(ctx->cached_response);
|
||||
ctx->cached_response=NULL;
|
||||
}
|
||||
|
||||
printf("cache query failed: %s %s\n", ctx->ref_session->req->req_spec.url, what);
|
||||
}
|
||||
static void cache_pending_on_succ(future_result_t * result, void * user)
|
||||
{
|
||||
struct pangu_http_ctx * ctx = (struct pangu_http_ctx *)user;
|
||||
const struct cached_meta* meta=NULL;
|
||||
meta=cache_pending_result_read_meta(result);
|
||||
ctx->resumed_cb=dummy_resume;
|
||||
tfe_http_session_resume(ctx->ref_session);
|
||||
future_destroy(ctx->f_cache_pending);
|
||||
ctx->f_cache_pending=NULL;
|
||||
if(meta==NULL)
|
||||
{
|
||||
ctx->pending_result==PENDING_RESULT_MISS;
|
||||
return;
|
||||
}
|
||||
if(!(meta->etag && meta->last_modified))
|
||||
{
|
||||
ctx->pending_result==PENDING_RESULT_FOBIDDEN;
|
||||
return;
|
||||
}
|
||||
ctx->pending_result=PENDING_RESULT_REVALIDATE;
|
||||
struct http_field_name in_field_name;
|
||||
const char * in_header_value = NULL;
|
||||
void * iterator = NULL;
|
||||
ctx->cache_revalidate_req=tfe_http_session_request_create(ctx->ref_session,
|
||||
ctx->ref_session->req->req_spec.method, ctx->ref_session->req->req_spec.uri);
|
||||
while (true)
|
||||
{
|
||||
if ((in_header_value = tfe_http_field_iterate(ctx->ref_session->req, &iterator, &in_field_name)) == NULL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(in_field_name.field_id==TFE_HTTP_IF_MATCH || in_field_name.field_id==TFE_HTTP_IF_NONE_MATCH
|
||||
|| in_field_name.field_id==TFE_HTTP_IF_MODIFIED_SINCE
|
||||
|| in_field_name.field_id==TFE_HTTP_IF_UNMODIFIED_SINCE)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
tfe_http_field_write(ctx->cache_revalidate_req, &in_field_name, in_header_value);
|
||||
}
|
||||
if(meta->etag) tfe_http_std_field_write(ctx->cache_revalidate_req, TFE_HTTP_IF_NONE_MATCH, meta->etag);
|
||||
if(meta->last_modified) tfe_http_std_field_write(ctx->cache_revalidate_req, TFE_HTTP_IF_MODIFIED_SINCE, meta->last_modified);
|
||||
ctx->resumed_cb=make_revalidate_request;
|
||||
return;
|
||||
}
|
||||
static void cache_pending_on_fail(enum e_future_error err, const char * what, void * user)
|
||||
{
|
||||
struct pangu_http_ctx * ctx = (struct pangu_http_ctx *)user;
|
||||
|
||||
ctx->pending_result=PENDING_RESULT_FOBIDDEN;
|
||||
tfe_http_session_resume(ctx->ref_session);
|
||||
ctx->resumed_cb=dummy_resume;
|
||||
future_destroy(ctx->f_cache_pending);
|
||||
ctx->f_cache_pending=NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void cache_pending(const struct tfe_http_session * session, unsigned int thread_id, struct pangu_http_ctx * ctx)
|
||||
{
|
||||
enum cache_pending_result ret;
|
||||
ctx->f_cache_pending=future_create("cache_pend", cache_pending_on_succ, cache_pending_on_fail, ctx);
|
||||
ctx->pending_result=web_cache_async_pending(g_pangu_rt->cache, thread_id, session->req, ctx->f_cache_pending);
|
||||
switch(ctx->pending_result)
|
||||
{
|
||||
case PENDING_RESULT_REVALIDATE:
|
||||
ctx->ref_session=tfe_http_session_allow_write(session);
|
||||
tfe_http_session_suspend(ctx->ref_session);
|
||||
break;
|
||||
case PENDING_RESULT_ALLOWED:
|
||||
case PENDING_RESULT_FOBIDDEN:
|
||||
case PENDING_RESULT_MISS:
|
||||
future_destroy(ctx->f_cache_query);
|
||||
ctx->f_cache_query=NULL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
void cache_query(const struct tfe_http_session * session, unsigned int thread_id, struct pangu_http_ctx * ctx)
|
||||
{
|
||||
ctx->f_cache_query=future_create("cache_get", cache_query_on_succ, cache_query_on_fail, ctx);
|
||||
ctx->ref_session=tfe_http_session_allow_write(session);
|
||||
tfe_http_session_suspend(ctx->ref_session);
|
||||
web_cache_async_query(g_pangu_rt->cache, thread_id, session->req, ctx->f_cache_query);
|
||||
}
|
||||
|
||||
void cache_update(const struct tfe_http_session * session, enum tfe_http_event events,
|
||||
const unsigned char * body_frag, size_t frag_size,
|
||||
unsigned int thread_id, struct pangu_http_ctx * ctx)
|
||||
{
|
||||
|
||||
if(events & EV_HTTP_RESP_BODY_BEGIN && ctx->cache_query_status == WEB_CACHE_NOT_HIT)
|
||||
if(events & EV_HTTP_RESP_BODY_BEGIN)
|
||||
{
|
||||
ctx->cache_update_ctx=web_cache_update_start(g_pangu_rt->cache, thread_id, session);
|
||||
}
|
||||
@@ -1058,33 +1166,42 @@ void pangu_on_http_data(const struct tfe_stream * stream, const struct tfe_http_
|
||||
enum tfe_http_event events, const unsigned char * body_frag, size_t frag_size, unsigned int thread_id, void ** pme)
|
||||
{
|
||||
struct pangu_http_ctx * ctx = *(struct pangu_http_ctx **) pme;
|
||||
|
||||
if(events & EV_HTTP_REQ_HDR && ctx->resume_from_cache_query && ctx->cache_query_status == WEB_CACHE_HIT)
|
||||
int ret=0;
|
||||
if(ctx->resumed_cb)
|
||||
{
|
||||
//resume from cache query.
|
||||
assert(ctx->action==PG_ACTION_NONE);
|
||||
tfe_http_session_detach(session);
|
||||
return;
|
||||
}
|
||||
if(!ctx->resume_from_cache_query)
|
||||
{
|
||||
enforce_control_policy(stream, session, events, body_frag, frag_size,thread_id, ctx);
|
||||
}
|
||||
if(ctx->action != PG_ACTION_NONE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(g_pangu_rt->cache_enabled)
|
||||
{
|
||||
if(events & EV_HTTP_REQ_HDR && !ctx->resume_from_cache_query)
|
||||
ret=ctx->resumed_cb(stream, session, events, body_frag, frag_size,thread_id, ctx);
|
||||
if(ret==RESUMED_CB_NO_MORE_CALLS)
|
||||
{
|
||||
cache_query(session, thread_id, ctx);
|
||||
ctx->resumed_cb=NULL;
|
||||
}
|
||||
if(!tfe_http_in_request(events))
|
||||
return;
|
||||
}
|
||||
|
||||
enforce_control_policy(stream, session, events, body_frag, frag_size,thread_id, ctx);
|
||||
|
||||
if(g_pangu_rt->cache_enabled && ctx->action == PG_ACTION_NONE)
|
||||
{
|
||||
if(events & EV_HTTP_REQ_HDR)
|
||||
{
|
||||
cache_pending(session, thread_id, ctx);
|
||||
if(ctx->pending_result==PENDING_RESULT_ALLOWED)
|
||||
{
|
||||
cache_query(session, thread_id, ctx);
|
||||
}
|
||||
}
|
||||
if(events & EV_HTTP_RESP_HDR && ctx->pending_result==PENDING_RESULT_REVALIDATE)
|
||||
{
|
||||
if(session->resp->resp_spec.resp_code==TFE_HTTP_STATUS_NOT_MODIFIED)
|
||||
{
|
||||
cache_query(session, thread_id, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
if(tfe_http_in_response(events))
|
||||
{
|
||||
cache_update(session, events, body_frag, frag_size, thread_id, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user