From 2b79de37e864b447d7bca8f13db9435bb0df5ee3 Mon Sep 17 00:00:00 2001 From: wessels <> Date: Wed, 8 Nov 2000 06:37:35 +0000 Subject: [PATCH] DW: - Changes prompted by bug report that "Wed Aug 9 11:36:06 2000" could not be parsed. The parse_rfc1123() code assumed there was an extra space after Aug and before "9". This change breaks the parsing into smaller functions to make the code easier to read and understand. I changed parsing of the "third" date format (asctime()) to use a buffer copy and strtok. This makes it more flexible. For example, we don't have to require strlen(s) < 24. --- lib/rfc1123.c | 198 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 134 insertions(+), 64 deletions(-) diff --git a/lib/rfc1123.c b/lib/rfc1123.c index f63eb6bbb1..f43c25dee6 100644 --- a/lib/rfc1123.c +++ b/lib/rfc1123.c @@ -1,6 +1,6 @@ /* - * $Id: rfc1123.c,v 1.25 2000/10/20 23:50:59 hno Exp $ + * $Id: rfc1123.c,v 1.26 2000/11/07 23:37:35 wessels Exp $ * * DEBUG: * AUTHOR: Harvest Derived @@ -61,6 +61,7 @@ #if HAVE_SYS_TIME_H #include #endif +#include "assert.h" #include "util.h" #include "snprintf.h" @@ -68,6 +69,8 @@ #define RFC850_STRFTIME "%A, %d-%b-%y %H:%M:%S GMT" #define RFC1123_STRFTIME "%a, %d %b %Y %H:%M:%S GMT" +static const char *const w_space = " \t\r\n"; + static int make_month(const char *s); static int make_num(const char *s); @@ -103,85 +106,152 @@ make_month(const char *s) return 0; } +static int +tmSaneValues(struct tm *tm) +{ + if (tm->tm_sec < 0 || tm->tm_sec > 59) + return 0; + if (tm->tm_min < 0 || tm->tm_min > 59) + return 0; + if (tm->tm_hour < 0 || tm->tm_hour > 23) + return 0; + if (tm->tm_mday < 1 || tm->tm_mday > 31) + return 0; + if (tm->tm_mon < 0 || tm->tm_mon > 11) + return 0; + if (tm->tm_year < 70 || tm->tm_year > 120) + return 0; + return 1; +} -time_t -parse_rfc1123(const char *str) +static struct tm * +parse_date1(const char *str) { + /* Thursday, 10-Jun-93 01:29:59 GMT */ + const char *s; + static struct tm tm; + assert(NULL != str); + memset(&tm, '\0', sizeof(struct tm)); + s = strchr(str, ','); + if (NULL == s) + return NULL; + while (*s == ' ') + s++; + /* backup if month is only one digit */ + if (xisdigit(*s) && !xisdigit(*(s + 1))) + s--; + if (!strchr(s, '-')) + return NULL; + if ((int) strlen(s) < 18) + return NULL; + memset(&tm, '\0', sizeof(tm)); + tm.tm_mday = make_num(s); + tm.tm_mon = make_month(s + 3); + tm.tm_year = make_num(s + 7); + /* + * Y2K: Arjan de Vet + * if tm.tm_year < 70, assume it's after the year 2000. + */ + if (tm.tm_year < 70) + tm.tm_year += 100; + tm.tm_hour = make_num(s + 10); + tm.tm_min = make_num(s + 13); + tm.tm_sec = make_num(s + 16); + return tmSaneValues(&tm) ? &tm : NULL; +} + +static struct tm * +parse_date2(const char *str) +{ + /* Thu, 10 Jan 1993 01:29:59 GMT */ const char *s; struct tm tm; - time_t t; + assert(NULL != str); + memset(&tm, '\0', sizeof(struct tm)); + s = strchr(str, ','); + if (NULL == s) + return NULL; + while (*s == ' ') + s++; + /* backup if month is only one digit */ + if (xisdigit(*s) && !xisdigit(*(s + 1))) + s--; + if (strchr(s, '-')) + return NULL; + if ((int) strlen(s) < 20) + return NULL; + memset(&tm, '\0', sizeof(tm)); + tm.tm_mday = make_num(s); + tm.tm_mon = make_month(s + 3); + tm.tm_year = (100 * make_num(s + 7) - 1900) + make_num(s + 9); + tm.tm_hour = make_num(s + 12); + tm.tm_min = make_num(s + 15); + tm.tm_sec = make_num(s + 18); + return tmSaneValues(&tm) ? &tm : NULL; +} - if (!str) - return -1; +static struct tm * +parse_date3(const char *str) +{ + /* Wed Jun 9 01:29:59 1993 GMT */ + static struct tm tm; + char *s; + static char buf[128]; + while (*str && *str == ' ') + str++; + xstrncpy(buf, str, 128); + if (NULL == (s = strtok(buf, w_space))) + return NULL; + if (NULL == (s = strtok(NULL, w_space))) + return NULL; + tm.tm_mon = make_month(s); + if (NULL == (s = strtok(NULL, w_space))) + return NULL; + tm.tm_mday = atoi(s); + if (NULL == (s = strtok(NULL, ":"))) + return NULL; + tm.tm_hour = atoi(s); + if (NULL == (s = strtok(NULL, ":"))) + return NULL; + tm.tm_min = atoi(s); + if (NULL == (s = strtok(NULL, w_space))) + return NULL; + tm.tm_sec = atoi(s); + if (NULL == (s = strtok(NULL, w_space))) + return NULL; + /* Y2K fix, richard.kettlewell@kewill.com */ + tm.tm_year = atoi(s) - 1900; + return tmSaneValues(&tm) ? &tm : NULL; +} - memset(&tm, '\0', sizeof(struct tm)); - if ((s = strchr(str, ','))) { /* Thursday, 10-Jun-93 01:29:59 GMT */ - s++; /* or: Thu, 10 Jan 1993 01:29:59 GMT */ - while (*s == ' ') - s++; - if (xisdigit(*s) && !xisdigit(*(s + 1))) /* backoff if only one digit */ - s--; - if (strchr(s, '-')) { /* First format */ - if ((int) strlen(s) < 18) - return -1; - tm.tm_mday = make_num(s); - tm.tm_mon = make_month(s + 3); - tm.tm_year = make_num(s + 7); - /* - * Y2K: Arjan de Vet - * if tm.tm_year < 70, assume it's after the year 2000. - */ - if (tm.tm_year < 70) - tm.tm_year += 100; - tm.tm_hour = make_num(s + 10); - tm.tm_min = make_num(s + 13); - tm.tm_sec = make_num(s + 16); - } else { /* Second format */ - if ((int) strlen(s) < 20) +time_t +parse_rfc1123(const char *str) +{ + struct tm *tm; + time_t t; + if (NULL == str) + return -1; + tm = parse_date1(str); + if (NULL == tm) { + tm = parse_date2(str); + if (NULL == tm) { + tm = parse_date3(str); + if (NULL == tm) return -1; - tm.tm_mday = make_num(s); - tm.tm_mon = make_month(s + 3); - tm.tm_year = (100 * make_num(s + 7) - 1900) + make_num(s + 9); - tm.tm_hour = make_num(s + 12); - tm.tm_min = make_num(s + 15); - tm.tm_sec = make_num(s + 18); - } - } else { /* Try the other format: */ - s = str; /* Wed Jun 9 01:29:59 1993 GMT */ - while (*s && *s == ' ') - s++; - if ((int) strlen(s) < 24) - return -1; - tm.tm_mday = make_num(s + 8); - tm.tm_mon = make_month(s + 4); - /* Y2K fix, richard.kettlewell@kewill.com */ - tm.tm_year = atoi(s + 20) - 1900; - tm.tm_hour = make_num(s + 11); - tm.tm_min = make_num(s + 14); - tm.tm_sec = make_num(s + 17); } - if (tm.tm_sec < 0 || tm.tm_sec > 59 || - tm.tm_min < 0 || tm.tm_min > 59 || - tm.tm_hour < 0 || tm.tm_hour > 23 || - tm.tm_mday < 1 || tm.tm_mday > 31 || - tm.tm_mon < 0 || tm.tm_mon > 11 || - tm.tm_year < 70 || tm.tm_year > 120) { - return -1; - } - tm.tm_isdst = -1; - + tm->tm_isdst = -1; #ifdef HAVE_TIMEGM - t = timegm(&tm); + t = timegm(tm); #elif HAVE_TM_GMTOFF - t = mktime(&tm); + t = mktime(tm); { struct tm *local = localtime(&t); t += local->tm_gmtoff; } #else /* some systems do not have tm_gmtoff so we fake it */ - t = mktime(&tm); + t = mktime(tm); { time_t dst = 0; #if defined (_TIMEZONE) @@ -195,7 +265,7 @@ parse_rfc1123(const char *str) * The following assumes a fixed DST offset of 1 hour, * which is probably wrong. */ - if (tm.tm_isdst > 0) + if (tm->tm_isdst > 0) dst = -3600; #if defined ( _timezone) || defined(_SQUID_CYGWIN_) t -= (_timezone + dst); -- 2.47.2