Description of problem: org.drools.guvnor.server.files.PackageDeploymentServlet responds Last-Modified header in SimpleDateFormat "EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z" (RFC822TimeZone) so in case of non-GMT timezone, the value will be like this: Tue, 05 Nov 2013 16:33:48 +0900 But this doesn't conform to RFC2616 which requires RFC 1123 format and GMT representation. http://www.ietf.org/rfc/rfc2616.txt ==== 3.3 Date/Time Formats 3.3.1 Full Date HTTP applications have historically allowed three different formats for the representation of date/time stamps: Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format The first format is preferred as an Internet standard and represents a fixed-length subset of that defined by RFC 1123 [8] (an update to RFC 822 [9]). The second format is in common use, but is based on the obsolete RFC 850 [12] date format and lacks a four-digit year. HTTP/1.1 clients and servers that parse the date value MUST accept all three formats (for compatibility with HTTP/1.0), though they MUST only generate the RFC 1123 format for representing HTTP-date values in header fields. See section 19.3 for further information. Note: Recipients of date values are encouraged to be robust in accepting date values that may have been sent by non-HTTP applications, as is sometimes the case when retrieving or posting messages via proxies/gateways to SMTP or NNTP. All HTTP date/time stamps MUST be represented in Greenwich Mean Time (GMT), without exception. For the purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal Time). This is indicated in the first two formats by the inclusion of "GMT" as the three-letter abbreviation for time zone, and MUST be assumed when reading the asctime format. HTTP-date is case sensitive and MUST NOT include additional LWS beyond that specifically included as SP in the grammar. HTTP-date = rfc1123-date | rfc850-date | asctime-date rfc1123-date = wkday "," SP date1 SP time SP "GMT" rfc850-date = weekday "," SP date2 SP time SP "GMT" asctime-date = wkday SP date3 SP time SP 4DIGIT date1 = 2DIGIT SP month SP 4DIGIT ; day month year (e.g., 02 Jun 1982) date2 = 2DIGIT "-" month "-" 2DIGIT ; day-month-year (e.g., 02-Jun-82) date3 = month SP ( 2DIGIT | ( SP 1DIGIT )) ; month day (e.g., Jun 2) time = 2DIGIT ":" 2DIGIT ":" 2DIGIT ; 00:00:00 - 23:59:59 wkday = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun" weekday = "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday" | "Saturday" | "Sunday" month = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec" Note: HTTP requirements for the date/time stamp format apply only to their usage within the protocol stream. Clients and servers are not required to use these formats for user presentation, request logging, etc. 14.29 Last-Modified The Last-Modified entity-header field indicates the date and time at which the origin server believes the variant was last modified. Last-Modified = "Last-Modified" ":" HTTP-date ==== It results in returning an wrong value by HttpURLConnection.getLastModified() because HttpURLConnection.getLastModified() cannot parse RFC822TimeZone part ("+0900"). Finally, org.drools.io.impl.UrlResource stores the wrong LastModified time. UrlResource.java: ==== private long grabLastMod() throws IOException { // use File if possible, as http rounds milliseconds on some machines, this fine level of granularity is only really an issue for testing // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4504473 if ( "file".equals( url.getProtocol() ) ) { File file = getFile(); return file.lastModified(); } else { URLConnection conn = getURL().openConnection(); if ( conn instanceof HttpURLConnection) { ((HttpURLConnection) conn).setRequestMethod( "HEAD" ); } long date = conn.getLastModified(); if (date == 0) { try { date = Long.parseLong(conn.getHeaderField("lastModified")); } catch (Exception e) { /* well, we tried ... */ } } return date; } } ==== Correct format is rfc1123-date so the value should be like: Wed, 06 Nov 2013 07:36:42 GMT Steps to Reproduce: 1. Start BRMS under non-GMT timezone (e.g. start with -Duser.timezone=Asia/Tokyo) 2. Run a java class like this: public class VerifyLastModified { public static void main(String[] args) throws Exception { URL url = new URL("http://localhost:8080/jboss-brms/org.drools.guvnor.Guvnor/package/defaultPackage/LATEST"); URLConnection conn = url.openConnection(); if (conn instanceof HttpURLConnection) { ((HttpURLConnection) conn).setRequestMethod("HEAD"); } String headerField2 = conn.getHeaderField("last-modified"); System.out.println("last-modified -> " + headerField2); System.out.println("last-modified -> " + Date.parse(headerField2)); System.out.println("last-modified -> " + new Date(Date.parse(headerField2))); long lastModified = conn.getLastModified(); System.out.println("conn.getLastModified -> " + lastModified); System.out.println("conn.getLastModified -> " + new Date(lastModified)); String headerField1 = conn.getHeaderField("lastModified"); System.out.println("lastModified -> " + headerField1); System.out.println("lastModified -> " + Long.parseLong(headerField1)); System.out.println("lastModified -> " + new Date(Long.parseLong(headerField1))); } } Actual results: last-modified header has RFC822TimeZone. conn.getLastModified() doesn't equal to the correct value (last-modified / lastModified) example) last-modified -> Wed, 06 Nov 2013 19:39:21 +0900 last-modified -> 1383734361000 last-modified -> Wed Nov 06 19:39:21 JST 2013 conn.getLastModified -> 1383766761000 conn.getLastModified -> Thu Nov 07 04:39:21 JST 2013 lastModified -> 1383734361812 lastModified -> 1383734361812 lastModified -> Wed Nov 06 19:39:21 JST 2013 Expected results: last-modified header is GMT. conn.getLastModified equals to the correct value (last-modified / lastModified) example) last-modified -> Wed, 06 Nov 2013 10:39:21 GMT last-modified -> 1383734361000 last-modified -> Wed Nov 06 19:39:21 JST 2013 conn.getLastModified -> 1383734361000 conn.getLastModified -> Wed Nov 06 19:39:21 JST 2013 lastModified -> 1383734361812 lastModified -> 1383734361812 lastModified -> Wed Nov 06 19:39:21 JST 2013
Sent a pull request: https://github.com/droolsjbpm/guvnor/pull/106
Verified fixed in 5.3.1-P05. Output from the reproducer (just for reference): last-modified -> Thu, 13 Feb 2014 14:41:06 GMT last-modified -> 1392302466000 last-modified -> Thu Feb 13 15:41:06 CET 2014 conn.getLastModified -> 1392302466000 conn.getLastModified -> Thu Feb 13 15:41:06 CET 2014 lastModified -> 1392302466109 lastModified -> 1392302466109 lastModified -> Thu Feb 13 15:41:06 CET 2014