/*
- * $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
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
+#include "assert.h"
#include "util.h"
#include "snprintf.h"
#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);
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 <Arjan.deVet@adv.IAEhv.nl>
+ * 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 <Arjan.deVet@adv.IAEhv.nl>
- * 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)
* 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);