/* * Copyright 2016 LINE Corporation * * LINE Corporation 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. */ /* * Copyright 2014 The Netty Project * * The Netty Project 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 com.linecorp.armeria.common.http; import static java.util.Objects.requireNonNull; import java.time.Instant; import java.time.Year; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeFormatterBuilder; import java.time.temporal.ChronoField; import java.util.Locale; /** * Parses and formats 3 date-and-time representations. * * <p><ul> * <li>Sun, 06 Nov 1994 08:49:37 GMT: standard specification, the only one with valid generation</li> * <li>Sun, 06 Nov 1994 08:49:37 GMT: obsolete specification</li> * <li>Sun Nov 6 08:49:37 1994: obsolete specification</li> * </ul> */ final class HeaderDateTimeFormat { private static final ZoneId GMT = ZoneId.of("GMT"); /** * Standard date format. * * <p><pre> * Sun, 06 Nov 1994 08:49:37 GMT -> E, d MMM yyyy HH:mm:ss z * </pre> */ private static final DateTimeFormatter format1 = newFormat("E, dd MMM yyyy HH:mm:ss z"); /** * First obsolete format. * * <p><pre> * Sunday, 06-Nov-94 08:49:37 GMT -> E, d-MMM-y HH:mm:ss z * </pre> */ private static final DateTimeFormatter format2 = newFormat("E, dd-MMM-yy HH:mm:ss z"); /** * A variant of the first obsolete format, which handles 20th century years such as 1994. * * @see <a href="http://stackoverflow.com/a/29496149">http://stackoverflow.com/a/29496149</a> */ private static final DateTimeFormatter format2a = new DateTimeFormatterBuilder().parseLenient() .parseCaseInsensitive() .appendPattern("E, dd-MMM-") .appendValueReduced( ChronoField.YEAR, 2, 2, Year.now().getValue() - 80) .appendPattern(" HH:mm:ss z") .toFormatter(Locale.ENGLISH).withZone(GMT); /** * Second obsolete format. * * <p><pre> * Sun Nov 6 08:49:37 1994 -> EEE, MMM d HH:mm:ss yyyy * </pre> */ private static final DateTimeFormatter format3 = newFormat("E MMM d HH:mm:ss yyyy"); private static DateTimeFormatter newFormat(String pattern) { return new DateTimeFormatterBuilder().parseLenient() .parseCaseInsensitive() .appendPattern(pattern) .toFormatter(Locale.ENGLISH).withZone(GMT); } static Instant parse(String text) { requireNonNull(text); try { return parse(format1, text); } catch (Exception e1) { // Try the second preferred format. try { return parse(format2, text); } catch (Exception e2) { // Try the variant of the second preferred format. try { return parse(format2a, text); } catch (Exception e2a) { // Try the third preferred format. try { return parse(format3, text); } catch (Exception e3) { // None worked. throw new IllegalArgumentException("not a date: " + text); } } } } } private static Instant parse(DateTimeFormatter formatter, String text) { return formatter.parse(text, Instant::from); } static String format(long timeMillis) { return format1.format(Instant.ofEpochMilli(timeMillis)); } private HeaderDateTimeFormat() {} }