2018-10-22 15:43:57 +08:00
|
|
|
#include "tango_cache_pending.h"
|
|
|
|
|
#include <tfe_utils.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdbool.h>
|
2018-09-22 23:06:38 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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);
|
2018-10-22 15:43:57 +08:00
|
|
|
time_value = ALLOC(char, len+1);
|
2018-09-22 23:06:38 +08:00
|
|
|
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)
|
|
|
|
|
{
|
2018-10-25 18:45:33 +08:00
|
|
|
return REVALIDATE;
|
2018-09-22 23:06:38 +08:00
|
|
|
}
|
|
|
|
|
if (strstr(value, "no-store") != NULL)
|
|
|
|
|
{
|
|
|
|
|
return FORBIDDEN;
|
|
|
|
|
}
|
|
|
|
|
get_request_freshness(value, restrict);
|
|
|
|
|
return ALLOWED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-25 18:45:33 +08:00
|
|
|
bool cache_verify(const struct tfe_http_half *request)
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
|
|
|
|
int i = 0;
|
2018-10-14 17:11:45 +08:00
|
|
|
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;
|
|
|
|
|
}
|
2018-09-22 23:06:38 +08:00
|
|
|
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";
|
2018-10-19 21:56:04 +08:00
|
|
|
if (strcasecmp(value, pragma_value) == 0)
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
2018-10-25 18:45:33 +08:00
|
|
|
return REVALIDATE;
|
2018-09-22 23:06:38 +08:00
|
|
|
}
|
|
|
|
|
return UNDEFINED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-14 17:11:45 +08:00
|
|
|
enum cache_pending_action tfe_cache_get_pending(const struct tfe_http_half *request, struct request_freshness* restrict)
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
2018-10-25 18:45:33 +08:00
|
|
|
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;
|
|
|
|
|
}
|
2018-10-22 16:41:26 +08:00
|
|
|
if(NULL!=tfe_http_std_field_read(request, TFE_HTTP_CONT_RANGE))
|
|
|
|
|
{
|
|
|
|
|
return FORBIDDEN;
|
|
|
|
|
}
|
2018-10-14 17:11:45 +08:00
|
|
|
value = tfe_http_std_field_read(request, TFE_HTTP_PRAGMA);
|
2018-10-25 18:45:33 +08:00
|
|
|
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;
|
2018-09-22 23:06:38 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2018-10-25 18:45:33 +08:00
|
|
|
time_t read_GMT_time(const char* gmt_string)
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
|
|
|
|
time_t expire_rel_time;
|
|
|
|
|
struct tm expire_gmt_time;
|
2018-10-25 18:45:33 +08:00
|
|
|
strptime(gmt_string, "%a, %d %b %Y %H:%M:%S GMT", &expire_gmt_time);
|
2018-09-22 23:06:38 +08:00
|
|
|
expire_rel_time = mktime(&expire_gmt_time);
|
|
|
|
|
return expire_rel_time;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool is_standard_gmt_format(const char* value)
|
|
|
|
|
{
|
|
|
|
|
int str_len = strlen(value);
|
2018-10-21 11:07:20 +08:00
|
|
|
if(0==strcasecmp(value+str_len-3,"GMT"))
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
|
|
|
|
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");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-14 17:11:45 +08:00
|
|
|
void get_response_freshness(const struct tfe_http_half *response, struct response_freshness* freshness)
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
|
|
|
|
time_t expire_rel_time = 0;
|
|
|
|
|
time_t cur_rel_time = 0;
|
|
|
|
|
struct tm cur_gmt_time;
|
|
|
|
|
const char* field_value = NULL;
|
2018-10-14 17:11:45 +08:00
|
|
|
field_value = tfe_http_std_field_read(response, TFE_HTTP_CACHE_CONTROL);
|
2018-09-22 23:06:38 +08:00
|
|
|
if (field_value != NULL)
|
|
|
|
|
{
|
|
|
|
|
freshness->timeout = get_response_s_maxage(field_value);
|
|
|
|
|
if (freshness->timeout == 0)
|
|
|
|
|
{
|
|
|
|
|
freshness->timeout = get_response_maxage(field_value);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-10-14 17:11:45 +08:00
|
|
|
field_value = tfe_http_std_field_read(response, TFE_HTTP_EXPIRES);
|
2018-10-21 11:07:20 +08:00
|
|
|
if (field_value != NULL && is_standard_gmt_format(field_value))
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
2018-10-25 18:45:33 +08:00
|
|
|
expire_rel_time = read_GMT_time(field_value);
|
2018-09-22 23:06:38 +08:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2018-10-14 17:11:45 +08:00
|
|
|
field_value = tfe_http_std_field_read(response, TFE_HTTP_DATE);
|
2018-09-22 23:06:38 +08:00
|
|
|
if (field_value != NULL)
|
|
|
|
|
{
|
|
|
|
|
assert(is_standard_gmt_format(field_value));
|
2018-10-25 18:45:33 +08:00
|
|
|
freshness->date = read_GMT_time(field_value);;
|
2018-09-22 23:06:38 +08:00
|
|
|
}
|
2018-10-14 17:11:45 +08:00
|
|
|
field_value = tfe_http_std_field_read(response, TFE_HTTP_LAST_MODIFIED);
|
2018-10-21 11:08:44 +08:00
|
|
|
if (field_value != NULL && is_standard_gmt_format(field_value))
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
2018-10-25 18:45:33 +08:00
|
|
|
freshness->last_modified = read_GMT_time(field_value);;
|
2018-09-22 23:06:38 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2018-10-25 18:45:33 +08:00
|
|
|
return REVALIDATE;
|
2018-09-22 23:06:38 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return ALLOWED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2018-10-14 17:11:45 +08:00
|
|
|
enum cache_pending_action tfe_cache_put_pending(const struct tfe_http_half *response, struct response_freshness* freshness)
|
2018-09-22 23:06:38 +08:00
|
|
|
{
|
|
|
|
|
enum cache_pending_action res = UNDEFINED;
|
|
|
|
|
int i = 0;
|
|
|
|
|
int index = 0;
|
|
|
|
|
const char *value = NULL;
|
|
|
|
|
memset(freshness,0,sizeof(struct response_freshness));
|
2018-10-22 16:41:26 +08:00
|
|
|
if(response->resp_spec.resp_code!=TFE_HTTP_STATUS_OK
|
2018-10-25 18:45:33 +08:00
|
|
|
|| NULL!=tfe_http_std_field_read(response, TFE_HTTP_CONT_RANGE) //NOT upload response with content-range
|
|
|
|
|
|| NULL==response->resp_spec.content_length)
|
2018-10-16 21:16:58 +08:00
|
|
|
{
|
|
|
|
|
return FORBIDDEN;
|
|
|
|
|
}
|
2018-10-21 15:03:04 +08:00
|
|
|
value=tfe_http_std_field_read(response, TFE_HTTP_SET_COOKIE);
|
|
|
|
|
if(value!=NULL)
|
|
|
|
|
{
|
|
|
|
|
return FORBIDDEN;
|
|
|
|
|
}
|
2018-10-14 17:11:45 +08:00
|
|
|
value = tfe_http_std_field_read(response, TFE_HTTP_PRAGMA);
|
2018-09-22 23:06:38 +08:00
|
|
|
if (value != NULL)
|
|
|
|
|
{
|
|
|
|
|
res = get_pragma_action(value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-10-14 17:11:45 +08:00
|
|
|
value = tfe_http_std_field_read(response, TFE_HTTP_CACHE_CONTROL);
|
2018-09-22 23:06:38 +08:00
|
|
|
if (value != NULL)
|
|
|
|
|
{
|
|
|
|
|
res = response_cache_control(value);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2018-10-14 17:11:45 +08:00
|
|
|
value = tfe_http_std_field_read(response, TFE_HTTP_EXPIRES);
|
2018-09-22 23:06:38 +08:00
|
|
|
if (value != NULL)
|
|
|
|
|
{
|
|
|
|
|
res = ALLOWED;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (res == ALLOWED)
|
|
|
|
|
{
|
2018-10-14 17:11:45 +08:00
|
|
|
get_response_freshness(response, freshness);
|
2018-09-22 23:06:38 +08:00
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|