mirror of https://github.com/apache/jclouds.git
JCLOUDS-1295: Support deprecated date formats in the Expires header
This commit is contained in:
parent
28c3c33bf0
commit
db2f86bcec
|
@ -36,4 +36,5 @@ public interface DateCodecFactory {
|
|||
|
||||
DateCodec iso8601Seconds();
|
||||
|
||||
DateCodec asctime();
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ public class DateServiceDateCodecFactory implements DateCodecFactory {
|
|||
private final DateCodec rfc1123Codec;
|
||||
private final DateCodec iso8601Codec;
|
||||
private final DateCodec iso8601SecondsCodec;
|
||||
private final DateCodec asctime;
|
||||
|
||||
@Inject
|
||||
public DateServiceDateCodecFactory(DateService dateService) {
|
||||
|
@ -43,6 +44,7 @@ public class DateServiceDateCodecFactory implements DateCodecFactory {
|
|||
this.rfc1123Codec = new DateServiceRfc1123Codec(dateService);
|
||||
this.iso8601Codec = new DateServiceIso8601Codec(dateService);
|
||||
this.iso8601SecondsCodec = new DateServiceIso8601SecondsCodec(dateService);
|
||||
this.asctime = new DateServiceAsctimeCodec(dateService);
|
||||
}
|
||||
|
||||
@Singleton
|
||||
|
@ -153,6 +155,33 @@ public class DateServiceDateCodecFactory implements DateCodecFactory {
|
|||
|
||||
}
|
||||
|
||||
@Singleton
|
||||
public static class DateServiceAsctimeCodec implements DateCodec {
|
||||
|
||||
protected final DateService dateService;
|
||||
|
||||
@Inject
|
||||
public DateServiceAsctimeCodec(DateService dateService) {
|
||||
this.dateService = checkNotNull(dateService, "dateService");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Date toDate(String date) throws IllegalArgumentException {
|
||||
return dateService.cDateParse(date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(Date date) {
|
||||
return dateService.cDateFormat(date);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "asctime()";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateCodec rfc822() {
|
||||
return rfc822Codec;
|
||||
|
@ -173,4 +202,9 @@ public class DateServiceDateCodecFactory implements DateCodecFactory {
|
|||
return iso8601SecondsCodec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DateCodec asctime() {
|
||||
return asctime;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
|
|||
import static com.google.common.net.HttpHeaders.EXPIRES;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -38,6 +39,7 @@ import org.jclouds.io.ContentMetadataCodec.DefaultContentMetadataCodec;
|
|||
import org.jclouds.logging.Logger;
|
||||
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMultimap;
|
||||
import com.google.common.collect.ImmutableMultimap.Builder;
|
||||
import com.google.common.collect.Multimap;
|
||||
|
@ -73,16 +75,22 @@ public interface ContentMetadataCodec {
|
|||
protected Logger logger = Logger.NULL;
|
||||
|
||||
private final DateCodec httpExpiresDateCodec;
|
||||
private final List<DateCodec> httpExpiresDateDecoders;
|
||||
|
||||
@Inject
|
||||
public DefaultContentMetadataCodec(DateCodecFactory dateCodecs) {
|
||||
httpExpiresDateCodec = dateCodecs.rfc1123();
|
||||
httpExpiresDateDecoders = ImmutableList.of(dateCodecs.rfc1123(), dateCodecs.asctime());
|
||||
}
|
||||
|
||||
|
||||
protected DateCodec getExpiresDateCodec() {
|
||||
return httpExpiresDateCodec;
|
||||
}
|
||||
|
||||
|
||||
protected List<DateCodec> getExpiresDateDecoders() {
|
||||
return httpExpiresDateDecoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Multimap<String, String> toHeaders(ContentMetadata md) {
|
||||
Builder<String, String> builder = ImmutableMultimap.builder();
|
||||
|
@ -134,14 +142,31 @@ public interface ContentMetadataCodec {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the date from the given Expires header.
|
||||
* <p>
|
||||
* According to the RFC, dates should always come in RFC-1123 format.
|
||||
* However, clients should also support older and deprecated formats for
|
||||
* compatibility, so this method will try to parse an RFC-1123 date, and
|
||||
* fallback to the ANSI C format.
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc2616#section-3.3
|
||||
*/
|
||||
public Date parseExpires(String expires) {
|
||||
try {
|
||||
return (expires != null) ? getExpiresDateCodec().toDate(expires) : null;
|
||||
} catch (IllegalArgumentException e) {
|
||||
logger.debug("Invalid Expires header (%s); should be in RFC-1123 format; treating as already expired: %s",
|
||||
expires, e.getMessage());
|
||||
return new Date(0);
|
||||
if (expires == null)
|
||||
return null;
|
||||
|
||||
for (DateCodec decoder : getExpiresDateDecoders()) {
|
||||
try {
|
||||
return decoder.toDate(expires);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
logger.trace("Expires header (%s) is not in the expected %s format", expires, decoder);
|
||||
// Continue trying the other decoders
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("Invalid Expires header (%s); should be in RFC-1123 format; treating as already expired", expires);
|
||||
return new Date(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ public class DateServiceDateCodecFactoryTest {
|
|||
private DateCodec rfc1123Codec;
|
||||
private DateCodec iso8601Codec;
|
||||
private DateCodec iso8601SecondsCodec;
|
||||
private DateCodec asctimeCodec;
|
||||
|
||||
@BeforeTest
|
||||
public void setUp() {
|
||||
|
@ -41,6 +42,7 @@ public class DateServiceDateCodecFactoryTest {
|
|||
rfc1123Codec = simpleDateCodecFactory.rfc1123();
|
||||
iso8601Codec = simpleDateCodecFactory.iso8601();
|
||||
iso8601SecondsCodec = simpleDateCodecFactory.iso8601Seconds();
|
||||
asctimeCodec = simpleDateCodecFactory.asctime();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -110,4 +112,21 @@ public class DateServiceDateCodecFactoryTest {
|
|||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCodecForAsctime() {
|
||||
Date date = new Date(1000);
|
||||
assertEquals(asctimeCodec.toDate(asctimeCodec.toString(date)), date);
|
||||
|
||||
assertEquals(asctimeCodec.toDate("Thu Dec 01 16:00:00 GMT 1994"), new Date(786297600000L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCodecForAsctimeThrowsParseExceptionWhenMalformed() {
|
||||
try {
|
||||
asctimeCodec.toDate("-");
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
* (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jclouds.io;
|
||||
|
||||
import static org.testng.Assert.assertEquals;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.jclouds.date.internal.DateServiceDateCodecFactory;
|
||||
import org.jclouds.date.internal.SimpleDateFormatDateService;
|
||||
import org.jclouds.io.ContentMetadataCodec.DefaultContentMetadataCodec;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
@Test(groups = "unit", testName = "DefaultContentMetadataCodecTest")
|
||||
public class DefaultContentMetadataCodecTest {
|
||||
|
||||
private final DateServiceDateCodecFactory codecfactory = new DateServiceDateCodecFactory(
|
||||
new SimpleDateFormatDateService());
|
||||
|
||||
public void testCanParseRFC1123Dates() {
|
||||
DefaultContentMetadataCodec codec = new DefaultContentMetadataCodec(codecfactory);
|
||||
Date parsed = codec.parseExpires("Thu, 01 Dec 1994 16:00:00 GMT");
|
||||
assertEquals(parsed, new Date(786297600000L));
|
||||
}
|
||||
|
||||
public void testCanParseAsctimeDates() {
|
||||
DefaultContentMetadataCodec codec = new DefaultContentMetadataCodec(codecfactory);
|
||||
Date parsed = codec.parseExpires("Thu Dec 01 16:00:00 GMT 1994");
|
||||
assertEquals(parsed, new Date(786297600000L));
|
||||
}
|
||||
|
||||
public void testFallbackToExpiredDate() {
|
||||
DefaultContentMetadataCodec codec = new DefaultContentMetadataCodec(codecfactory);
|
||||
Date parsed = codec.parseExpires("1994-12-01T16:00:00.000Z");
|
||||
assertEquals(parsed, new Date(0));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue