protected boolean isExplicitlyNonCacheable(final HttpResponse response) { final Iterator<HeaderElement> it = MessageSupport.iterate(response, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elem = it.next(); if (HeaderConstants.CACHE_CONTROL_NO_STORE.equals(elem.getName()) || HeaderConstants.CACHE_CONTROL_NO_CACHE.equals(elem.getName()) || (sharedCache && HeaderConstants.PRIVATE.equals(elem.getName()))) { return true; } } return false; }
public boolean hasCacheControlDirective(final HttpCacheEntry entry, final String directive) { final Iterator<HeaderElement> it = MessageSupport.iterate(entry, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if (directive.equalsIgnoreCase(elt.getName())) { return true; } } return false; }
boolean mayCallBackend(final HttpRequest request) { final Iterator<HeaderElement> it = MessageSupport.iterate(request, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if ("only-if-cached".equals(elt.getName())) { log.debug("Request marked only-if-cached"); return false; } } return true; }
protected boolean hasCacheControlParameterFrom(final HttpMessage msg, final String[] params) { final Iterator<HeaderElement> it = MessageSupport.iterate(msg, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elem = it.next(); for (final String param : params) { if (param.equalsIgnoreCase(elem.getName())) { return true; } } } return false; }
protected long getMaxAge(final HttpCacheEntry entry) { long maxage = -1; final Iterator<HeaderElement> it = MessageSupport.iterate(entry, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if (HeaderConstants.CACHE_CONTROL_MAX_AGE.equals(elt.getName()) || "s-maxage".equals(elt.getName())) { try { final long currMaxAge = Long.parseLong(elt.getValue()); if (maxage == -1 || currMaxAge < maxage) { maxage = currMaxAge; } } catch (final NumberFormatException nfe) { // be conservative if can't parse maxage = 0; } } } return maxage; }
private RequestProtocolError requestContainsNoCacheDirectiveWithFieldName(final HttpRequest request) { final Iterator<HeaderElement> it = MessageSupport.iterate(request, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if (HeaderConstants.CACHE_CONTROL_NO_CACHE.equalsIgnoreCase(elt.getName()) && elt.getValue() != null) { return RequestProtocolError.NO_CACHE_DIRECTIVE_WITH_FIELD_NAME; } } return null; } }
boolean explicitFreshnessRequest(final HttpRequest request, final HttpCacheEntry entry, final Date now) { final Iterator<HeaderElement> it = MessageSupport.iterate(request, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if (HeaderConstants.CACHE_CONTROL_MAX_STALE.equals(elt.getName())) { try { final int maxstale = Integer.parseInt(elt.getValue()); final long age = validityPolicy.getCurrentAgeSecs(entry, now); final long lifetime = validityPolicy.getFreshnessLifetimeSecs(entry); if (age - lifetime > maxstale) { return true; } } catch (final NumberFormatException nfe) { return true; } } else if (HeaderConstants.CACHE_CONTROL_MIN_FRESH.equals(elt.getName()) || HeaderConstants.CACHE_CONTROL_MAX_AGE.equals(elt.getName())) { return true; } } return false; }
private boolean mayReturnStaleIfError(final MessageHeaders headers, final String name, final long stalenessSecs) { boolean result = false; final Iterator<HeaderElement> it = MessageSupport.iterate(headers, name); while (it.hasNext()) { final HeaderElement elt = it.next(); if (HeaderConstants.STALE_IF_ERROR.equals(elt.getName())) { try { final int staleIfErrorSecs = Integer.parseInt(elt.getValue()); if (stalenessSecs <= staleIfErrorSecs) { result = true; break; } } catch (final NumberFormatException nfe) { // skip malformed directive } } } return result; }
private void stripOtherFreshnessDirectivesWithNoCache(final HttpRequest request) { final List<HeaderElement> outElts = new ArrayList<>(); boolean shouldStrip = false; final Iterator<HeaderElement> it = MessageSupport.iterate(request, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if (!disallowedWithNoCache.contains(elt.getName())) { outElts.add(elt); } if (HeaderConstants.CACHE_CONTROL_NO_CACHE.equals(elt.getName())) { shouldStrip = true; } } if (!shouldStrip) { return; } request.removeHeaders(HeaderConstants.CACHE_CONTROL); request.setHeader(HeaderConstants.CACHE_CONTROL, buildHeaderFromElements(outElts)); }
public boolean mayReturnStaleWhileRevalidating(final HttpCacheEntry entry, final Date now) { final Iterator<HeaderElement> it = MessageSupport.iterate(entry, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if (HeaderConstants.STALE_WHILE_REVALIDATE.equalsIgnoreCase(elt.getName())) { try { final int allowedStalenessLifetime = Integer.parseInt(elt.getValue()); if (getStalenessSecs(entry, now) <= allowedStalenessLifetime) { return true; } } catch (final NumberFormatException nfe) { // skip malformed directive } } } return false; }
public static final void assert110WarningFound(final HttpResponse response) { boolean found110Warning = false; final Iterator<HeaderElement> it = MessageSupport.iterate(response, HttpHeaders.WARNING); while (it.hasNext()) { final HeaderElement elt = it.next(); final String[] parts = elt.getName().split("\\s"); if ("110".equals(parts[0])) { found110Warning = true; break; } } Assert.assertTrue(found110Warning); }
@Test public void testBuildUnconditionalRequestAddsPragmaNoCache() throws Exception { final HttpRequest result = impl.buildUnconditionalRequest(request); boolean ccNoCacheFound = false; final Iterator<HeaderElement> it = MessageSupport.iterate(result, HeaderConstants.PRAGMA); while (it.hasNext()) { final HeaderElement elt = it.next(); if ("no-cache".equals(elt.getName())) { ccNoCacheFound = true; } } Assert.assertTrue(ccNoCacheFound); }
@Test public void testBuildUnconditionalRequestAddsCacheControlNoCache() throws Exception { final HttpRequest result = impl.buildUnconditionalRequest(request); boolean ccNoCacheFound = false; final Iterator<HeaderElement> it = MessageSupport.iterate(result, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if ("no-cache".equals(elt.getName())) { ccNoCacheFound = true; } } Assert.assertTrue(ccNoCacheFound); }
@Test public void testCacheEntryWithProxyRevalidateDoesEndToEndRevalidation() throws Exception { final HttpRequest basicRequest = new BasicHttpRequest("GET", "/"); final HttpRequest requestWrapper = RequestCopier.INSTANCE.copy(basicRequest); final Date now = new Date(); final Date elevenSecondsAgo = new Date(now.getTime() - 11 * 1000L); final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); final Date nineSecondsAgo = new Date(now.getTime() - 9 * 1000L); final Header[] cacheEntryHeaders = new Header[] { new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)), new BasicHeader("ETag", "\"etag\""), new BasicHeader("Cache-Control","max-age=5, proxy-revalidate") }; final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders); final HttpRequest result = impl.buildConditionalRequest(requestWrapper, cacheEntry); boolean foundMaxAge0 = false; final Iterator<HeaderElement> it = MessageSupport.iterate(result, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if ("max-age".equalsIgnoreCase(elt.getName()) && "0".equals(elt.getValue())) { foundMaxAge0 = true; } } Assert.assertTrue(foundMaxAge0); }
@Test public void testIdentityCodingIsNotUsedInContentEncodingHeader() throws Exception { originResponse.setHeader("Content-Encoding", "identity"); backendExpectsAnyRequest().andReturn(originResponse); replayMocks(); final ClassicHttpResponse result = execute(request); verifyMocks(); boolean foundIdentity = false; final Iterator<HeaderElement> it = MessageSupport.iterate(result, HttpHeaders.CONTENT_ENCODING); while (it.hasNext()) { final HeaderElement elt = it.next(); if ("identity".equalsIgnoreCase(elt.getName())) { foundIdentity = true; } } assertFalse(foundIdentity); }
@Test public void testCacheEntryWithMustRevalidateDoesEndToEndRevalidation() throws Exception { final HttpRequest basicRequest = new BasicHttpRequest("GET","/"); final HttpRequest requestWrapper = RequestCopier.INSTANCE.copy(basicRequest); final Date now = new Date(); final Date elevenSecondsAgo = new Date(now.getTime() - 11 * 1000L); final Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L); final Date nineSecondsAgo = new Date(now.getTime() - 9 * 1000L); final Header[] cacheEntryHeaders = new Header[] { new BasicHeader("Date", DateUtils.formatDate(tenSecondsAgo)), new BasicHeader("ETag", "\"etag\""), new BasicHeader("Cache-Control","max-age=5, must-revalidate") }; final HttpCacheEntry cacheEntry = HttpTestUtils.makeCacheEntry(elevenSecondsAgo, nineSecondsAgo, cacheEntryHeaders); final HttpRequest result = impl.buildConditionalRequest(requestWrapper, cacheEntry); boolean foundMaxAge0 = false; final Iterator<HeaderElement> it = MessageSupport.iterate(result, HeaderConstants.CACHE_CONTROL); while (it.hasNext()) { final HeaderElement elt = it.next(); if ("max-age".equalsIgnoreCase(elt.getName()) && "0".equals(elt.getValue())) { foundMaxAge0 = true; } } Assert.assertTrue(foundMaxAge0); }
@Test public void testMustNotAddMultipartByteRangeContentTypeTo416Response() throws Exception { originResponse = new BasicClassicHttpResponse(416, "Requested Range Not Satisfiable"); EasyMock.expect( mockExecChain.proceed( EasyMock.isA(ClassicHttpRequest.class), EasyMock.isA(ExecChain.Scope.class))).andReturn(originResponse); replayMocks(); final ClassicHttpResponse result = execute(request); verifyMocks(); if (result.getCode() == 416) { final Iterator<HeaderElement> it = MessageSupport.iterate(result, HttpHeaders.CONTENT_TYPE); while (it.hasNext()) { final HeaderElement elt = it.next(); Assert.assertFalse("multipart/byteranges".equalsIgnoreCase(elt.getName())); } } }
@Test public void testVaryStarIsNotGeneratedByProxy() throws Exception { request.setHeader("User-Agent","my-agent/1.0"); originResponse.setHeader("Cache-Control","public, max-age=3600"); originResponse.setHeader("Vary","User-Agent"); originResponse.setHeader("ETag","\"etag\""); backendExpectsAnyRequest().andReturn(originResponse); replayMocks(); final ClassicHttpResponse result = execute(request); verifyMocks(); final Iterator<HeaderElement> it = MessageSupport.iterate(result, HttpHeaders.VARY); while (it.hasNext()) { final HeaderElement elt = it.next(); Assert.assertFalse("*".equals(elt.getName())); } }
@Test public void testOrderOfMultipleTransferEncodingHeadersIsPreserved() throws Exception { originResponse.addHeader("Transfer-Encoding","chunked"); originResponse.addHeader("Transfer-Encoding","x-transfer"); backendExpectsAnyRequest().andReturn(originResponse); replayMocks(); final ClassicHttpResponse result = execute(request); verifyMocks(); int transfer_encodings = 0; final Iterator<HeaderElement> it = MessageSupport.iterate(result, HttpHeaders.TRANSFER_ENCODING); while (it.hasNext()) { final HeaderElement elt = it.next(); switch(transfer_encodings) { case 0: Assert.assertEquals("chunked",elt.getName()); break; case 1: Assert.assertEquals("x-transfer",elt.getName()); break; default: Assert.fail("too many transfer encodings"); } transfer_encodings++; } Assert.assertEquals(2, transfer_encodings); }
@Test public void test206ResponseGeneratedFromCacheMustHaveContentRangeOrMultipartByteRangesContentType() throws Exception { final ClassicHttpRequest req1 = new BasicClassicHttpRequest("GET", "/"); final ClassicHttpResponse resp1 = HttpTestUtils.make200Response(); resp1.setHeader("ETag", "\"etag\""); resp1.setHeader("Cache-Control", "max-age=3600"); final ClassicHttpRequest req2 = new BasicClassicHttpRequest("GET", "/"); req2.setHeader("Range", "bytes=0-50"); backendExpectsAnyRequestAndReturn(resp1).times(1, 2); replayMocks(); execute(req1); final ClassicHttpResponse result = execute(req2); verifyMocks(); if (HttpStatus.SC_PARTIAL_CONTENT == result.getCode()) { if (result.getFirstHeader("Content-Range") == null) { final HeaderElement elt = MessageSupport.parse(result.getFirstHeader("Content-Type"))[0]; Assert.assertTrue("multipart/byteranges".equalsIgnoreCase(elt.getName())); Assert.assertNotNull(elt.getParameterByName("boundary")); Assert.assertNotNull(elt.getParameterByName("boundary").getValue()); Assert.assertFalse("".equals(elt.getParameterByName("boundary").getValue().trim())); } } }