All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.micronaut.function.aws.proxy.cookie.DateFormatter Maven / Gradle / Ivy

/*
 * Copyright 2016 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:
 *
 *   https://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 io.micronaut.function.aws.proxy.cookie;

import io.micronaut.core.annotation.Internal;

import java.util.BitSet;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Objects;
import java.util.TimeZone;

/**
 * A formatter for HTTP header dates, such as "Expires" and "Date" headers, or "expires" field in "Set-Cookie".
 *
 * On the parsing side, it honors RFC6265 (so it supports RFC1123).
 * Note that:
 * 
    *
  • Day of week is ignored and not validated
  • *
  • Timezone is ignored, as RFC6265 assumes UTC
  • *
* If you're looking for a date format that validates day of week, or supports other timezones, consider using * java.util.DateTimeFormatter.RFC_1123_DATE_TIME. * * On the formatting side, it uses a subset of RFC1123 (2 digit day-of-month and 4 digit year) as per RFC2616. * This subset supports RFC6265. * * @see RFC6265 for the parsing side * @see RFC1123 and * RFC2616 for the encoding side. * * Forked from Netty `io.netty.handler.codec` */ @Internal public final class DateFormatter { private static final BitSet DELIMITERS = new BitSet(); static { DELIMITERS.set(0x09); for (char c = 0x20; c <= 0x2F; c++) { DELIMITERS.set(c); } for (char c = 0x3B; c <= 0x40; c++) { DELIMITERS.set(c); } for (char c = 0x5B; c <= 0x60; c++) { DELIMITERS.set(c); } for (char c = 0x7B; c <= 0x7E; c++) { DELIMITERS.set(c); } } private static final String[] DAY_OF_WEEK_TO_SHORT_NAME = new String[]{"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; private static final String[] CALENDAR_MONTH_TO_SHORT_NAME = new String[]{"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; private static final ThreadLocal INSTANCES = ThreadLocal.withInitial(DateFormatter::new); private final GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("UTC")); private final StringBuffer sb = new StringBuffer(29); // Sun, 27 Nov 2016 19:37:15 GMT private boolean timeFound; private int hours; private int minutes; private int seconds; private boolean dayOfMonthFound; private int dayOfMonth; private boolean monthFound; private int month; private boolean yearFound; private int year; private DateFormatter() { reset(); } /** * Format a {@link Date} into RFC1123 format. * @param date the date to format * @return a RFC1123 string */ public static String format(Date date) { return formatter().format0(Objects.requireNonNull(date)); } /** * Append a {@link Date} to a {@link StringBuffer} into RFC1123 format. * @param date the date to format * @param sb the StringBuilder * @return the same StringBuilder */ public static StringBuffer append(Date date, StringBuffer sb) { return formatter().append0(Objects.requireNonNull(date), Objects.requireNonNull(sb)); } private static DateFormatter formatter() { DateFormatter formatter = INSTANCES.get(); formatter.reset(); return formatter; } // delimiter = %x09 / %x20-2F / %x3B-40 / %x5B-60 / %x7B-7E private static boolean isDelim(char c) { return DELIMITERS.get(c); } private static boolean isDigit(char c) { return c >= 48 && c <= 57; } private static int getNumericalValue(char c) { return c - 48; } public void reset() { timeFound = false; hours = -1; minutes = -1; seconds = -1; dayOfMonthFound = false; dayOfMonth = -1; monthFound = false; month = -1; yearFound = false; year = -1; cal.clear(); sb.setLength(0); } private boolean tryParseTime(CharSequence txt, int tokenStart, int tokenEnd) { int len = tokenEnd - tokenStart; // h:m:s to hh:mm:ss if (len < 5 || len > 8) { return false; } int localHours = -1; int localMinutes = -1; int localSeconds = -1; int currentPartNumber = 0; int currentPartValue = 0; int numDigits = 0; for (int i = tokenStart; i < tokenEnd; i++) { char c = txt.charAt(i); if (isDigit(c)) { currentPartValue = currentPartValue * 10 + getNumericalValue(c); if (++numDigits > 2) { return false; // too many digits in this part } } else if (c == ':') { if (numDigits == 0) { // no digits between separators return false; } switch (currentPartNumber) { case 0: // flushing hours localHours = currentPartValue; break; case 1: // flushing minutes localMinutes = currentPartValue; break; default: // invalid, too many : return false; } currentPartValue = 0; currentPartNumber++; numDigits = 0; } else { // invalid char return false; } } if (numDigits > 0) { // pending seconds localSeconds = currentPartValue; } if (localHours >= 0 && localMinutes >= 0 && localSeconds >= 0) { hours = localHours; minutes = localMinutes; seconds = localSeconds; return true; } return false; } private boolean tryParseDayOfMonth(CharSequence txt, int tokenStart, int tokenEnd) { int len = tokenEnd - tokenStart; if (len == 1) { char c0 = txt.charAt(tokenStart); if (isDigit(c0)) { dayOfMonth = getNumericalValue(c0); return true; } } else if (len == 2) { char c0 = txt.charAt(tokenStart); char c1 = txt.charAt(tokenStart + 1); if (isDigit(c0) && isDigit(c1)) { dayOfMonth = getNumericalValue(c0) * 10 + getNumericalValue(c1); return true; } } return false; } private boolean tryParseYear(CharSequence txt, int tokenStart, int tokenEnd) { int len = tokenEnd - tokenStart; if (len == 2) { char c0 = txt.charAt(tokenStart); char c1 = txt.charAt(tokenStart + 1); if (isDigit(c0) && isDigit(c1)) { year = getNumericalValue(c0) * 10 + getNumericalValue(c1); return true; } } else if (len == 4) { char c0 = txt.charAt(tokenStart); char c1 = txt.charAt(tokenStart + 1); char c2 = txt.charAt(tokenStart + 2); char c3 = txt.charAt(tokenStart + 3); if (isDigit(c0) && isDigit(c1) && isDigit(c2) && isDigit(c3)) { year = getNumericalValue(c0) * 1000 + getNumericalValue(c1) * 100 + getNumericalValue(c2) * 10 + getNumericalValue(c3); return true; } } return false; } private boolean normalizeAndValidate() { if (dayOfMonth < 1 || dayOfMonth > 31 || hours > 23 || minutes > 59 || seconds > 59) { return false; } if (year >= 70 && year <= 99) { year += 1900; } else if (year >= 0 && year < 70) { year += 2000; } else if (year < 1601) { // invalid value return false; } return true; } private Date computeDate() { cal.set(Calendar.DAY_OF_MONTH, dayOfMonth); cal.set(Calendar.MONTH, month); cal.set(Calendar.YEAR, year); cal.set(Calendar.HOUR_OF_DAY, hours); cal.set(Calendar.MINUTE, minutes); cal.set(Calendar.SECOND, seconds); return cal.getTime(); } private String format0(Date date) { append0(date, sb); return sb.toString(); } private StringBuffer append0(Date date, StringBuffer sb) { cal.setTime(date); sb.append(DAY_OF_WEEK_TO_SHORT_NAME[cal.get(Calendar.DAY_OF_WEEK) - 1]).append(", "); appendZeroLeftPadded(cal.get(Calendar.DAY_OF_MONTH), sb).append(' '); sb.append(CALENDAR_MONTH_TO_SHORT_NAME[cal.get(Calendar.MONTH)]).append(' '); sb.append(cal.get(Calendar.YEAR)).append(' '); appendZeroLeftPadded(cal.get(Calendar.HOUR_OF_DAY), sb).append(':'); appendZeroLeftPadded(cal.get(Calendar.MINUTE), sb).append(':'); return appendZeroLeftPadded(cal.get(Calendar.SECOND), sb).append(" GMT"); } private static StringBuffer appendZeroLeftPadded(int value, StringBuffer sb) { if (value < 10) { sb.append('0'); } return sb.append(value); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy