Imported Upstream version 7.59.0
[platform/upstream/curl.git] / lib / parsedate.c
index 3c783be..aa27303 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -75,9 +75,7 @@
 
 #include "curl_setup.h"
 
-#ifdef HAVE_LIMITS_H
 #include <limits.h>
-#endif
 
 #include <curl/curl.h>
 #include "strcase.h"
@@ -167,20 +165,20 @@ static const struct tzinfo tz[]= {
      RFC 1123) had their signs wrong. Here we use the correct signs to match
      actual military usage.
    */
-  {"A",  +1 * 60},         /* Alpha */
-  {"B",  +2 * 60},         /* Bravo */
-  {"C",  +3 * 60},         /* Charlie */
-  {"D",  +4 * 60},         /* Delta */
-  {"E",  +5 * 60},         /* Echo */
-  {"F",  +6 * 60},         /* Foxtrot */
-  {"G",  +7 * 60},         /* Golf */
-  {"H",  +8 * 60},         /* Hotel */
-  {"I",  +9 * 60},         /* India */
+  {"A",  1 * 60},         /* Alpha */
+  {"B",  2 * 60},         /* Bravo */
+  {"C",  3 * 60},         /* Charlie */
+  {"D",  4 * 60},         /* Delta */
+  {"E",  5 * 60},         /* Echo */
+  {"F",  6 * 60},         /* Foxtrot */
+  {"G",  7 * 60},         /* Golf */
+  {"H",  8 * 60},         /* Hotel */
+  {"I",  9 * 60},         /* India */
   /* "J", Juliet is not used as a timezone, to indicate the observer's local
      time */
-  {"K", +10 * 60},         /* Kilo */
-  {"L", +11 * 60},         /* Lima */
-  {"M", +12 * 60},         /* Mike */
+  {"K", 10 * 60},         /* Kilo */
+  {"L", 11 * 60},         /* Lima */
+  {"M", 12 * 60},         /* Mike */
   {"N",  -1 * 60},         /* November */
   {"O",  -2 * 60},         /* Oscar */
   {"P",  -3 * 60},         /* Papa */
