tizen 2.3.1 release
[external/curl.git] / lib / parsedate.c
index 3e003db..3e168f5 100644 (file)
@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, 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
   20040911 +0200
 
 */
-#include "setup.h"
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
 
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h> /* for strtol() */
+#include "curl_setup.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
 #endif
 
 #include <curl/curl.h>
@@ -100,6 +98,24 @@ struct tzinfo {
   int offset; /* +/- in minutes */
 };
 
+/*
+ * parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK     - a fine conversion
+ * PARSEDATE_FAIL   - failed to convert
+ * PARSEDATE_LATER  - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+static int parsedate(const char *date, time_t *output);
+
+#define PARSEDATE_OK     0
+#define PARSEDATE_FAIL   -1
+#define PARSEDATE_LATER  1
+#define PARSEDATE_SOONER 2
+
 /* Here's a bunch of frequently used time zone names. These were supported
    by the old getdate parser. */
 #define tDAYZONE -60       /* offset for daylight savings time */
@@ -160,7 +176,8 @@ static const struct tzinfo tz[]= {
   {"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 */
+  /* "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 */
@@ -282,11 +299,11 @@ static time_t my_timegm(struct my_tm *tm)
 
   year = tm->tm_year + 1900;
   month = tm->tm_mon;
-  if (month < 0) {
+  if(month < 0) {
     year += (11 - month) / 12;
     month = 11 - (11 - month) % 12;
   }
-  else if (month >= 12) {
+  else if(month >= 12) {
     year -= month / 12;
     month = month % 12;
   }
@@ -301,7 +318,7 @@ static time_t my_timegm(struct my_tm *tm)
 }
 
 /*
- * Curl_parsedate()
+ * parsedate()
  *
  * Returns:
  *
@@ -311,7 +328,7 @@ static time_t my_timegm(struct my_tm *tm)
  * PARSEDATE_SOONER - time underflow at the low end of time_t
  */
 
-int Curl_parsedate(const char *date, time_t *output)
+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) */
@@ -336,9 +353,11 @@ int Curl_parsedate(const char *date, time_t *output)
       /* a name coming up */
       char buf[32]="";
       size_t len;
-      sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]",
-             buf);
-      len = strlen(buf);
+      if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+                          "abcdefghijklmnopqrstuvwxyz]", buf))
+        len = strlen(buf);
+      else
+        len = 0;
 
       if(wdaynum == -1) {
         wdaynum = checkday(buf, len);
@@ -379,7 +398,26 @@ int Curl_parsedate(const char *date, time_t *output)
         secnum = 0;
       }
       else {
-        val = curlx_sltosi(strtol(date, &end, 10));
+        long lval;
+        int error;
+        int old_errno;
+
+        old_errno = ERRNO;
+        SET_ERRNO(0);
+        lval = strtol(date, &end, 10);
+        error = ERRNO;
+        if(error != old_errno)
+          SET_ERRNO(old_errno);
+
+        if(error)
+          return PARSEDATE_FAIL;
+
+#if LONG_MAX != INT_MAX
+        if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
+          return PARSEDATE_FAIL;
+#endif
+
+        val = curlx_sltosi(lval);
 
         if((tzoff == -1) &&
            ((end - date) == 4) &&
@@ -387,7 +425,7 @@ int Curl_parsedate(const char *date, time_t *output)
            (indate< date) &&
            ((date[-1] == '+' || date[-1] == '-'))) {
           /* four digits and a value less than or equal to 1400 (to take into
-             account all sorts of funny time zone diffs) and it is preceeded
+             account all sorts of funny time zone diffs) and it is preceded
              with a plus or minus. This is a time zone indication.  1400 is
              picked since +1300 is frequently used and +1400 is mentioned as
              an edge number in the document "ISO C 200X Proposal: Timezone
@@ -466,6 +504,10 @@ int Curl_parsedate(const char *date, time_t *output)
     return PARSEDATE_SOONER;
   }
 
+  if((mdaynum > 31) || (monnum > 11) ||
+     (hournum > 23) || (minnum > 59) || (secnum > 60))
+    return PARSEDATE_FAIL; /* clearly an illegal date */
+
   tm.tm_sec = secnum;
   tm.tm_min = minnum;
   tm.tm_hour = hournum;
@@ -488,8 +530,10 @@ int Curl_parsedate(const char *date, time_t *output)
     /* Add the time zone diff between local time zone and GMT. */
     long delta = (long)(tzoff!=-1?tzoff:0);
 
-    if((delta>0) && (t + delta < t))
-      return -1; /* time_t overflow */
+    if((delta>0) && (t > LONG_MAX - delta)) {
+      *output = 0x7fffffff;
+      return PARSEDATE_LATER; /* time_t overflow */
+    }
 
     t += delta;
   }
@@ -501,8 +545,8 @@ int Curl_parsedate(const char *date, time_t *output)
 
 time_t curl_getdate(const char *p, const time_t *now)
 {
-  time_t parsed;
-  int rc = Curl_parsedate(p, &parsed);
+  time_t parsed = -1;
+  int rc = parsedate(p, &parsed);
   (void)now; /* legacy argument from the past that we ignore */
 
   switch(rc) {
@@ -514,3 +558,26 @@ time_t curl_getdate(const char *p, const time_t *now)
   /* everything else is fail */
   return -1;
 }
+
+/*
+ * Curl_gmtime() is a gmtime() replacement for portability. Do not use the
+ * gmtime_r() or gmtime() functions anywhere else but here.
+ *
+ */
+
+CURLcode Curl_gmtime(time_t intime, struct tm *store)
+{
+  const struct tm *tm;
+#ifdef HAVE_GMTIME_R
+  /* thread-safe version */
+  tm = (struct tm *)gmtime_r(&intime, store);
+#else
+  tm = gmtime(&intime);
+  if(tm)
+    *store = *tm; /* copy the pointed struct to the local copy */
+#endif
+
+  if(!tm)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  return CURLE_OK;
+}