13c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpackage com.squareup.okhttp; 23c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 33c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerimport com.squareup.okhttp.internal.http.HeaderParser; 43c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 53c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller/** 63c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * A Cache-Control header with cache directives from a server or client. These 73c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * directives set policy on what responses can be stored, and which requests can 83c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * be satisfied by those stored responses. 93c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p>See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9">RFC 113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 2616, 14.9</a>. 123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fullerpublic final class CacheControl { 143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final boolean noCache; 153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final boolean noStore; 163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final int maxAgeSeconds; 173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final int sMaxAgeSeconds; 183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final boolean isPublic; 193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final boolean mustRevalidate; 203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final int maxStaleSeconds; 213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final int minFreshSeconds; 223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private final boolean onlyIfCached; 233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller private CacheControl(boolean noCache, boolean noStore, int maxAgeSeconds, int sMaxAgeSeconds, 253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller boolean isPublic, boolean mustRevalidate, int maxStaleSeconds, int minFreshSeconds, 263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller boolean onlyIfCached) { 273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.noCache = noCache; 283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.noStore = noStore; 293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.maxAgeSeconds = maxAgeSeconds; 303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.sMaxAgeSeconds = sMaxAgeSeconds; 313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.isPublic = isPublic; 323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.mustRevalidate = mustRevalidate; 333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.maxStaleSeconds = maxStaleSeconds; 343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.minFreshSeconds = minFreshSeconds; 353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller this.onlyIfCached = onlyIfCached; 363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * In a response, this field's name "no-cache" is misleading. It doesn't 403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * prevent us from caching the response; it only means we have to validate the 413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * response with the origin server before returning it. We can do this with a 423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * conditional GET. 433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * 443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * <p>In a request, it means do not use a cache to satisfy the request. 453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public boolean noCache() { 473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return noCache; 483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** If true, this response should not be cached. */ 513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public boolean noStore() { 523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return noStore; 533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * The duration past the response's served date that it can be served without 573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * validation. 583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public int maxAgeSeconds() { 603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return maxAgeSeconds; 613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * The "s-maxage" directive is the max age for shared caches. Not to be 653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * confused with "max-age" for non-shared caches, As in Firefox and Chrome, 663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * this directive is not honored by this cache. 673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public int sMaxAgeSeconds() { 693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return sMaxAgeSeconds; 703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public boolean isPublic() { 733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return isPublic; 743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public boolean mustRevalidate() { 773c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return mustRevalidate; 783c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 793c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 803c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public int maxStaleSeconds() { 813c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return maxStaleSeconds; 823c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 833c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 843c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public int minFreshSeconds() { 853c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return minFreshSeconds; 863c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 873c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 883c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 893c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * This field's name "only-if-cached" is misleading. It actually means "do 903c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * not use the network". It is set by a client who only wants to make a 913c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * request if it can be fully satisfied by the cache. Cached responses that 923c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * would require validation (ie. conditional gets) are not permitted if this 933c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * header is set. 943c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 953c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public boolean onlyIfCached() { 963c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return onlyIfCached; 973c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 983c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 993c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller /** 1003c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Returns the cache directives of {@code headers}. This honors both 1013c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller * Cache-Control and Pragma headers if they are present. 1023c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller */ 1033c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller public static CacheControl parse(Headers headers) { 1043c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller boolean noCache = false; 1053c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller boolean noStore = false; 1063c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int maxAgeSeconds = -1; 1073c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int sMaxAgeSeconds = -1; 1083c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller boolean isPublic = false; 1093c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller boolean mustRevalidate = false; 1103c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int maxStaleSeconds = -1; 1113c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int minFreshSeconds = -1; 1123c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller boolean onlyIfCached = false; 1133c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1143c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller for (int i = 0; i < headers.size(); i++) { 1153c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (!headers.name(i).equalsIgnoreCase("Cache-Control") 1163c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller && !headers.name(i).equalsIgnoreCase("Pragma")) { 1173c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller continue; 1183c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1193c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1203c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String string = headers.value(i); 1213c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int pos = 0; 1223c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller while (pos < string.length()) { 1233c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int tokenStart = pos; 1243c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos = HeaderParser.skipUntil(string, pos, "=,;"); 1253c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String directive = string.substring(tokenStart, pos).trim(); 1263c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller String parameter; 1273c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1283c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (pos == string.length() || string.charAt(pos) == ',' || string.charAt(pos) == ';') { 1293c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos++; // consume ',' or ';' (if necessary) 1303c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller parameter = null; 1313c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 1323c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos++; // consume '=' 1333c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos = HeaderParser.skipWhitespace(string, pos); 1343c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1353c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // quoted string 1363c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if (pos < string.length() && string.charAt(pos) == '\"') { 1373c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos++; // consume '"' open quote 1383c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int parameterStart = pos; 1393c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos = HeaderParser.skipUntil(string, pos, "\""); 1403c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller parameter = string.substring(parameterStart, pos); 1413c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos++; // consume '"' close quote (if necessary) 1423c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1433c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller // unquoted string 1443c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else { 1453c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller int parameterStart = pos; 1463c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller pos = HeaderParser.skipUntil(string, pos, ",;"); 1473c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller parameter = string.substring(parameterStart, pos).trim(); 1483c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1493c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1503c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1513c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller if ("no-cache".equalsIgnoreCase(directive)) { 1523c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller noCache = true; 1533c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else if ("no-store".equalsIgnoreCase(directive)) { 1543c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller noStore = true; 1553c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else if ("max-age".equalsIgnoreCase(directive)) { 1563c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller maxAgeSeconds = HeaderParser.parseSeconds(parameter); 1573c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else if ("s-maxage".equalsIgnoreCase(directive)) { 1583c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller sMaxAgeSeconds = HeaderParser.parseSeconds(parameter); 1593c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else if ("public".equalsIgnoreCase(directive)) { 1603c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller isPublic = true; 1613c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else if ("must-revalidate".equalsIgnoreCase(directive)) { 1623c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller mustRevalidate = true; 1633c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else if ("max-stale".equalsIgnoreCase(directive)) { 1643c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller maxStaleSeconds = HeaderParser.parseSeconds(parameter); 1653c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else if ("min-fresh".equalsIgnoreCase(directive)) { 1663c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller minFreshSeconds = HeaderParser.parseSeconds(parameter); 1673c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } else if ("only-if-cached".equalsIgnoreCase(directive)) { 1683c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller onlyIfCached = true; 1693c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1703c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1713c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1723c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller 1733c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller return new CacheControl(noCache, noStore, maxAgeSeconds, sMaxAgeSeconds, isPublic, 1743c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller mustRevalidate, maxStaleSeconds, minFreshSeconds, onlyIfCached); 1753c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller } 1763c938a3f6b61ce5e2dba0d039b03fe73b89fd26cNeil Fuller} 177