コード例 #1
0
ファイル: util_date.c プロジェクト: wtj/formosa
/*
 * Parses an HTTP date in one of three standard forms:
 *
 *     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
 *
 * and returns the time_t number of seconds since 1 Jan 1970 GMT, or
 * 0 if this would be out of range or if the date is invalid.
 *
 * The restricted HTTP syntax is
 * 
 *     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"
 *
 * However, for the sake of robustness (and Netscapeness), we ignore the
 * weekday and anything after the time field (including the timezone).
 *
 * This routine is intended to be very fast; 10x faster than using sscanf.
 *
 * Originally from Andrew Daviel <*****@*****.**>, 29 Jul 96
 * but many changes since then.
 *
 */
time_t 
parseHTTPdate(const char *date)
{
	struct tm ds;
	int mint, mon;
	const char *monstr, *timstr;
	const int months[12] =
	{
	     ('J' << 16) | ('a' << 8) | 'n', ('F' << 16) | ('e' << 8) | 'b',
	     ('M' << 16) | ('a' << 8) | 'r', ('A' << 16) | ('p' << 8) | 'r',
	     ('M' << 16) | ('a' << 8) | 'y', ('J' << 16) | ('u' << 8) | 'n',
	     ('J' << 16) | ('u' << 8) | 'l', ('A' << 16) | ('u' << 8) | 'g',
	     ('S' << 16) | ('e' << 8) | 'p', ('O' << 16) | ('c' << 8) | 't',
	    ('N' << 16) | ('o' << 8) | 'v', ('D' << 16) | ('e' << 8) | 'c'};

	if (!date)
		return BAD_DATE;

	while (*date && isspace((int) *date))	/* Find first non-whitespace char */
		++date;

	if (*date == '\0')
		return BAD_DATE;

	if ((date = strchr(date, ' ')) == NULL)		/* Find space after weekday */
		return BAD_DATE;

	++date;			/* Now pointing to first char after space, which should be */
	/* start of the actual date information for all 3 formats. */

	if (checkmask(date, "## @$$ #### ##:##:## *"))
	{			/* RFC 1123 format */
		ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
		if (ds.tm_year < 0)
			return BAD_DATE;

		ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0');

		ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');

		monstr = date + 3;
		timstr = date + 12;
	}
	else if (checkmask(date, "##-@$$-## ##:##:## *"))
	{			/* RFC 850 format  */
		ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
		if (ds.tm_year < 70)
			ds.tm_year += 100;

		ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');

		monstr = date + 3;
		timstr = date + 10;
	}
	else if (checkmask(date, "@$$ ~# ##:##:## ####*"))
	{			/* asctime format  */
		ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100;
		if (ds.tm_year < 0)
			return BAD_DATE;

		ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0');

		if (date[4] == ' ')
			ds.tm_mday = 0;
		else
			ds.tm_mday = (date[4] - '0') * 10;

		ds.tm_mday += (date[5] - '0');

		monstr = date;
		timstr = date + 7;
	}
	else
		return BAD_DATE;

	if (ds.tm_mday <= 0 || ds.tm_mday > 31)
		return BAD_DATE;

	ds.tm_hour = ((timstr[0] - '0') * 10) + (timstr[1] - '0');
	ds.tm_min = ((timstr[3] - '0') * 10) + (timstr[4] - '0');
	ds.tm_sec = ((timstr[6] - '0') * 10) + (timstr[7] - '0');

	if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61))
		return BAD_DATE;

	mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2];
	for (mon = 0; mon < 12; mon++)
		if (mint == months[mon])
			break;
	if (mon == 12)
		return BAD_DATE;

	if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10))
		return BAD_DATE;

	/* February gets special check for leapyear */

	if ((mon == 1) && ((ds.tm_mday > 29) ||
			   ((ds.tm_mday == 29) && ((ds.tm_year & 3) ||
	    (((ds.tm_year % 100) == 0) && (((ds.tm_year % 400) != 100)))))))
		return BAD_DATE;

	ds.tm_mon = mon;

	return tm2sec(&ds);
}
コード例 #2
0
ファイル: OsDateTime.cpp プロジェクト: Konnekt/lib-sipx
long OsDateTimeBase::convertHttpDateToEpoch(const char *date)
{
    /*
     * Parses an HTTP date in one of three standard forms:
     *
     *     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
     *
     * and returns the time_t number of seconds since 1 Jan 1970 GMT, or
     * 0 if this would be out of range or if the date is invalid.
     *
     * The restricted HTTP syntax is
     * 
     *     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"
     *
     * However, for the sake of robustness (and Netscapeness), we ignore the
     * weekday and anything after the time field (including the timezone).
     *
     * This routine is intended to be very fast; 10x faster than using sscanf.
     *
     * Originally from Andrew Daviel <*****@*****.**>, 29 Jul 96
     * but many changes since then.
     *
     */
    struct tm ds;
    int mint, mon;
    const char *monstr, *timstr;
    const int months[12] = {
        ('J' << 16) | ( 'a' << 8) | 'n',  ('F' << 16) | ( 'e' << 8) | 'b',
        ('M' << 16) | ( 'a' << 8) | 'r',  ('A' << 16) | ( 'p' << 8) | 'r',
        ('M' << 16) | ( 'a' << 8) | 'y',  ('J' << 16) | ( 'u' << 8) | 'n',
        ('J' << 16) | ( 'u' << 8) | 'l',  ('A' << 16) | ( 'u' << 8) | 'g',
        ('S' << 16) | ( 'e' << 8) | 'p',  ('O' << 16) | ( 'c' << 8) | 't',
        ('N' << 16) | ( 'o' << 8) | 'v',  ('D' << 16) | ( 'e' << 8) | 'c'};

    if (!date)
        return BAD_DATE;

    while (*date && isspace(*date))      /* Find first non-whitespace char */
        ++date;

    if (*date == '\0')
        return BAD_DATE;

    if ((date = strchr(date,' ')) == NULL)   /* Find space after weekday */
        return BAD_DATE;

    ++date;    /* Now pointing to first char after space, which should be */
               /* start of the actual date information for all 3 formats. */
    
    if (checkmask(date, "## @$$ #### ##:##:## *")) {     /* RFC 1123 format */
        ds.tm_year = ((date[7] - '0') * 10 + (date[8] - '0') - 19) * 100;
        if (ds.tm_year < 0)
            return BAD_DATE;

        ds.tm_year += ((date[9] - '0') * 10) + (date[10] - '0');

        ds.tm_mday  = ((date[0] - '0') * 10) + (date[1] - '0');

        monstr = date + 3;
        timstr = date + 12;
    }
    else if (checkmask(date, "##-@$$-## ##:##:## *")) {  /* RFC 850 format  */
        ds.tm_year = ((date[7] - '0') * 10) + (date[8] - '0');
        if (ds.tm_year < 70)
            ds.tm_year += 100;

        ds.tm_mday = ((date[0] - '0') * 10) + (date[1] - '0');

        monstr = date + 3;
        timstr = date + 10;
    }
    else if (checkmask(date, "@$$ ~# ##:##:## ####*")) { /* asctime format  */
        ds.tm_year = ((date[16] - '0') * 10 + (date[17] - '0') - 19) * 100;
        if (ds.tm_year < 0)
            return BAD_DATE;

        ds.tm_year += ((date[18] - '0') * 10) + (date[19] - '0');

        if (date[4] == ' ')
            ds.tm_mday = 0;
        else
            ds.tm_mday = (date[4] - '0') * 10;

        ds.tm_mday += (date[5] - '0');

        monstr = date;
        timstr = date + 7;
    }
    else return BAD_DATE;

    if (ds.tm_mday <= 0 || ds.tm_mday > 31)
        return BAD_DATE;

    ds.tm_hour = ((timstr[0] - '0') * 10) + (timstr[1] - '0');
    ds.tm_min  = ((timstr[3] - '0') * 10) + (timstr[4] - '0');
    ds.tm_sec  = ((timstr[6] - '0') * 10) + (timstr[7] - '0');

    if ((ds.tm_hour > 23) || (ds.tm_min > 59) || (ds.tm_sec > 61))
        return BAD_DATE;

    mint = (monstr[0] << 16) | (monstr[1] << 8) | monstr[2];
    for (mon=0; mon < 12; mon++)
        if (mint == months[mon])
            break;
    if (mon == 12)
        return BAD_DATE;
    
    if ((ds.tm_mday == 31) && (mon == 3 || mon == 5 || mon == 8 || mon == 10))
        return BAD_DATE;

    /* February gets special check for leapyear */

    if ((mon == 1) && ((ds.tm_mday > 29) ||
         ((ds.tm_mday == 29) && ((ds.tm_year & 3) ||
           (((ds.tm_year % 100) == 0) && (((ds.tm_year % 400) != 100)))))))
        return BAD_DATE;

    ds.tm_mon = mon;

    return tm2Epoch(&ds);
}