util_date.c revision 3d96ee83babeec32482c9082c9426340cee8c44d
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering/* ====================================================================
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * The Apache Software License, Version 1.1
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Copyright (c) 2000 The Apache Software Foundation. All rights
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Redistribution and use in source and binary forms, with or without
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * modification, are permitted provided that the following conditions
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * 1. Redistributions of source code must retain the above copyright
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * notice, this list of conditions and the following disclaimer.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * 2. Redistributions in binary form must reproduce the above copyright
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * notice, this list of conditions and the following disclaimer in
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * the documentation and/or other materials provided with the
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * distribution.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * 3. The end-user documentation included with the redistribution,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * if any, must include the following acknowledgment:
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * "This product includes software developed by the
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Apache Software Foundation (http://www.apache.org/)."
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Alternately, this acknowledgment may appear in the software itself,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * if and wherever such third-party acknowledgments normally appear.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * 4. The names "Apache" and "Apache Software Foundation" must
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * not be used to endorse or promote products derived from this
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * software without prior written permission. For written
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * permission, please contact apache@apache.org.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * 5. Products derived from this software may not be called "Apache",
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * nor may "Apache" appear in their name, without prior written
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * permission of the Apache Software Foundation.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * SUCH DAMAGE.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * ====================================================================
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * This software consists of voluntary contributions made by many
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * individuals on behalf of the Apache Software Foundation. For more
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * information on the Apache Software Foundation, please see
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Portions of this software are based upon public domain software
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * originally written at the National Center for Supercomputing Applications,
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * University of Illinois, Urbana-Champaign.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * util_date.c: date parsing utility routines
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * These routines are (hopefully) platform independent.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * 27 Oct 1996 Roy Fielding
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Extracted (with many modifications) from mod_proxy.c and
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * tested with over 50,000 randomly chosen valid date strings
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * and several hundred variations of invalid date strings.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Compare a string to a mask
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Mask characters (arbitrary maximum is 256 characters, just in case):
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * @ - uppercase letter
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * $ - lowercase letter
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * & - hex digit
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * ~ - digit or space
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * * - swallow remaining characters
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * <x> - exact match for any other character
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart PoetteringAP_DECLARE(int) ap_checkmask(const char *data, const char *mask)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering for (i = 0; i < 256; i++) {
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return (d == '\0');
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering return 0; /* We only get here if mask is corrupted (exceeds 256) */
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * Parses an HTTP date in one of three standard forms:
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * and returns the time_t number of seconds since 1 Jan 1970 GMT, or
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * 0 if this would be out of range or if the date is invalid.
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * The restricted HTTP syntax is
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * HTTP-date = rfc1123-date | rfc850-date | asctime-date
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * rfc1123-date = wkday "," SP date1 SP time SP "GMT"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * rfc850-date = weekday "," SP date2 SP time SP "GMT"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * asctime-date = wkday SP date3 SP time SP 4DIGIT
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * date1 = 2DIGIT SP month SP 4DIGIT
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * ; day month year (e.g., 02 Jun 1982)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering * date2 = 2DIGIT "-" month "-" 2DIGIT
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * ; day-month-year (e.g., 02-Jun-82)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * date3 = month SP ( 2DIGIT | ( SP 1DIGIT ))
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * ; month day (e.g., Jun 2)
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * time = 2DIGIT ":" 2DIGIT ":" 2DIGIT
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * ; 00:00:00 - 23:59:59
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * wkday = "Mon" | "Tue" | "Wed"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * | "Thu" | "Fri" | "Sat" | "Sun"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * weekday = "Monday" | "Tuesday" | "Wednesday"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * | "Thursday" | "Friday" | "Saturday" | "Sunday"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * month = "Jan" | "Feb" | "Mar" | "Apr"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * | "May" | "Jun" | "Jul" | "Aug"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * | "Sep" | "Oct" | "Nov" | "Dec"
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * However, for the sake of robustness (and Netscapeness), we ignore the
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * weekday and anything after the time field (including the timezone).
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * This routine is intended to be very fast; 10x faster than using sscanf.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * Originally from Andrew Daviel <andrew@vancouver-webpages.com>, 29 Jul 96
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering * but many changes since then.
ee8c45689526ca973407cbb77bce7b96a062c40bLennart PoetteringAP_DECLARE(apr_time_t) ap_parseHTTPdate(const char *date)
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering ('J' << 16) | ('a' << 8) | 'n', ('F' << 16) | ('e' << 8) | 'b',
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering ('M' << 16) | ('a' << 8) | 'r', ('A' << 16) | ('p' << 8) | 'r',
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering ('M' << 16) | ('a' << 8) | 'y', ('J' << 16) | ('u' << 8) | 'n',
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ('J' << 16) | ('u' << 8) | 'l', ('A' << 16) | ('u' << 8) | 'g',
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ('S' << 16) | ('e' << 8) | 'p', ('O' << 16) | ('c' << 8) | 't',
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering ('N' << 16) | ('o' << 8) | 'v', ('D' << 16) | ('e' << 8) | 'c'};
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering while (*date && apr_isspace(*date)) /* Find first non-whitespace char */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering if ((date = strchr(date, ' ')) == NULL) /* Find space after weekday */
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering ++date; /* Now pointing to first char after space, which should be */
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering /* start of the actual date information for all 3 formats. */
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering if (ap_checkmask(date, "## @$$ #### ##:##:## *")) { /* RFC 1123 format */
df3fb561b2df486a495a5f0bcc83168bd1860533Lennart Poettering ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0');
6d0c65ffb4f82e8c6dceb453919b3db54343fc27Lennart Poettering ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (ap_checkmask(date, "##-@$$-## ##:##:## *")) { /* RFC 850 format */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering else if (ap_checkmask(date, "@$$ ~# ##:##:## ####*")) { /* asctime format */
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100;
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0');
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ds.tm_hour = ((timstr[0] - '0') * 10) + (timstr[1] - '0');
ee8c45689526ca973407cbb77bce7b96a062c40bLennart Poettering ds.tm_min = ((timstr[3] - '0') * 10) + (timstr[4] - '0');
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering ds.tm_sec = ((timstr[6] - '0') * 10) + (timstr[7] - '0');
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61))
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2];
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10))
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering /* February gets special check for leapyear */
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering /* ap_mplode_time uses tm_usec and tm_gmtoff fields, but they haven't
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * been set yet.
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * It should be safe to just zero out these values.
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * tm_usec is the number of microseconds into the second. HTTP only
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * cares about second granularity.
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * tm_gmtoff is the number of seconds off of GMT the time is. By
9085f64a6694f2928c79fcce365edb1dca6937d4Lennart Poettering * definition all times going through this function are in GMT, so this