You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2017/12/26 16:22:12 UTC

httpcomponents-client git commit: Added Date util methods for common operations

Repository: httpcomponents-client
Updated Branches:
  refs/heads/master 1e4e20416 -> 6459d6882


Added Date util methods for common operations


Project: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/repo
Commit: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/commit/6459d688
Tree: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/tree/6459d688
Diff: http://git-wip-us.apache.org/repos/asf/httpcomponents-client/diff/6459d688

Branch: refs/heads/master
Commit: 6459d6882c9cc8fb37c92d44f4d9b4d95d90aaf3
Parents: 1e4e204
Author: Oleg Kalnichevski <ol...@apache.org>
Authored: Tue Dec 26 17:18:20 2017 +0100
Committer: Oleg Kalnichevski <ol...@apache.org>
Committed: Tue Dec 26 17:18:20 2017 +0100

----------------------------------------------------------------------
 .../hc/client5/http/cache/HttpCacheEntry.java   |   6 +-
 .../http/impl/cache/CacheUpdateHandler.java     |  11 +-
 .../http/impl/cache/CacheValidityPolicy.java    |  20 +--
 .../cache/CachedResponseSuitabilityChecker.java |   6 +-
 .../http/impl/cache/CachingExecBase.java        |  46 +++----
 .../impl/cache/DefaultCacheInvalidator.java     |  17 +--
 .../http/impl/cache/ResponseCachingPolicy.java  |   3 +-
 .../impl/cache/ResponseProtocolCompliance.java  |   2 +-
 .../impl/cache/TestCacheValidityPolicy.java     |   8 --
 .../apache/hc/client5/http/utils/DateUtils.java |  95 +++++++++++++++
 .../hc/client5/http/utils/TestDateUtils.java    | 121 +++++++++++--------
 11 files changed, 190 insertions(+), 145 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheEntry.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheEntry.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheEntry.java
index 62cf508..1affd69 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheEntry.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/cache/HttpCacheEntry.java
@@ -132,11 +132,7 @@ public class HttpCacheEntry implements MessageHeaders, Serializable {
      * @return the Date value of the header or null if the header is not present
      */
     private Date parseDate() {
-        final Header dateHdr = getFirstHeader(HttpHeaders.DATE);
-        if (dateHdr == null) {
-            return null;
-        }
-        return DateUtils.parseDate(dateHdr.getValue());
+        return DateUtils.parseDate(this, HttpHeaders.DATE);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheUpdateHandler.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheUpdateHandler.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheUpdateHandler.java
index 5034e04..5ca5225 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheUpdateHandler.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheUpdateHandler.java
@@ -44,7 +44,6 @@ import org.apache.hc.core5.http.HttpHeaders;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpResponse;
 import org.apache.hc.core5.http.HttpStatus;
-import org.apache.hc.core5.http.MessageHeaders;
 import org.apache.hc.core5.http.message.HeaderGroup;
 import org.apache.hc.core5.util.Args;
 import org.apache.hc.core5.util.ByteArrayBuffer;
@@ -137,16 +136,8 @@ class CacheUpdateHandler {
                 variantMap);
     }
 
-    private static Date getDate(final MessageHeaders messageHeaders) {
-        final Header dateHeader = messageHeaders.getFirstHeader(HttpHeaders.DATE);
-        return dateHeader != null ? DateUtils.parseDate(dateHeader.getValue()): null;
-    }
-
     private Header[] mergeHeaders(final HttpCacheEntry entry, final HttpResponse response) {
-        final Date cacheDate = getDate(entry);
-        final Date responseDate = getDate(response);
-        if (cacheDate != null && responseDate != null && cacheDate.after(responseDate)) {
-            // Don't merge headers, keep the entry's headers as they are newer.
+        if (DateUtils.isAfter(entry, response, HttpHeaders.DATE)) {
             return entry.getAllHeaders();
         }
         final HeaderGroup headerGroup = new HeaderGroup();

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
index 0173a3e..7930d43 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CacheValidityPolicy.java
@@ -69,7 +69,7 @@ class CacheValidityPolicy {
             return 0L;
         }
 
-        final Date expiry = getExpirationDate(entry);
+        final Date expiry = DateUtils.parseDate(entry, HeaderConstants.EXPIRES);
         if (expiry == null) {
             return 0;
         }
@@ -102,7 +102,7 @@ class CacheValidityPolicy {
     public long getHeuristicFreshnessLifetimeSecs(final HttpCacheEntry entry,
             final float coefficient, final long defaultLifetime) {
         final Date dateValue = entry.getDate();
-        final Date lastModifiedValue = getLastModifiedValue(entry);
+        final Date lastModifiedValue = DateUtils.parseDate(entry, HeaderConstants.LAST_MODIFIED);
 
         if (dateValue != null && lastModifiedValue != null) {
             final long diff = dateValue.getTime() - lastModifiedValue.getTime();
@@ -173,14 +173,6 @@ class CacheValidityPolicy {
         return result;
     }
 
-    protected Date getLastModifiedValue(final HttpCacheEntry entry) {
-        final Header dateHdr = entry.getFirstHeader(HeaderConstants.LAST_MODIFIED);
-        if (dateHdr == null) {
-            return null;
-        }
-        return DateUtils.parseDate(dateHdr.getValue());
-    }
-
     /**
      * This matters for deciding whether the cache entry is valid to serve as a
      * response. If these values do not match, we might have a partial response
@@ -275,14 +267,6 @@ class CacheValidityPolicy {
         return maxage;
     }
 
-    protected Date getExpirationDate(final HttpCacheEntry entry) {
-        final Header expiresHeader = entry.getFirstHeader(HeaderConstants.EXPIRES);
-        if (expiresHeader == null) {
-            return null;
-        }
-        return DateUtils.parseDate(expiresHeader.getValue());
-    }
-
     public boolean hasCacheControlDirective(final HttpCacheEntry entry, final String directive) {
         final Iterator<HeaderElement> it = MessageSupport.iterate(entry, HeaderConstants.CACHE_CONTROL);
         while (it.hasNext()) {

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
index 4754f04..c7160fb 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachedResponseSuitabilityChecker.java
@@ -336,11 +336,7 @@ class CachedResponseSuitabilityChecker {
      * @return  boolean Does the last modified header match
      */
     private boolean lastModifiedValidatorMatches(final HttpRequest request, final HttpCacheEntry entry, final Date now) {
-        final Header lastModifiedHeader = entry.getFirstHeader(HeaderConstants.LAST_MODIFIED);
-        Date lastModified = null;
-        if (lastModifiedHeader != null) {
-            lastModified = DateUtils.parseDate(lastModifiedHeader.getValue());
-        }
+        final Date lastModified = DateUtils.parseDate(entry, HeaderConstants.LAST_MODIFIED);
         if (lastModified == null) {
             return false;
         }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
index d823513..39300f3 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/CachingExecBase.java
@@ -362,25 +362,12 @@ public class CachingExecBase {
         return true;
     }
 
-    boolean revalidationResponseIsTooOld(final HttpResponse backendResponse,
-            final HttpCacheEntry cacheEntry) {
-        final Header entryDateHeader = cacheEntry.getFirstHeader(HttpHeaders.DATE);
-        final Header responseDateHeader = backendResponse.getFirstHeader(HttpHeaders.DATE);
-        if (entryDateHeader != null && responseDateHeader != null) {
-            final Date entryDate = DateUtils.parseDate(entryDateHeader.getValue());
-            final Date respDate = DateUtils.parseDate(responseDateHeader.getValue());
-            if (entryDate == null || respDate == null) {
-                // either backend response or cached entry did not have a valid
-                // Date header, so we can't tell if they are out of order
-                // according to the origin clock; thus we can skip the
-                // unconditional retry recommended in 13.2.6 of RFC 2616.
-                return false;
-            }
-            if (respDate.before(entryDate)) {
-                return true;
-            }
-        }
-        return false;
+    boolean revalidationResponseIsTooOld(final HttpResponse backendResponse, final HttpCacheEntry cacheEntry) {
+        // either backend response or cached entry did not have a valid
+        // Date header, so we can't tell if they are out of order
+        // according to the origin clock; thus we can skip the
+        // unconditional retry recommended in 13.2.6 of RFC 2616.
+        return DateUtils.isBefore(backendResponse, cacheEntry, HttpHeaders.DATE);
     }
 
     void tryToUpdateVariantMap(
@@ -426,6 +413,14 @@ public class CachingExecBase {
 
     boolean alreadyHaveNewerCacheEntry(
             final HttpHost target, final HttpRequest request, final HttpResponse backendResponse) {
+        final Header responseDateHeader = backendResponse.getFirstHeader(HttpHeaders.DATE);
+        if (responseDateHeader == null) {
+            return false;
+        }
+        final Date responseDate = DateUtils.parseDate(responseDateHeader.getValue());
+        if (responseDate == null) {
+            return false;
+        }
         HttpCacheEntry existing = null;
         try {
             existing = responseCache.getCacheEntry(target, request);
@@ -435,17 +430,8 @@ public class CachingExecBase {
         if (existing == null) {
             return false;
         }
-        final Header entryDateHeader = existing.getFirstHeader(HttpHeaders.DATE);
-        if (entryDateHeader == null) {
-            return false;
-        }
-        final Header responseDateHeader = backendResponse.getFirstHeader(HttpHeaders.DATE);
-        if (responseDateHeader == null) {
-            return false;
-        }
-        final Date entryDate = DateUtils.parseDate(entryDateHeader.getValue());
-        final Date responseDate = DateUtils.parseDate(responseDateHeader.getValue());
-        if (entryDate == null || responseDate == null) {
+        final Date entryDate = DateUtils.parseDate(existing, HttpHeaders.DATE);
+        if (entryDate == null) {
             return false;
         }
         return responseDate.before(entryDate);

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
index e988947..725540f 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/DefaultCacheInvalidator.java
@@ -29,7 +29,6 @@ package org.apache.hc.client5.http.impl.cache;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.util.Date;
 
 import org.apache.hc.client5.http.cache.HeaderConstants;
 import org.apache.hc.client5.http.cache.HttpCacheEntry;
@@ -273,19 +272,7 @@ class DefaultCacheInvalidator implements HttpCacheInvalidator {
         return (!entryEtag.getValue().equals(responseEtag.getValue()));
     }
 
-    private boolean responseDateOlderThanEntryDate(final HttpResponse response,
-            final HttpCacheEntry entry) {
-        final Header entryDateHeader = entry.getFirstHeader(HttpHeaders.DATE);
-        final Header responseDateHeader = response.getFirstHeader(HttpHeaders.DATE);
-        if (entryDateHeader == null || responseDateHeader == null) {
-            /* be conservative; should probably flush */
-            return false;
-        }
-        final Date entryDate = DateUtils.parseDate(entryDateHeader.getValue());
-        final Date responseDate = DateUtils.parseDate(responseDateHeader.getValue());
-        if (entryDate == null || responseDate == null) {
-            return false;
-        }
-        return responseDate.before(entryDate);
+    private boolean responseDateOlderThanEntryDate(final HttpResponse response, final HttpCacheEntry entry) {
+        return DateUtils.isBefore(response, entry, HttpHeaders.DATE);
     }
 }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
index 37d8a97..4078c1a 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseCachingPolicy.java
@@ -161,8 +161,7 @@ class ResponseCachingPolicy {
             return false;
         }
 
-        final Header h = response.getFirstHeader(HttpHeaders.DATE);
-        final Date date = h != null ? DateUtils.parseDate(h.getValue()) : null;
+        final Date date = DateUtils.parseDate(response, HttpHeaders.DATE);
         if (date == null) {
             log.debug("Invalid / missing Date header");
             return false;

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java
index 0d618be..ff5f0cc 100644
--- a/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java
+++ b/httpclient5-cache/src/main/java/org/apache/hc/client5/http/impl/cache/ResponseProtocolCompliance.java
@@ -91,7 +91,7 @@ class ResponseProtocolCompliance {
 
     private void warningsWithNonMatchingWarnDatesAreRemoved(
             final HttpResponse response) {
-        final Date responseDate = DateUtils.parseDate(response.getFirstHeader(HttpHeaders.DATE).getValue());
+        final Date responseDate = DateUtils.parseDate(response, HttpHeaders.DATE);
         if (responseDate == null) {
             return;
         }

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
----------------------------------------------------------------------
diff --git a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
index 935986b..4da26f7 100644
--- a/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
+++ b/httpclient5-cache/src/test/java/org/apache/hc/client5/http/impl/cache/TestCacheValidityPolicy.java
@@ -28,7 +28,6 @@ package org.apache.hc.client5.http.impl.cache;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
 import static org.junit.Assert.assertTrue;
 
@@ -383,13 +382,6 @@ public class TestCacheValidityPolicy {
     }
 
     @Test
-    public void testMalformedExpirationDateReturnsNull() {
-        final Header[] headers = new Header[] { new BasicHeader("Expires", "asdf") };
-        final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);
-        assertNull(impl.getExpirationDate(entry));
-    }
-
-    @Test
     public void testMustRevalidateIsFalseIfDirectiveNotPresent() {
         final Header[] headers = new Header[] { new BasicHeader("Cache-Control","public") };
         final HttpCacheEntry entry = HttpTestUtils.makeCacheEntry(headers);

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java b/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java
index a9a7ab2..ed5cb38 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/utils/DateUtils.java
@@ -39,6 +39,8 @@ import java.util.TimeZone;
 
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http.Header;
+import org.apache.hc.core5.http.MessageHeaders;
 import org.apache.hc.core5.util.Args;
 
 /**
@@ -98,6 +100,99 @@ public final class DateUtils {
     }
 
     /**
+     * Parses a date value from a header with the given name.
+     *
+     * @param headers message headers
+     * @param headerName header name
+     *
+     * @return the parsed date or null if input could not be parsed
+     *
+     * @since 5.0
+     */
+    public static Date parseDate(final MessageHeaders headers, final String headerName) {
+        if (headers == null) {
+            return null;
+        }
+        final Header header = headers.getFirstHeader(headerName);
+        if (header == null) {
+            return null;
+        }
+        return parseDate(header.getValue(), null, null);
+    }
+
+    /**
+     * Tests if the first message is after (newer) than seconds message
+     * using the given message header for comparison.
+     *
+     * @param message1 the first message
+     * @param message2 the second message
+     * @param headerName header name
+     *
+     * @return {@code true} if both messages contain a header with the given name
+     *  and the value of the header from the first message is newer that of
+     *  the second message.
+     *
+     * @since 5.0
+     */
+    public static boolean isAfter(
+            final MessageHeaders message1,
+            final MessageHeaders message2,
+            final String headerName) {
+        if (message1 != null && message2 != null) {
+            final Header dateHeader1 = message1.getFirstHeader(headerName);
+            if (dateHeader1 != null) {
+                final Header dateHeader2 = message2.getFirstHeader(headerName);
+                if (dateHeader2 != null) {
+                    final Date date1 = parseDate(dateHeader1.getValue());
+                    if (date1 != null) {
+                        final Date date2 = parseDate(dateHeader2.getValue());
+                        if (date2 != null) {
+                            return date1.after(date2);
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Tests if the first message is before (older) than seconds message
+     * using the given message header for comparison.
+     *
+     * @param message1 the first message
+     * @param message2 the second message
+     * @param headerName header name
+     *
+     * @return {@code true} if both messages contain a header with the given name
+     *  and the value of the header from the first message is older that of
+     *  the second message.
+     *
+     * @since 5.0
+     */
+    public static boolean isBefore(
+            final MessageHeaders message1,
+            final MessageHeaders message2,
+            final String headerName) {
+        if (message1 != null && message2 != null) {
+            final Header dateHeader1 = message1.getFirstHeader(headerName);
+            if (dateHeader1 != null) {
+                final Header dateHeader2 = message2.getFirstHeader(headerName);
+                if (dateHeader2 != null) {
+                    final Date date1 = parseDate(dateHeader1.getValue());
+                    if (date1 != null) {
+                        final Date date2 = parseDate(dateHeader2.getValue());
+                        if (date2 != null) {
+                            return date1.before(date2);
+                        }
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
      * Parses the date value using the given date formats.
      *
      * @param dateValue the date value to parse

http://git-wip-us.apache.org/repos/asf/httpcomponents-client/blob/6459d688/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java
----------------------------------------------------------------------
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java b/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java
index 591ad1c..8f1da94 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/utils/TestDateUtils.java
@@ -30,6 +30,10 @@ package org.apache.hc.client5.http.utils;
 import java.util.Calendar;
 import java.util.Date;
 
+import org.apache.hc.core5.http.HttpHeaders;
+import org.apache.hc.core5.http.message.BasicHeader;
+import org.apache.hc.core5.http.message.HeaderGroup;
+import org.hamcrest.CoreMatchers;
 import org.junit.Assert;
 import org.junit.Test;
 
@@ -38,23 +42,33 @@ import org.junit.Test;
  */
 public class TestDateUtils {
 
-    @Test
-    public void testBasicDateParse() throws Exception {
+    private static Date createDate(final int year, final int month, final int day) {
         final Calendar calendar = Calendar.getInstance();
         calendar.setTimeZone(DateUtils.GMT);
-        calendar.set(2005, Calendar.OCTOBER, 14, 0, 0, 0);
-        calendar.set(Calendar.MILLISECOND, 0);
-        final Date date1 = calendar.getTime();
+        calendar.setTimeInMillis(0);
+        calendar.set(year, month, day);
+        return calendar.getTime();
+    }
 
-        final String[] formats = new String[] {
-                DateUtils.PATTERN_RFC1123
-                };
-        Date date2 = DateUtils.parseDate("Fri, 14 Oct 2005 00:00:00 GMT", formats, null);
-        Assert.assertEquals(date1, date2);
-        date2 = DateUtils.parseDate("Fri, 14 Oct 2005 00:00:00 GMT", formats);
-        Assert.assertEquals(date1, date2);
-        date2 = DateUtils.parseDate("Fri, 14 Oct 2005 00:00:00 GMT");
-        Assert.assertEquals(date1, date2);
+    @Test
+    public void testBasicDateParse() throws Exception {
+        final Date date = createDate(2005, Calendar.OCTOBER, 14);
+        final String[] formats = new String[] { DateUtils.PATTERN_RFC1123 };
+        Assert.assertEquals(date, DateUtils.parseDate("Fri, 14 Oct 2005 00:00:00 GMT", formats, null));
+        Assert.assertEquals(date, DateUtils.parseDate("Fri, 14 Oct 2005 00:00:00 GMT", formats));
+        Assert.assertEquals(date, DateUtils.parseDate("Fri, 14 Oct 2005 00:00:00 GMT"));
+    }
+
+    @Test
+    public void testDateParseMessage() throws Exception {
+        final HeaderGroup message1 = new HeaderGroup();
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "Fri, 14 Oct 2005 00:00:00 GMT"));
+        Assert.assertEquals(createDate(2005, Calendar.OCTOBER, 14), DateUtils.parseDate(message1, HttpHeaders.DATE));
+
+        final HeaderGroup message2 = new HeaderGroup();
+        message2.addHeader(new BasicHeader(HttpHeaders.DATE, "Fri, 14 Oct 2005 00:00:00 GMT"));
+        message2.addHeader(new BasicHeader(HttpHeaders.DATE, "Fri, 21 Oct 2005 00:00:00 GMT"));
+        Assert.assertEquals(createDate(2005, Calendar.OCTOBER, 14), DateUtils.parseDate(message2, HttpHeaders.DATE));
     }
 
     @Test
@@ -86,55 +100,60 @@ public class TestDateUtils {
 
     @Test
     public void testTwoDigitYearDateParse() throws Exception {
-        final Calendar calendar = Calendar.getInstance();
-        calendar.setTimeZone(DateUtils.GMT);
-        calendar.set(2005, Calendar.OCTOBER, 14, 0, 0, 0);
-        calendar.set(Calendar.MILLISECOND, 0);
-        Date date1 = calendar.getTime();
-
-        final String[] formats = new String[] {
-                DateUtils.PATTERN_RFC1036
-                };
-        Date date2 = DateUtils.parseDate("Friday, 14-Oct-05 00:00:00 GMT", formats, null);
-        Assert.assertEquals(date1, date2);
-
-        calendar.set(1900, Calendar.JANUARY, 0, 0, 0, 0);
-        calendar.set(Calendar.MILLISECOND, 0);
-        final Date startDate = calendar.getTime();
-
-        calendar.set(1905, Calendar.OCTOBER, 14, 0, 0, 0);
-        calendar.set(Calendar.MILLISECOND, 0);
-        date1 = calendar.getTime();
-
-        date2 = DateUtils.parseDate("Friday, 14-Oct-05 00:00:00 GMT", formats, startDate);
-        Assert.assertEquals(date1, date2);
+        final String[] formats = new String[] { DateUtils.PATTERN_RFC1036 };
+        Assert.assertEquals(createDate(2005, Calendar.OCTOBER, 14), DateUtils.parseDate("Friday, 14-Oct-05 00:00:00 GMT", formats, null));
+        Assert.assertEquals(createDate(1905, Calendar.OCTOBER, 14), DateUtils.parseDate("Friday, 14-Oct-05 00:00:00 GMT", formats,
+                createDate(1900, Calendar.JANUARY, 0)));
     }
 
     @Test
     public void testParseQuotedDate() throws Exception {
-        final Calendar calendar = Calendar.getInstance();
-        calendar.setTimeZone(DateUtils.GMT);
-        calendar.set(2005, Calendar.OCTOBER, 14, 0, 0, 0);
-        calendar.set(Calendar.MILLISECOND, 0);
-        final Date date1 = calendar.getTime();
-
-        final String[] formats = new String[] {
-                DateUtils.PATTERN_RFC1123
-                };
+        final Date date1 = createDate(2005, Calendar.OCTOBER, 14);
+        final String[] formats = new String[] { DateUtils.PATTERN_RFC1123 };
         final Date date2 = DateUtils.parseDate("'Fri, 14 Oct 2005 00:00:00 GMT'", formats);
         Assert.assertEquals(date1, date2);
     }
 
     @Test
     public void testBasicDateFormat() throws Exception {
-        final Calendar calendar = Calendar.getInstance();
-        calendar.setTimeZone(DateUtils.GMT);
-        calendar.set(2005, Calendar.OCTOBER, 14, 0, 0, 0);
-        calendar.set(Calendar.MILLISECOND, 0);
-        final Date date = calendar.getTime();
-
+        final Date date = createDate(2005, Calendar.OCTOBER, 14);
         Assert.assertEquals("Fri, 14 Oct 2005 00:00:00 GMT", DateUtils.formatDate(date));
         Assert.assertEquals("Fri, 14 Oct 2005 00:00:00 GMT", DateUtils.formatDate(date, DateUtils.PATTERN_RFC1123));
     }
 
+    @Test
+    public void testIsBefore() throws Exception {
+        final HeaderGroup message1 = new HeaderGroup();
+        final HeaderGroup message2 = new HeaderGroup();
+        Assert.assertThat(DateUtils.isBefore(null, null, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+        Assert.assertThat(DateUtils.isBefore(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "huh?"));
+        message2.setHeader(new BasicHeader(HttpHeaders.DATE, "eh?"));
+        Assert.assertThat(DateUtils.isBefore(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "huh?"));
+        message2.setHeader(new BasicHeader(HttpHeaders.DATE, "Tuesday, 26-Dec-2017 00:00:00 GMT"));
+        Assert.assertThat(DateUtils.isBefore(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "Wednesday, 25-Dec-2017 00:00:00 GMT"));
+        Assert.assertThat(DateUtils.isBefore(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(true));
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "Thursday, 27-Dec-2017 00:00:00 GMT"));
+        Assert.assertThat(DateUtils.isBefore(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+    }
+
+    @Test
+    public void testIsAfter() throws Exception {
+        final HeaderGroup message1 = new HeaderGroup();
+        final HeaderGroup message2 = new HeaderGroup();
+        Assert.assertThat(DateUtils.isAfter(null, null, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+        Assert.assertThat(DateUtils.isAfter(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "huh?"));
+        message2.setHeader(new BasicHeader(HttpHeaders.DATE, "eh?"));
+        Assert.assertThat(DateUtils.isAfter(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "huh?"));
+        message2.setHeader(new BasicHeader(HttpHeaders.DATE, "Tuesday, 26-Dec-2017 00:00:00 GMT"));
+        Assert.assertThat(DateUtils.isAfter(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "Thursday, 27-Dec-2017 00:00:00 GMT"));
+        Assert.assertThat(DateUtils.isAfter(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(true));
+        message1.setHeader(new BasicHeader(HttpHeaders.DATE, "Wednesday, 25-Dec-2017 00:00:00 GMT"));
+        Assert.assertThat(DateUtils.isAfter(message1, message2, HttpHeaders.DATE), CoreMatchers.equalTo(false));
+    }
 }