aboutsummaryrefslogtreecommitdiffstats
path: root/lib/parsedate.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/parsedate.c')
-rw-r--r--lib/parsedate.c110
1 files changed, 89 insertions, 21 deletions
diff --git a/lib/parsedate.c b/lib/parsedate.c
index 5d8af269..3e168f5a 100644
--- a/lib/parsedate.c
+++ b/lib/parsedate.c
@@ -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
@@ -72,17 +72,16 @@
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>
#include "rawstr.h"
+#include "warnless.h"
#include "parsedate.h"
const char * const Curl_wkday[] =
@@ -99,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 */
@@ -159,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 */
@@ -281,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;
}
@@ -300,7 +318,7 @@ static time_t my_timegm(struct my_tm *tm)
}
/*
- * Curl_parsedate()
+ * parsedate()
*
* Returns:
*
@@ -310,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) */
@@ -335,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);
@@ -378,7 +398,26 @@ int Curl_parsedate(const char *date, time_t *output)
secnum = 0;
}
else {
- val = (int)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) &&
@@ -386,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
@@ -465,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;
@@ -487,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;
}
@@ -500,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) {
@@ -513,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;
+}