一、ATS中检查HTTP响应是否允许进行缓存的算法如下:
1、非GET\HEAD方法的请求不进行缓存
2、携带了cookie,未在cache.config中设置ttl-in-cache,不进行缓存
3、携带了WWW-Authenticate,但未设置proxy.config.http.cache.ignore_authentication不进行缓存
4、未设置proxy.config.http.cache.ignore_server_no_cache
未在cache.config中设置ignore-no-cache 则遵循原则
未在cache.config中设置ignore-server-no-cache 则遵循源站
未在cache.config中设置ttl-in-cache
服务器响应头Cache-Control为:private\no-cache\no-store
5、在cache.config中设置了action=never-cache,则不进行缓存
6、未设置proxy.config.http.cache.ignore_client_no_cache
未在cache.config中设置ignore-no-cache
未在cache.config中设置ignore-client-no-cache
客户端请求头Cache-Control为:no-store
7、响应码为200,未在cache.config中设置ttl-in-cache
7.1 proxy.config.http.cache.required_headers设置为1,响应头中未携带"Last-Modified:", "Expires:", or "Cache-Control: max-age",则不缓存
7.2 proxy.config.http.cache.required_headers设置为2,响应头中未携带"Expires:" or "Cache-Control: max-age",则不缓存
8、部分内容,即206/416响应,不缓存
9.1、 如果响应中携带了Cache-Control头域,且取值为:public、max-age、s-maxages、must-revalidate、proxy-revalidate,则缓存
9.2、如果响应中携带了Cache-Control头域,且取值为:no-store、private
未设置proxy.config.http.cache.ignore_server_no_cache
未在cache.config中设置ignore-no-cache
未在cache.config中设置ignore-server-no-cache
未在cache.config中设置ttl-in-cache
则不缓存
10、响应头中有Expires头域,进行缓存
11、302\307响应不进行缓存
12、POST请求,未在cache.config中设置ttl-in-cache,不进行缓存
13、插件决定不进行缓存,则不缓存
14、如果未设置proxy.config.http.negative_caching_enabled,则响应码为:200\304\203\300\301\410进行缓存,其它响应码不缓存
15、响应码为:303\401\407不进行缓存
16、除以上情况,则缓存
二、在ATS的HttpTransact::is_response_cacheable(State* s, HTTPHdr* request, HTTPHdr* response)进行控制
///
// Name : is_response_cacheable()
// Description: check if a response is cacheable
//
// Input : State, request header, response header
// Output : true or false
//
// Details :
//
///
// 检查HTTP响应是否允许进行缓存
bool
HttpTransact::is_response_cacheable(State* s, HTTPHdr* request, HTTPHdr* response)
{
// if method is not GET or HEAD, do not cache.
// Note: POST is also cacheable with Expires or Cache-control.
// but due to INKqa11567, we are not caching POST responses.
// Basically, the problem is the resp for POST url1 req should not
// be served to a GET url1 request, but we just match URL not method.
// 非GET\HEAD方法的请求不进行缓存
int req_method = request->method_get_wksidx();
if (!(HttpTransactHeaders::is_method_cacheable(req_method)) && s->api_req_cacheable == false) {
DebugTxn("http_trans", "[is_response_cacheable] " "only GET, and some HEAD and POST are cachable");
return false;
}
// DebugTxn("http_trans", "[is_response_cacheable] method is cacheable");
// If the request was not looked up in the cache, the response
// should not be cached (same subsequent requests will not be
// looked up, either, so why cache this).
if (!(is_request_cache_lookupable(s))) {
DebugTxn("http_trans", "[is_response_cacheable] " "request is not cache lookupable, response is not cachable");
return (false);
}
// already has a fresh copy in the cache
if (s->range_setup == RANGE_NOT_HANDLED)
return false;
// Check whether the response is cachable based on its cookie
// If there are cookies in response but a ttl is set, allow caching
// 携带了cookie,未在cache.config中设置ttl-in-cache,不进行缓存
if ((s->cache_control.ttl_in_cache <= 0) &&
do_cookies_prevent_caching((int) s->txn_conf->cache_responses_to_cookies, request, response)) {
DebugTxn("http_trans", "[is_response_cacheable] " "response has uncachable cookies, response is not cachable");
return (false);
}
// if server spits back a WWW-Authenticate
// 携带了WWW-Authenticate,但未设置proxy.config.http.cache.ignore_authentication不进行缓存
if ((s->txn_conf->cache_ignore_auth) == 0 && response->presence(MIME_PRESENCE_WWW_AUTHENTICATE)) {
DebugTxn("http_trans", "[is_response_cacheable] " "response has WWW-Authenticate, response is not cachable");
return (false);
}
// does server explicitly forbid storing?
// If OS forbids storing but a ttl is set, allow caching
// 未设置proxy.config.http.cache.ignore_server_no_cache
// 未在cache.config中设置ignore-no-cache
// 未在cache.config中设置ignore-server-no-cache
// 未在cache.config中设置ttl-in-cache
// 服务器响应头Cache-Control为:private\no-cache\no-store
if (!s->cache_info.directives.does_server_permit_storing &&
!s->cache_control.ignore_server_no_cache && (s->cache_control.ttl_in_cache <= 0)) {
DebugTxn("http_trans", "[is_response_cacheable] server does not permit storing and config file does not "
"indicate that server directive should be ignored");
return (false);
}
// DebugTxn("http_trans", "[is_response_cacheable] server permits storing");
// does config explicitly forbid storing?
// ttl overides other config parameters
// 在cache.config中设置了action=never-cache,则不进行缓存
if ((!s->cache_info.directives.does_config_permit_storing &&
!s->cache_control.ignore_server_no_cache &&
(s->cache_control.ttl_in_cache <= 0)) || (s->cache_control.never_cache)) {
DebugTxn("http_trans", "[is_response_cacheable] config doesn't allow storing, and cache control does not "
"say to ignore no-cache and does not specify never-cache or a ttl");
return (false);
}
// DebugTxn("http_trans", "[is_response_cacheable] config permits storing");
// does client explicitly forbid storing?
// 未设置proxy.config.http.cache.ignore_client_no_cache
// 未在cache.config中设置ignore-no-cache
// 未在cache.config中设置ignore-client-no-cache
// 客户端请求头Cache-Control为:no-store
if (!s->cache_info.directives.does_client_permit_storing && !s->cache_control.ignore_client_no_cache) {
DebugTxn("http_trans", "[is_response_cacheable] client does not permit storing, "
"and cache control does not say to ignore client no-cache");
return (false);
}
DebugTxn("http_trans", "[is_response_cacheable] client permits storing");
HTTPStatus response_code = response->status_get();
// caching/not-caching based on required headers
// only makes sense when the server sends back a
// 200 and a document.
// 响应码为200,未在cache.config中设置ttl-in-cache
// proxy.config.http.cache.required_headers设置为1,响应头中未携带"Last-Modified:", "Expires:", or "Cache-Control: max-age",则不缓存
// proxy.config.http.cache.required_headers设置为2,响应头中未携带"Expires:" or "Cache-Control: max-age",则不缓存
if (response_code == HTTP_STATUS_OK) {
// If a ttl is set: no header required for caching
// otherwise: follow parameter http.cache.required_headers
if (s->cache_control.ttl_in_cache <= 0) {
uint32_t cc_mask = (MIME_COOKED_MASK_CC_MAX_AGE | MIME_COOKED_MASK_CC_S_MAXAGE);
// server did not send expires header or last modified
// and we are configured to not cache without them.
switch (s->txn_conf->cache_required_headers) {
case HttpConfigParams::CACHE_REQUIRED_HEADERS_NONE:
DebugTxn("http_trans", "[is_response_cacheable] " "no response headers required");
break;
case HttpConfigParams::CACHE_REQUIRED_HEADERS_AT_LEAST_LAST_MODIFIED:
if (!response->presence(MIME_PRESENCE_EXPIRES) && !(response->get_cooked_cc_mask() & cc_mask) &&
!response->get_last_modified()) {
DebugTxn("http_trans", "[is_response_cacheable] " "last_modified, expires, or max-age is required");
s->squid_codes.hit_miss_code = ((response->get_date() == 0) ? (SQUID_MISS_HTTP_NO_DLE) : (SQUID_MISS_HTTP_NO_LE));
return (false);
}
break;
case HttpConfigParams::CACHE_REQUIRED_HEADERS_CACHE_CONTROL:
if (!response->presence(MIME_PRESENCE_EXPIRES) && !(response->get_cooked_cc_mask() & cc_mask)) {
DebugTxn("http_trans", "[is_response_cacheable] " "expires header or max-age is required");
return (false);
}
break;
default:
break;
}
}
}
// do not cache partial content - Range response
// 不对部分内容进行cache,206/416响应
if (response_code == HTTP_STATUS_PARTIAL_CONTENT || response_code == HTTP_STATUS_RANGE_NOT_SATISFIABLE) {
DebugTxn("http_trans", "[is_response_cacheable] " "response code %d - don't cache", response_code);
return false;
}
// check if cache control overrides default cacheability
int indicator;
indicator = response_cacheable_indicated_by_cc(response);
if (indicator > 0) { // cacheable indicated by cache control header
DebugTxn("http_trans", "[is_response_cacheable] YES by response cache control");
// even if it is authenticated, this is cacheable based on regular rules
s->www_auth_content = CACHE_AUTH_NONE;
return true;
} else if (indicator < 0) { // not cacheable indicated by cache control header
// If a ttl is set, allow caching even if response contains
// Cache-Control headers to prevent caching
if (s->cache_control.ttl_in_cache > 0) {
DebugTxn("http_trans", "[is_response_cacheable] Cache-control header directives in response overridden by ttl in cache.config");
} else if (!s->cache_control.ignore_server_no_cache) {
DebugTxn("http_trans", "[is_response_cacheable] NO by response cache control");
return false;
}
}
// else no indication by cache control header
// continue to determine cacheability
// if client contains Authorization header,
// only cache if response has proper Cache-Control
// if (s->www_auth_content == CACHE_AUTH_FRESH) {
// response to the HEAD request
// return false;
//} else if (s->www_auth_content == CACHE_AUTH_TRUE ||
// (s->www_auth_content == CACHE_AUTH_NONE && request->presence(MIME_PRESENCE_AUTHORIZATION))) {
// if (!s->cache_control.cache_auth_content || response_code != HTTP_STATUS_OK || req_method != HTTP_WKSIDX_GET)
// return false;
//}
// s->www_auth_content == CACHE_AUTH_STALE silently continues
// 响应头中有Expires头域,进行缓存
if (response->presence(MIME_PRESENCE_EXPIRES)) {
DebugTxn("http_trans", "[is_response_cacheable] YES response w/ Expires");
return true;
}
// if it's a 302 or 307 and no positive indicator from cache-control, reject
// 302\307响应不进行缓存
if (response_code == HTTP_STATUS_MOVED_TEMPORARILY || response_code == HTTP_STATUS_TEMPORARY_REDIRECT) {
DebugTxn("http_trans", "[is_response_cacheable] cache-control or expires header is required for 302");
return false;
}
// if it's a POST request and no positive indicator from cache-control
//POST请求,未在cache.config中设置ttl-in-cache,不进行缓存
if (req_method == HTTP_WKSIDX_POST) {
// allow caching for a POST requests w/o Expires but with a ttl
if (s->cache_control.ttl_in_cache > 0) {
DebugTxn("http_trans", "[is_response_cacheable] POST method with a TTL");
} else {
DebugTxn("http_trans", "[is_response_cacheable] NO POST w/o Expires or CC");
return false;
}
}
// the plugin may decide we don't want to cache the response
// 插件决定不进行缓存,则不缓存
if (s->api_server_response_no_store) {
return (false);
}
// default cacheability
// 如果未设置proxy.config.http.negative_caching_enabled,响应码为:200\304\203\300\301\410进行缓存,其它响应码不缓存
if (!s->txn_conf->negative_caching_enabled) {
if ((response_code == HTTP_STATUS_OK) ||
(response_code == HTTP_STATUS_NOT_MODIFIED) ||
(response_code == HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION) ||
(response_code == HTTP_STATUS_MOVED_PERMANENTLY) ||
(response_code == HTTP_STATUS_MULTIPLE_CHOICES) || (response_code == HTTP_STATUS_GONE)) {
DebugTxn("http_trans", "[is_response_cacheable] YES by default ");
return true;
} else {
DebugTxn("http_trans", "[is_response_cacheable] NO by default");
return false;
}
}
// 响应码为:303\401\407不进行缓存
if (response_code == HTTP_STATUS_SEE_OTHER ||
response_code == HTTP_STATUS_UNAUTHORIZED ||
response_code == HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED)
return false;
// let is_negative_caching_approriate decide what to do
// 除以上情况,则缓存
return true;
}