>
+ */
+ protected void consumeQuotedString() {
+ if (src.charAt(offs) != '\"') parseError();
+ offs++;
+ boolean foundEnd = false;
+ while(offs < src.length() && !foundEnd) {
+ char c = src.charAt(offs);
+ if (offs + 1 < src.length() && c == '\\'
+ && isChar(src.charAt(offs+1))) {
+ offs += 2; // consume quoted-pair
+ } else if (c == '\"') {
+ foundEnd = true;
+ offs++;
+ } else if (c != '\"' && !isControl(c)) {
+ offs++;
+ } else {
+ parseError();
+ }
+ }
+ if (!foundEnd) parseError();
+ }
+
+ /*
+ * warn-text = quoted-string
+ */
+ protected void consumeWarnText() {
+ int curr = offs;
+ consumeQuotedString();
+ warnText = src.substring(curr, offs);
+ }
+
+ private static final String MONTH = "Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec";
+ private static final String WEEKDAY = "Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday";
+ private static final String WKDAY = "Mon|Tue|Wed|Thu|Fri|Sat|Sun";
+ private static final String TIME = "\\d{2}:\\d{2}:\\d{2}";
+ private static final String DATE3 = "(" + MONTH + ") ( |\\d)\\d";
+ private static final String DATE2 = "\\d{2}-(" + MONTH + ")-\\d{2}";
+ private static final String DATE1 = "\\d{2} (" + MONTH + ") \\d{4}";
+ private static final String ASCTIME_DATE = "(" + WKDAY + ") (" + DATE3 + ") (" + TIME + ") \\d{4}";
+ private static final String RFC850_DATE = "(" + WEEKDAY + "), (" + DATE2 + ") (" + TIME + ") GMT";
+ private static final String RFC1123_DATE = "(" + WKDAY + "), (" + DATE1 + ") (" + TIME + ") GMT";
+ private static final String HTTP_DATE = "(" + RFC1123_DATE + ")|(" + RFC850_DATE + ")|(" + ASCTIME_DATE + ")";
+ private static final String WARN_DATE = "\"(" + HTTP_DATE + ")\"";
+ private static final Pattern WARN_DATE_PATTERN = Pattern.compile(WARN_DATE);
+
+ /*
+ * warn-date = <"> HTTP-date <">
+ */
+ protected void consumeWarnDate() {
+ int curr = offs;
+ Matcher m = WARN_DATE_PATTERN.matcher(src.substring(offs));
+ if (!m.lookingAt()) parseError();
+ offs += m.end();
+ try {
+ warnDate = DateUtils.parseDate(src.substring(curr+1,offs-1));
+ } catch (DateParseException e) {
+ throw new IllegalStateException("couldn't parse a parseable date");
+ }
+ }
+
+ /*
+ * warning-value = warn-code SP warn-agent SP warn-text [SP warn-date]
+ */
+ protected void consumeWarnValue() {
+ consumeLinearWhitespace();
+ consumeWarnCode();
+ consumeWarnAgent();
+ consumeWarnText();
+ if (offs + 1 < src.length() && src.charAt(offs) == ' ' && src.charAt(offs+1) == '\"') {
+ consumeCharacter(' ');
+ consumeWarnDate();
+ }
+ consumeLinearWhitespace();
+ if (offs != src.length()) {
+ consumeCharacter(',');
+ }
+ }
+
+ protected void consumeCharacter(char c) {
+ if (offs + 1 > src.length()
+ || c != src.charAt(offs)) {
+ parseError();
+ }
+ offs++;
+ }
+
+ /*
+ * warn-code = 3DIGIT
+ */
+ protected void consumeWarnCode() {
+ if (offs + 4 > src.length()
+ || !Character.isDigit(src.charAt(offs))
+ || !Character.isDigit(src.charAt(offs + 1))
+ || !Character.isDigit(src.charAt(offs + 2))
+ || src.charAt(offs + 3) != ' ') {
+ parseError();
+ }
+ warnCode = Integer.parseInt(src.substring(offs,offs+3));
+ offs += 4;
+ }
+
+ private void parseError() {
+ String s = src.substring(init_offs);
+ throw new IllegalArgumentException("Bad warn code \"" + s + "\"");
+ }
+
+ /** Returns the 3-digit code associated with this warning.
+ * @return int
+ */
+ public int getWarnCode() { return warnCode; }
+
+ /** Returns the "warn-agent" string associated with this warning,
+ * which is either the name or pseudonym of the server that added
+ * this particular Warning header.
+ * @return {@link String}
+ */
+ public String getWarnAgent() { return warnAgent; }
+
+ /** Returns the human-readable warning text for this warning. Note
+ * that the original quoted-string is returned here, including
+ * escaping for any contained characters. In other words, if the
+ * header was:
+ *
+ * Warning: 110 fred "Response is stale"
+ *
+ * then this method will return "\"Response is stale\""
+ * (surrounding quotes included).
+ * @return {@link String}
+ */
+ public String getWarnText() { return warnText; }
+
+ /** Returns the date and time when this warning was added, or
+ * null if a warning date was not supplied in the
+ * header.
+ * @return {@link Date}
+ */
+ public Date getWarnDate() { return warnDate; }
+
+ /** Formats a WarningValue as a {@link String}
+ * suitable for including in a header. For example, you can:
+ *
+ * WarningValue wv = ...;
+ * HttpResponse resp = ...;
+ * resp.addHeader("Warning", wv.toString());
+ *
+ * @return {@link String}
+ */
+ public String toString() {
+ if (warnDate != null) {
+ return String.format("%d %s %s \"%s\"", warnCode,
+ warnAgent, warnText, DateUtils.formatDate(warnDate));
+ } else {
+ return String.format("%d %s %s", warnCode, warnAgent, warnText);
+ }
+ }
+}
Index: httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java
===================================================================
--- httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java (revision 992312)
+++ httpclient-cache/src/test/java/org/apache/http/impl/client/cache/TestProtocolRequirements.java (working copy)
@@ -2291,6 +2291,12 @@
* there was a communication failure."
*
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.1.1
+ *
+ * "111 Revalidation failed MUST be included if a cache returns a stale
+ * response because an attempt to revalidate the response failed, due to an
+ * inability to reach the server."
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46
*/
@Test
public void testMustServeAppropriateErrorOrWarningIfNoOriginCommunicationPossible()
@@ -2538,6 +2544,12 @@
* been added."
*
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.2.4
+ *
+ * "113 Heuristic expiration MUST be included if the cache heuristically
+ * chose a freshness lifetime greater than 24 hours and the response's age
+ * is greater than 24 hours."
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46
*/
@Test
public void testHeuristicCacheOlderThan24HoursHasWarningAttached() throws Exception {
@@ -4705,6 +4717,11 @@
* is stale).
*
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.3
+ *
+ * "110 Response is stale MUST be included whenever the returned
+ * response is stale."
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46
*/
@Test
public void testWarning110IsAddedToStaleResponses()
@@ -5474,84 +5491,84 @@
*/
@Test
public void testProperlyFormattedViaHeaderIsAddedToRequests() throws Exception {
- Capture cap = new Capture();
- request.removeHeaders("Via");
- EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class),
- EasyMock.capture(cap), (HttpContext)EasyMock.isNull()))
- .andReturn(originResponse);
-
- replayMocks();
- impl.execute(host, request);
- verifyMocks();
-
- HttpRequest captured = cap.getValue();
- String via = captured.getFirstHeader("Via").getValue();
- assertValidViaHeader(via);
+ Capture cap = new Capture();
+ request.removeHeaders("Via");
+ EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class),
+ EasyMock.capture(cap), (HttpContext)EasyMock.isNull()))
+ .andReturn(originResponse);
+
+ replayMocks();
+ impl.execute(host, request);
+ verifyMocks();
+
+ HttpRequest captured = cap.getValue();
+ String via = captured.getFirstHeader("Via").getValue();
+ assertValidViaHeader(via);
}
-
+
@Test
public void testProperlyFormattedViaHeaderIsAddedToResponses() throws Exception {
- originResponse.removeHeaders("Via");
- backendExpectsAnyRequest().andReturn(originResponse);
- replayMocks();
- HttpResponse result = impl.execute(host, request);
- verifyMocks();
- assertValidViaHeader(result.getFirstHeader("Via").getValue());
+ originResponse.removeHeaders("Via");
+ backendExpectsAnyRequest().andReturn(originResponse);
+ replayMocks();
+ HttpResponse result = impl.execute(host, request);
+ verifyMocks();
+ assertValidViaHeader(result.getFirstHeader("Via").getValue());
}
-
-
+
+
private void assertValidViaHeader(String via) {
- // Via = "Via" ":" 1#( received-protocol received-by [ comment ] )
- // received-protocol = [ protocol-name "/" ] protocol-version
- // protocol-name = token
- // protocol-version = token
- // received-by = ( host [ ":" port ] ) | pseudonym
- // pseudonym = token
-
- String[] parts = via.split("\\s+");
- Assert.assertTrue(parts.length >= 2);
-
- // received protocol
- String receivedProtocol = parts[0];
- String[] protocolParts = receivedProtocol.split("/");
- Assert.assertTrue(protocolParts.length >= 1);
- Assert.assertTrue(protocolParts.length <= 2);
-
- final String tokenRegexp = "[^\\p{Cntrl}()<>@,;:\\\\\"/\\[\\]?={} \\t]+";
- for(String protocolPart : protocolParts) {
- Assert.assertTrue(Pattern.matches(tokenRegexp, protocolPart));
- }
-
- // received-by
- if (!Pattern.matches(tokenRegexp, parts[1])) {
- // host : port
- new HttpHost(parts[1]);
- }
-
- // comment
- if (parts.length > 2) {
- StringBuilder buf = new StringBuilder(parts[2]);
- for(int i=3; i= 2);
+
+ // received protocol
+ String receivedProtocol = parts[0];
+ String[] protocolParts = receivedProtocol.split("/");
+ Assert.assertTrue(protocolParts.length >= 1);
+ Assert.assertTrue(protocolParts.length <= 2);
+
+ final String tokenRegexp = "[^\\p{Cntrl}()<>@,;:\\\\\"/\\[\\]?={} \\t]+";
+ for(String protocolPart : protocolParts) {
+ Assert.assertTrue(Pattern.matches(tokenRegexp, protocolPart));
+ }
+
+ // received-by
+ if (!Pattern.matches(tokenRegexp, parts[1])) {
+ // host : port
+ new HttpHost(parts[1]);
+ }
+
+ // comment
+ if (parts.length > 2) {
+ StringBuilder buf = new StringBuilder(parts[2]);
+ for(int i=3; i cap = new Capture();
- EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class),
- EasyMock.capture(cap), (HttpContext)EasyMock.isNull()))
- .andReturn(originResponse);
-
- replayMocks();
- impl.execute(host, request);
- verifyMocks();
-
- HttpRequest captured = cap.getValue();
- String via = captured.getFirstHeader("Via").getValue();
- String protocol = via.split("\\s+")[0];
- String[] protoParts = protocol.split("/");
- if (protoParts.length > 1) {
- Assert.assertTrue("http".equalsIgnoreCase(protoParts[0]));
- }
- Assert.assertEquals("1.0",protoParts[protoParts.length-1]);
+ throws Exception {
+ request = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_0);
+ request.removeHeaders("Via");
+ Capture cap = new Capture();
+ EasyMock.expect(mockBackend.execute(EasyMock.isA(HttpHost.class),
+ EasyMock.capture(cap), (HttpContext)EasyMock.isNull()))
+ .andReturn(originResponse);
+
+ replayMocks();
+ impl.execute(host, request);
+ verifyMocks();
+
+ HttpRequest captured = cap.getValue();
+ String via = captured.getFirstHeader("Via").getValue();
+ String protocol = via.split("\\s+")[0];
+ String[] protoParts = protocol.split("/");
+ if (protoParts.length > 1) {
+ Assert.assertTrue("http".equalsIgnoreCase(protoParts[0]));
+ }
+ Assert.assertEquals("1.0",protoParts[protoParts.length-1]);
}
-
+
@Test
public void testViaHeaderOnResponseProperlyRecordsOriginProtocol()
- throws Exception {
+ throws Exception {
+
+ originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_NO_CONTENT, "No Content");
+
+ backendExpectsAnyRequest().andReturn(originResponse);
+
+ replayMocks();
+ HttpResponse result = impl.execute(host, request);
+ verifyMocks();
+
+ String via = result.getFirstHeader("Via").getValue();
+ String protocol = via.split("\\s+")[0];
+ String[] protoParts = protocol.split("/");
+ Assert.assertTrue(protoParts.length >= 1);
+ Assert.assertTrue(protoParts.length <= 2);
+ if (protoParts.length > 1) {
+ Assert.assertTrue("http".equalsIgnoreCase(protoParts[0]));
+ }
+ Assert.assertEquals("1.0", protoParts[protoParts.length - 1]);
+ }
- originResponse = new BasicHttpResponse(HttpVersion.HTTP_1_0, HttpStatus.SC_NO_CONTENT, "No Content");
+ /* "A cache MUST NOT delete any Warning header that it received with
+ * a message."
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46
+ */
+ @Test
+ public void testRetainsWarningHeadersReceivedFromUpstream()
+ throws Exception {
+ originResponse.removeHeaders("Warning");
+ final String warning = "199 fred \"misc\"";
+ originResponse.addHeader("Warning", warning);
+ backendExpectsAnyRequest().andReturn(originResponse);
+
+ replayMocks();
+ HttpResponse result = impl.execute(host, request);
+ verifyMocks();
+ Assert.assertEquals(warning,
+ result.getFirstHeader("Warning").getValue());
+ }
+
+ /* "However, if a cache successfully validates a cache entry, it
+ * SHOULD remove any Warning headers previously attached to that
+ * entry except as specified for specific Warning codes. It MUST
+ * then add any Warning headers received in the validating response."
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46
+ */
+ @Test
+ public void testUpdatesWarningHeadersOnValidation()
+ throws Exception {
+ HttpRequest req1 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
+ HttpRequest req2 = new BasicHttpRequest("GET", "/", HttpVersion.HTTP_1_1);
+
+ Date now = new Date();
+ Date twentySecondsAgo = new Date(now.getTime() - 20 * 1000L);
+ HttpResponse resp1 = make200Response();
+ resp1.setHeader("Date", DateUtils.formatDate(twentySecondsAgo));
+ resp1.setHeader("Cache-Control","public,max-age=5");
+ resp1.setHeader("ETag", "\"etag1\"");
+ final String oldWarning = "113 wilma \"stale\"";
+ resp1.setHeader("Warning", oldWarning);
+
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+ HttpResponse resp2 = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_NOT_MODIFIED, "Not Modified");
+ resp2.setHeader("Date", DateUtils.formatDate(tenSecondsAgo));
+ resp2.setHeader("ETag", "\"etag1\"");
+ final String newWarning = "113 betty \"stale too\"";
+ resp2.setHeader("Warning", newWarning);
+
+ backendExpectsAnyRequest().andReturn(resp1);
+ backendExpectsAnyRequest().andReturn(resp2);
+
+ replayMocks();
+ impl.execute(host, req1);
+ HttpResponse result = impl.execute(host, req2);
+ verifyMocks();
+
+ boolean oldWarningFound = false;
+ boolean newWarningFound = false;
+ for(Header h : result.getHeaders("Warning")) {
+ for(String warnValue : h.getValue().split("\\s*,\\s*")) {
+ if (oldWarning.equals(warnValue)) {
+ oldWarningFound = true;
+ } else if (newWarning.equals(warnValue)) {
+ newWarningFound = true;
+ }
+ }
+ }
+ Assert.assertFalse(oldWarningFound);
+ Assert.assertTrue(newWarningFound);
+ }
+
+ /* "If an implementation sends a message with one or more Warning
+ * headers whose version is HTTP/1.0 or lower, then the sender MUST
+ * include in each warning-value a warn-date that matches the date
+ * in the response."
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46
+ */
+ @Test
+ public void testWarnDatesAreAddedToWarningsOnLowerProtocolVersions()
+ throws Exception {
+ final String dateHdr = DateUtils.formatDate(new Date());
+ final String origWarning = "110 fred \"stale\"";
+ originResponse.setStatusLine(HttpVersion.HTTP_1_0, HttpStatus.SC_OK);
+ originResponse.addHeader("Warning", origWarning);
+ originResponse.setHeader("Date", dateHdr);
+ backendExpectsAnyRequest().andReturn(originResponse);
+ replayMocks();
+ HttpResponse result = impl.execute(host, request);
+ verifyMocks();
+ // note that currently the implementation acts as an HTTP/1.1 proxy,
+ // which means that all the responses from the caching module should
+ // be HTTP/1.1, so we won't actually be testing anything here until
+ // that changes.
+ if (HttpVersion.HTTP_1_0.greaterEquals(result.getProtocolVersion())) {
+ Assert.assertEquals(dateHdr, result.getFirstHeader("Date").getValue());
+ boolean warningFound = false;
+ String targetWarning = origWarning + " \"" + dateHdr + "\"";
+ for(Header h : result.getHeaders("Warning")) {
+ for(String warning : h.getValue().split("\\s*,\\s*")) {
+ if (targetWarning.equals(warning)) {
+ warningFound = true;
+ break;
+ }
+ }
+ }
+ Assert.assertTrue(warningFound);
+ }
+ }
+
+ /* "If an implementation receives a message with a warning-value that
+ * includes a warn-date, and that warn-date is different from the Date
+ * value in the response, then that warning-value MUST be deleted from
+ * the message before storing, forwarding, or using it. (This prevents
+ * bad consequences of naive caching of Warning header fields.) If all
+ * of the warning-values are deleted for this reason, the Warning
+ * header MUST be deleted as well."
+ *
+ * http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.46
+ */
+ @Test
+ public void testStripsBadlyDatedWarningsFromForwardedResponses()
+ throws Exception {
+ Date now = new Date();
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+ originResponse.setHeader("Date", DateUtils.formatDate(now));
+ originResponse.addHeader("Warning", "110 fred \"stale\", 110 wilma \"stale\" \""
+ + DateUtils.formatDate(tenSecondsAgo) + "\"");
+ originResponse.setHeader("Cache-Control","no-cache,no-store");
+ backendExpectsAnyRequest().andReturn(originResponse);
+
+ replayMocks();
+ HttpResponse result = impl.execute(host, request);
+ verifyMocks();
+
+ for(Header h : result.getHeaders("Warning")) {
+ Assert.assertFalse(h.getValue().contains("wilma"));
+ }
+ }
+
+ @Test
+ public void testStripsBadlyDatedWarningsFromStoredResponses()
+ throws Exception {
+ Date now = new Date();
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+ originResponse.setHeader("Date", DateUtils.formatDate(now));
+ originResponse.addHeader("Warning", "110 fred \"stale\", 110 wilma \"stale\" \""
+ + DateUtils.formatDate(tenSecondsAgo) + "\"");
+ originResponse.setHeader("Cache-Control","public,max-age=3600");
+ backendExpectsAnyRequest().andReturn(originResponse);
+
+ replayMocks();
+ HttpResponse result = impl.execute(host, request);
+ verifyMocks();
+
+ for(Header h : result.getHeaders("Warning")) {
+ Assert.assertFalse(h.getValue().contains("wilma"));
+ }
+ }
+
+ @Test
+ public void testRemovesWarningHeaderIfAllWarnValuesAreBadlyDated()
+ throws Exception {
+ Date now = new Date();
+ Date tenSecondsAgo = new Date(now.getTime() - 10 * 1000L);
+ originResponse.setHeader("Date", DateUtils.formatDate(now));
+ originResponse.addHeader("Warning", "110 wilma \"stale\" \""
+ + DateUtils.formatDate(tenSecondsAgo) + "\"");
+ backendExpectsAnyRequest().andReturn(originResponse);
- backendExpectsAnyRequest().andReturn(originResponse);
+ replayMocks();
+ HttpResponse result = impl.execute(host, request);
+ verifyMocks();
- replayMocks();
- HttpResponse result = impl.execute(host, request);
- verifyMocks();
+ Header[] warningHeaders = result.getHeaders("Warning");
+ Assert.assertTrue(warningHeaders == null || warningHeaders.length == 0);
+ }
- String via = result.getFirstHeader("Via").getValue();
- String protocol = via.split("\\s+")[0];
- String[] protoParts = protocol.split("/");
- Assert.assertTrue(protoParts.length >= 1);
- Assert.assertTrue(protoParts.length <= 2);
- if (protoParts.length > 1) {
- Assert.assertTrue("http".equalsIgnoreCase(protoParts[0]));
- }
- Assert.assertEquals("1.0", protoParts[protoParts.length - 1]);
- }
}
\ No newline at end of file
Index: httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java
===================================================================
--- httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java (revision 992312)
+++ httpclient-cache/src/main/java/org/apache/http/impl/client/cache/CacheEntryUpdater.java (working copy)
@@ -107,9 +107,8 @@
}
removeCacheHeadersThatMatchResponse(cacheEntryHeaderList, response);
-
- cacheEntryHeaderList.addAll(Arrays.asList(response.getAllHeaders()));
removeCacheEntry1xxWarnings(cacheEntryHeaderList, entry);
+ cacheEntryHeaderList.addAll(Arrays.asList(response.getAllHeaders()));
return cacheEntryHeaderList.toArray(new Header[cacheEntryHeaderList.size()]);
}
Index: httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProtocolCompliance.java
===================================================================
--- httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProtocolCompliance.java (revision 992312)
+++ httpclient-cache/src/main/java/org/apache/http/impl/client/cache/ResponseProtocolCompliance.java (working copy)
@@ -26,8 +26,11 @@
*/
package org.apache.http.impl.client.cache;
+import java.util.ArrayList;
import java.util.Date;
+import java.util.List;
+import org.apache.http.Header;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
@@ -38,7 +41,9 @@
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.cache.HeaderConstants;
import org.apache.http.impl.client.RequestWrapper;
+import org.apache.http.impl.cookie.DateParseException;
import org.apache.http.impl.cookie.DateUtils;
+import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
/**
@@ -77,9 +82,41 @@
ensure200ForOPTIONSRequestWithNoBodyHasContentLengthZero(request, response);
ensure206ContainsDateHeader(response);
+
+ warningsWithNonMatchingWarnDatesAreRemoved(response);
}
- private void authenticationRequiredDidNotHaveAProxyAuthenticationHeader(HttpRequest request,
+ private void warningsWithNonMatchingWarnDatesAreRemoved(
+ HttpResponse response) {
+ Date responseDate = null;
+ try {
+ responseDate = DateUtils.parseDate(response.getFirstHeader("Date").getValue());
+ } catch (DateParseException e) {
+ }
+ if (responseDate == null) return;
+ Header[] warningHeaders = response.getHeaders("Warning");
+ if (warningHeaders == null || warningHeaders.length == 0) return;
+ List newWarningHeaders = new ArrayList();
+ boolean modified = false;
+ for(Header h : warningHeaders) {
+ for(WarningValue wv : WarningValue.getWarningValues(h)) {
+ Date warnDate = wv.getWarnDate();
+ if (warnDate == null || warnDate.equals(responseDate)) {
+ newWarningHeaders.add(new BasicHeader("Warning",wv.toString()));
+ } else {
+ modified = true;
+ }
+ }
+ }
+ if (modified) {
+ response.removeHeaders("Warning");
+ for(Header h : newWarningHeaders) {
+ response.addHeader(h);
+ }
+ }
+ }
+
+ private void authenticationRequiredDidNotHaveAProxyAuthenticationHeader(HttpRequest request,
HttpResponse response) throws ClientProtocolException {
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_PROXY_AUTHENTICATION_REQUIRED)
return;