GoogleGAL_Http_CacheParser

Implement the caching directives specified in rfc2616.

Defined (1)

The class is defined in the following location(s).

/core/Google/Http/CacheParser.php  
  1. class GoogleGAL_Http_CacheParser 
  2. public static $CACHEABLE_HTTP_METHODS = array('GET', 'HEAD'); 
  3. public static $CACHEABLE_STATUS_CODES = array('200', '203', '300', '301'); 
  4.  
  5. /** 
  6. * Check if an HTTP request can be cached by a private local cache. 
  7. * @static 
  8. * @param GoogleGAL_Http_Request $resp 
  9. * @return bool True if the request is cacheable. 
  10. * False if the request is uncacheable. 
  11. */ 
  12. public static function isRequestCacheable(GoogleGAL_Http_Request $resp) 
  13. $method = $resp->getRequestMethod(); 
  14. if (! in_array($method, self::$CACHEABLE_HTTP_METHODS)) { 
  15. return false; 
  16.  
  17. // Don't cache authorized requests/responses. 
  18. // [rfc2616-14.8] When a shared cache receives a request containing an 
  19. // Authorization field, it MUST NOT return the corresponding response 
  20. // as a reply to any other request... 
  21. if ($resp->getRequestHeader("authorization")) { 
  22. return false; 
  23.  
  24. return true; 
  25.  
  26. /** 
  27. * Check if an HTTP response can be cached by a private local cache. 
  28. * @static 
  29. * @param GoogleGAL_Http_Request $resp 
  30. * @return bool True if the response is cacheable. 
  31. * False if the response is un-cacheable. 
  32. */ 
  33. public static function isResponseCacheable(GoogleGAL_Http_Request $resp) 
  34. // First, check if the HTTP request was cacheable before inspecting the 
  35. // HTTP response. 
  36. if (false == self::isRequestCacheable($resp)) { 
  37. return false; 
  38.  
  39. $code = $resp->getResponseHttpCode(); 
  40. if (! in_array($code, self::$CACHEABLE_STATUS_CODES)) { 
  41. return false; 
  42.  
  43. // The resource is uncacheable if the resource is already expired and 
  44. // the resource doesn't have an ETag for revalidation. 
  45. $etag = $resp->getResponseHeader("etag"); 
  46. if (self::isExpired($resp) && $etag == false) { 
  47. return false; 
  48.  
  49. // [rfc2616-14.9.2] If [no-store is] sent in a response, a cache MUST NOT 
  50. // store any part of either this response or the request that elicited it. 
  51. $cacheControl = $resp->getParsedCacheControl(); 
  52. if (isset($cacheControl['no-store'])) { 
  53. return false; 
  54.  
  55. // Pragma: no-cache is an http request directive, but is occasionally 
  56. // used as a response header incorrectly. 
  57. $pragma = $resp->getResponseHeader('pragma'); 
  58. if ($pragma == 'no-cache' || strpos($pragma, 'no-cache') !== false) { 
  59. return false; 
  60.  
  61. // [rfc2616-14.44] Vary: * is extremely difficult to cache. "It implies that 
  62. // a cache cannot determine from the request headers of a subsequent request 
  63. // whether this response is the appropriate representation." 
  64. // Given this, we deem responses with the Vary header as uncacheable. 
  65. $vary = $resp->getResponseHeader('vary'); 
  66. if ($vary) { 
  67. return false; 
  68.  
  69. return true; 
  70.  
  71. /** 
  72. * @static 
  73. * @param GoogleGAL_Http_Request $resp 
  74. * @return bool True if the HTTP response is considered to be expired. 
  75. * False if it is considered to be fresh. 
  76. */ 
  77. public static function isExpired(GoogleGAL_Http_Request $resp) 
  78. // HTTP/1.1 clients and caches MUST treat other invalid date formats,  
  79. // especially including the value *0*, as in the past. 
  80. $parsedExpires = false; 
  81. $responseHeaders = $resp->getResponseHeaders(); 
  82.  
  83. if (isset($responseHeaders['expires'])) { 
  84. $rawExpires = $responseHeaders['expires']; 
  85. // Check for a malformed expires header first. 
  86. if (empty($rawExpires) || (is_numeric($rawExpires) && $rawExpires <= 0)) { 
  87. return true; 
  88.  
  89. // See if we can parse the expires header. 
  90. $parsedExpires = strtotime($rawExpires); 
  91. if (false == $parsedExpires || $parsedExpires <= 0) { 
  92. return true; 
  93.  
  94. // Calculate the freshness of an http response. 
  95. $freshnessLifetime = false; 
  96. $cacheControl = $resp->getParsedCacheControl(); 
  97. if (isset($cacheControl['max-age'])) { 
  98. $freshnessLifetime = $cacheControl['max-age']; 
  99.  
  100. $rawDate = $resp->getResponseHeader('date'); 
  101. $parsedDate = strtotime($rawDate); 
  102.  
  103. if (empty($rawDate) || false == $parsedDate) { 
  104. // We can't default this to now, as that means future cache reads 
  105. // will always pass with the logic below, so we will require a 
  106. // date be injected if not supplied. 
  107. throw new GoogleGAL_Exception("All cacheable requests must have creation dates."); 
  108.  
  109. if (false == $freshnessLifetime && isset($responseHeaders['expires'])) { 
  110. $freshnessLifetime = $parsedExpires - $parsedDate; 
  111.  
  112. if (false == $freshnessLifetime) { 
  113. return true; 
  114.  
  115. // Calculate the age of an http response. 
  116. $age = max(0, time() - $parsedDate); 
  117. if (isset($responseHeaders['age'])) { 
  118. $age = max($age, strtotime($responseHeaders['age'])); 
  119.  
  120. return $freshnessLifetime <= $age; 
  121.  
  122. /** 
  123. * Determine if a cache entry should be revalidated with by the origin. 
  124. * @param GoogleGAL_Http_Request $response 
  125. * @return bool True if the entry is expired, else return false. 
  126. */ 
  127. public static function mustRevalidate(GoogleGAL_Http_Request $response) 
  128. // [13.3] When a cache has a stale entry that it would like to use as a 
  129. // response to a client's request, it first has to check with the origin 
  130. // server to see if its cached entry is still usable. 
  131. return self::isExpired($response);