@@ -205,14 +203,14 @@ static int checkday(const char *check, size_t len)
 {
   int i;
   const char * const *what;
-  bool found= FALSE;
+  bool found = FALSE;
   if(len > 3)
     what = &weekday[0];
   else
     what = &Curl_wkday[0];
-  for(i=0; i<7; i++) {
+  for(i = 0; i<7; i++) {
     if(strcasecompare(check, what[0])) {
-      found=TRUE;
+      found = TRUE;
       break;
     }
     what++;
@@ -224,12 +222,12 @@ static int checkmonth(const char *check)
 {
   int i;
   const char * const *what;
-  bool found= FALSE;
+  bool found = FALSE;
 
   what = &Curl_month[0];
-  for(i=0; i<12; i++) {
+  for(i = 0; i<12; i++) {
     if(strcasecompare(check, what[0])) {
-      found=TRUE;
+      found = TRUE;
       break;
     }
     what++;
@@ -244,12 +242,12 @@ static int checktz(const char *check)
 {
   unsigned int i;
   const struct tzinfo *what;
-  bool found= FALSE;
+  bool found = FALSE;
 
   what = tz;
-  for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) {
+  for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
     if(strcasecompare(check, what->name)) {
-      found=TRUE;
+      found = TRUE;
       break;
     }
     what++;
@@ -278,26 +276,23 @@ struct my_tm {
   int tm_hour;
   int tm_mday;
   int tm_mon;
-  int tm_year;
+  int tm_year; /* full year */
 };
 
 /* struct tm to time since epoch in GMT time zone.
  * This is similar to the standard mktime function but for GMT only, and
  * doesn't suffer from the various bugs and portability problems that
  * some systems' implementations have.
+ *
+ * Returns 0 on success, otherwise non-zero.
  */
-static time_t my_timegm(struct my_tm *tm)
+static void my_timegm(struct my_tm *tm, time_t *t)
 {
   static const int month_days_cumulative [12] =
     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
   int month, year, leap_days;
 
-  if(tm->tm_year < 70)
-    /* we don't support years before 1970 as they will cause this function
-       to return a negative value */
-    return -1;
-
-  year = tm->tm_year + 1900;
+  year = tm->tm_year;
   month = tm->tm_mon;
   if(month < 0) {
     year += (11 - month) / 12;
@@ -312,9 +307,9 @@ static time_t my_timegm(struct my_tm *tm)
   leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
                - (1969 / 4) + (1969 / 100) - (1969 / 400));
 
-  return ((((time_t) (year - 1970) * 365
-            + leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24
-           + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
+  *t = ((((time_t) (year - 1970) * 365
+          + leap_days + month_days_cumulative[month] + tm->tm_mday - 1) * 24
+         + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
 }
 
 /*
@@ -331,21 +326,21 @@ static time_t my_timegm(struct my_tm *tm)
 static int parsedate(const char *date, time_t *output)
 {
   time_t t = 0;
-  int wdaynum=-1;  /* day of the week number, 0-6 (mon-sun) */
-  int monnum=-1;   /* month of the year number, 0-11 */
-  int mdaynum=-1; /* day of month, 1 - 31 */
-  int hournum=-1;
-  int minnum=-1;
-  int secnum=-1;
-  int yearnum=-1;
-  int tzoff=-1;
+  int wdaynum = -1;  /* day of the week number, 0-6 (mon-sun) */
+  int monnum = -1;   /* month of the year number, 0-11 */
+  int mdaynum = -1; /* day of month, 1 - 31 */
+  int hournum = -1;
+  int minnum = -1;
+  int secnum = -1;
+  int yearnum = -1;
+  int tzoff = -1;
   struct my_tm tm;
   enum assume dignext = DATE_MDAY;
   const char *indate = date; /* save the original pointer */
   int part = 0; /* max 6 parts */
 
   while(*date && (part < 6)) {
-    bool found=FALSE;
+    bool found = FALSE;
 
     skip(&date);
 
@@ -386,7 +381,7 @@ static int parsedate(const char *date, time_t *output)
       /* a digit */
       int val;
       char *end;
-      int len=0;
+      int len = 0;
       if((secnum == -1) &&
          (3 == sscanf(date, "%02d:%02d:%02d%n",
                       &hournum, &minnum, &secnum, &len))) {
@@ -404,12 +399,12 @@ static int parsedate(const char *date, time_t *output)
         int error;
         int old_errno;
 
-        old_errno = ERRNO;
-        SET_ERRNO(0);
+        old_errno = errno;
+        errno = 0;
         lval = strtol(date, &end, 10);
-        error = ERRNO;
-        if(error != old_errno)
-          SET_ERRNO(old_errno);
+        error = errno;
+        if(errno != old_errno)
+          errno = old_errno;
 
         if(error)
           return PARSEDATE_FAIL;
@@ -438,7 +433,7 @@ static int parsedate(const char *date, time_t *output)
           tzoff = (val/100 * 60 + val%100)*60;
 
           /* the + and - prefix indicates the local time compared to GMT,
-             this we need ther reversed math to get what we want */
+             this we need their reversed math to get what we want */
           tzoff = date[-1]=='+'?-tzoff:tzoff;
         }
 
@@ -464,7 +459,7 @@ static int parsedate(const char *date, time_t *output)
         if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
           yearnum = val;
           found = TRUE;
-          if(yearnum < 1900) {
+          if(yearnum < 100) {
             if(yearnum > 70)
               yearnum += 1900;
             else
@@ -493,18 +488,39 @@ static int parsedate(const char *date, time_t *output)
     /* lacks vital info, fail */
     return PARSEDATE_FAIL;
 
-#if SIZEOF_TIME_T < 5
-  /* 32 bit time_t can only hold dates to the beginning of 2038 */
-  if(yearnum > 2037) {
-    *output = 0x7fffffff;
-    return PARSEDATE_LATER;
+#ifdef HAVE_TIME_T_UNSIGNED
+  if(yearnum < 1970) {
+    /* only positive numbers cannot return earlier */
+    *output = TIME_T_MIN;
+    return PARSEDATE_SOONER;
   }
 #endif
 
-  if(yearnum < 1970) {
-    *output = 0;
+#if (SIZEOF_TIME_T < 5)
+
+#ifdef HAVE_TIME_T_UNSIGNED
+  /* an unsigned 32 bit time_t can only hold dates to 2106 */
+  if(yearnum > 2105) {
+    *output = TIME_T_MAX;
+    return PARSEDATE_LATER;
+  }
+#else
+  /* a signed 32 bit time_t can only hold dates to the beginning of 2038 */
+  if(yearnum > 2037) {
+    *output = TIME_T_MAX;
+    return PARSEDATE_LATER;
+  }
+  if(yearnum < 1903) {
+    *output = TIME_T_MIN;
     return PARSEDATE_SOONER;
   }
+#endif
+
+#else
+  /* The Gregorian calendar was introduced 1582 */
+  if(yearnum < 1583)
+    return PARSEDATE_FAIL;
+#endif
 
   if((mdaynum > 31) || (monnum > 11) ||
      (hournum > 23) || (minnum > 59) || (secnum > 60))
@@ -515,31 +531,25 @@ static int parsedate(const char *date, time_t *output)
   tm.tm_hour = hournum;
   tm.tm_mday = mdaynum;
   tm.tm_mon = monnum;
-  tm.tm_year = yearnum - 1900;
-
-  /* my_timegm() returns a time_t. time_t is often 32 bits, even on many
-     architectures that feature 64 bit 'long'.
+  tm.tm_year = yearnum;
 
-     Some systems have 64 bit time_t and deal with years beyond 2038. However,
-     even on some of the systems with 64 bit time_t mktime() returns -1 for
-     dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
+  /* my_timegm() returns a time_t. time_t is often 32 bits, sometimes even on
+     architectures that feature 64 bit 'long' but ultimately time_t is the
+     correct data type to use.
   */
-  t = my_timegm(&tm);
-
-  /* time zone adjust (cast t to int to compare to negative one) */
-  if(-1 != (int)t) {
+  my_timegm(&tm, &t);
 
-    /* Add the time zone diff between local time zone and GMT. */
-    long delta = (long)(tzoff!=-1?tzoff:0);
+  /* Add the time zone diff between local time zone and GMT. */
+  if(tzoff == -1)
+    tzoff = 0;
 
-    if((delta>0) && (t > LONG_MAX - delta)) {
-      *output = 0x7fffffff;
-      return PARSEDATE_LATER; /* time_t overflow */
-    }
-
-    t += delta;
+  if((tzoff > 0) && (t > TIME_T_MAX - tzoff)) {
+    *output = TIME_T_MAX;
+    return PARSEDATE_LATER; /* time_t overflow */
   }
 
+  t += tzoff;
+
   *output = t;
 
   return PARSEDATE_OK;
@@ -551,10 +561,10 @@ time_t curl_getdate(const char *p, const time_t *now)
   int rc = parsedate(p, &parsed);
   (void)now; /* legacy argument from the past that we ignore */
 
-  switch(rc) {
-  case PARSEDATE_OK:
-  case PARSEDATE_LATER:
-  case PARSEDATE_SOONER:
+  if(rc == PARSEDATE_OK) {
+    if(parsed == -1)
+      /* avoid returning -1 for a working scenario */
+      parsed++;
     return parsed;
   }
   /* everything else is fail */