#include "tango_cache_pending.h" #include #include #include #include #include #include time_t get_time_value(const char* field_value, const char* field_type) { time_t time; char* time_value = NULL; field_value += strlen(field_type); field_value++; int len = strlen(field_value); time_value = ALLOC(char, len+1); int index = 0; while (field_value[index] != ',' && field_value[index] != '\r' && index < len) { time_value[index] = field_value[index]; index++; } time_value[index] = '\0'; time = (time_t)atol(time_value); free(time_value); return time; } void get_request_freshness(const char *value, struct request_freshness* restrict) { const char* field_value = NULL; const char* cache_control_time[] = { "min-fresh", "max-age" }; int i = 0; time_t relative_time; field_value = strstr(value, "min-fresh"); if (field_value != NULL) { restrict->min_fresh = get_time_value(field_value, "min-fresh");; } field_value = strstr(value, "max-age"); if (field_value != NULL) { restrict->max_age = get_time_value(field_value, "max-age");; } } enum cache_pending_action request_cache_control(const char* value, struct request_freshness* restrict) { int i = 0; if (strstr(value, "no-cache") != NULL) { return REVALIDATE; } if (strstr(value, "no-store") != NULL) { return FORBIDDEN; } get_request_freshness(value, restrict); return ALLOWED; } bool cache_verify(const struct tfe_http_half *request) { int i = 0; if( !tfe_http_std_field_read(request,TFE_HTTP_IF_MATCH) || !tfe_http_std_field_read(request,TFE_HTTP_IF_NONE_MATCH) || !tfe_http_std_field_read(request,TFE_HTTP_IF_MODIFIED_SINCE) || !tfe_http_std_field_read(request,TFE_HTTP_IF_UNMODIFIED_SINCE) ) { return true; } return false; } const char* get_head_value(const struct tfe_http_field *http_fields, size_t n_fields, enum tfe_http_std_field head_key) { int i = 0; for (i = 0; i < n_fields; i++) { if (http_fields[i].http_field == head_key) { return http_fields[i].value; } } return NULL; } enum cache_pending_action get_pragma_action(const char * value) { const char *pragma_value = "no-cache"; if (strcasecmp(value, pragma_value) == 0) { return REVALIDATE; } return UNDEFINED; } enum cache_pending_action tfe_cache_get_pending(const struct tfe_http_half *request, struct request_freshness* restrict) { enum cache_pending_action res = UNDEFINED; int i = 0; int index = 0; const char *value = NULL; memset(restrict,0,sizeof(struct request_freshness)); if(request->req_spec.method!=TFE_HTTP_METHOD_GET) { return FORBIDDEN; } if(NULL!=tfe_http_std_field_read(request, TFE_HTTP_CONT_RANGE)) { return FORBIDDEN; } value = tfe_http_std_field_read(request, TFE_HTTP_PRAGMA); if (value != NULL) { res = get_pragma_action(value); } else { value = tfe_http_std_field_read(request, TFE_HTTP_CACHE_CONTROL); if (value != NULL) { res = request_cache_control(value, restrict); } else { if (cache_verify(request)) { res = REVALIDATE; } } } return res; } time_t read_GMT_time(const char* gmt_string) { time_t expire_rel_time; struct tm expire_gmt_time; strptime(gmt_string, "%a, %d %b %Y %H:%M:%S GMT", &expire_gmt_time); expire_rel_time = mktime(&expire_gmt_time); return expire_rel_time; } bool is_standard_gmt_format(const char* value) { int str_len = strlen(value); if(0==strcasecmp(value+str_len-3,"GMT")) { return true; } else { return false; } } time_t get_relative_time(const char* value) { const char* temp_str = NULL; char * str_age = NULL; time_t time = 0; const char * cache_ctl_time[] = { "s-maxage","max-age" };//s-maxage优先级大于max-age优先级 int i = 0; for (; i < 2; i++) { temp_str = strstr(value, cache_ctl_time[i]); } return time; } time_t get_response_s_maxage(const char* cache_ctl) { const char* s_maxage = NULL; s_maxage = strstr(cache_ctl, "s-maxage"); if (s_maxage != NULL) { return get_time_value(s_maxage, "s-maxage"); } } time_t get_response_maxage(const char* cache_ctl) { const char* max_age = NULL; max_age = strstr(cache_ctl, "max-age"); if (max_age != NULL) { return get_time_value(max_age, "max-age"); } } void get_response_freshness(const struct tfe_http_half *response, struct response_freshness* freshness) { time_t expire_rel_time = 0; time_t cur_rel_time = 0; struct tm cur_gmt_time; const char* field_value = NULL; field_value = tfe_http_std_field_read(response, TFE_HTTP_CACHE_CONTROL); if (field_value != NULL) { freshness->timeout = get_response_s_maxage(field_value); if (freshness->timeout == 0) { freshness->timeout = get_response_maxage(field_value); } } else { field_value = tfe_http_std_field_read(response, TFE_HTTP_EXPIRES); if (field_value != NULL && is_standard_gmt_format(field_value)) { expire_rel_time = read_GMT_time(field_value); const time_t cur_ct_time = time(NULL); if (gmtime_r(&cur_ct_time, &cur_gmt_time) == NULL) { assert(0); } cur_rel_time = mktime(&cur_gmt_time); freshness->timeout = expire_rel_time - cur_rel_time; } } field_value = tfe_http_std_field_read(response, TFE_HTTP_DATE); if (field_value != NULL) { assert(is_standard_gmt_format(field_value)); freshness->date = read_GMT_time(field_value);; } field_value = tfe_http_std_field_read(response, TFE_HTTP_LAST_MODIFIED); if (field_value != NULL && is_standard_gmt_format(field_value)) { freshness->last_modified = read_GMT_time(field_value);; } } enum cache_pending_action response_cache_control(const char* value) { const char *forbidden_vaule[] = {"no-store", "private"}; const char *verify_vaule[] = { "no-cache", "must-revalidate","proxy-revalidate" }; int i = 0; for (i = 0; i < 2; i++) { if (strstr(value, forbidden_vaule[i]) != NULL) { return FORBIDDEN; } } for (i = 0; i < 3; i++) { if (strstr(value, verify_vaule[i]) != NULL) { return REVALIDATE; } } return ALLOWED; } enum cache_pending_action tfe_cache_put_pending(const struct tfe_http_half *response, struct response_freshness* freshness) { enum cache_pending_action res = UNDEFINED; int i = 0; int index = 0; const char *value = NULL; memset(freshness,0,sizeof(struct response_freshness)); if(response->resp_spec.resp_code!=TFE_HTTP_STATUS_OK || NULL!=tfe_http_std_field_read(response, TFE_HTTP_CONT_RANGE) //NOT upload response with content-range || NULL==response->resp_spec.content_length) { return FORBIDDEN; } value=tfe_http_std_field_read(response, TFE_HTTP_SET_COOKIE); if(value!=NULL) { return FORBIDDEN; } value = tfe_http_std_field_read(response, TFE_HTTP_PRAGMA); if (value != NULL) { res = get_pragma_action(value); } else { value = tfe_http_std_field_read(response, TFE_HTTP_CACHE_CONTROL); if (value != NULL) { res = response_cache_control(value); } else { value = tfe_http_std_field_read(response, TFE_HTTP_EXPIRES); if (value != NULL) { res = ALLOWED; } } } if (res == ALLOWED) { get_response_freshness(response, freshness); } return res; }