aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2008-09-23 11:00:01 +0000
committerDaniel Stenberg <daniel@haxx.se>2008-09-23 11:00:01 +0000
commitd369a2b7755d763490575fc18de748def0b3ba77 (patch)
tree7eebd3b352f91fae13a982ac8f30e9a9cceee11e
parenta5f4cfc6126b5e6085d3972a00f37409de65ad11 (diff)
- Introducing Jamie Lokier's function for date to epoch conversion used in the
date parser function. This makes our function less dependent on system- provided functions and instead we do all the magic ourselves. We also no longer depend on the TZ environment variable.
-rw-r--r--CHANGES19
-rw-r--r--RELEASE-NOTES4
-rw-r--r--lib/parsedate.c72
-rw-r--r--tests/data/test5171
4 files changed, 62 insertions, 34 deletions
diff --git a/CHANGES b/CHANGES
index 6bba10a61..9ea9f3b64 100644
--- a/CHANGES
+++ b/CHANGES
@@ -7,6 +7,25 @@
Changelog
Daniel Stenberg (23 Sep 2008)
+- Introducing Jamie Lokier's function for date to epoch conversion used in the
+ date parser function. This makes our function less dependent on system-
+ provided functions and instead we do all the magic ourselves. We also no
+ longer depend on the TZ environment variable. Switching to our own converter
+ has some side-effect and they are noted here for future reference (taken
+ from a mail by mr Lokier):
+
+ time_t is not measured in seconds in the ANSI C standard - or even counted
+ uniformly - weird platforms can use other numeric representations of dates
+ in time_t - hence the difftime() function.
+
+ On POSIX time_t is measured in UTC seconds, which means not including leap
+ seconds. But it's mentioned in a few places that some old POSIX-ish
+ environments include leap seconds in their time_t counts...
+
+ I'm pretty sure [the new implementation is] correct on anything truly POSIX.
+ And it's obviously a lot less dependent on platform quirks and corner cases
+ in many ways than the mktime() version.
+
- Rob Crittenden brought a patch to "add some locking for thread-safety to NSS
implementation".
diff --git a/RELEASE-NOTES b/RELEASE-NOTES
index c9cc9a324..a90bd2e32 100644
--- a/RELEASE-NOTES
+++ b/RELEASE-NOTES
@@ -26,6 +26,7 @@ This release includes the following bugfixes:
o recv() failures cause CURLE_RECV_ERROR
o SFTP over SOCKS crash fixed
o thread-safety issues addressed for NSS-powered libcurls
+ o removed the use of mktime() and gmtime(_r)() in date parsing and conversions
This release includes the following known bugs:
@@ -40,6 +41,7 @@ advice from friends like these:
Keith Mok, Yang Tse, Daniel Fandrich, Guenter Knauf, Dmitriy Sergeyev,
Linus Nielsen Feltzing, Martin Drasar, Stefan Krause, Dmitry Kurochkin,
- Mike Revi, Andres Garcia, Michael Goffioul, Markus Moeller, Rob Crittenden
+ Mike Revi, Andres Garcia, Michael Goffioul, Markus Moeller, Rob Crittenden,
+ Jamie Lokier
Thanks! (and sorry if I forgot to mention someone)
diff --git a/lib/parsedate.c b/lib/parsedate.c
index 64bb2cc41..d1d1fdc82 100644
--- a/lib/parsedate.c
+++ b/lib/parsedate.c
@@ -222,6 +222,38 @@ enum assume {
DATE_TIME
};
+/* struct tm to time since epoch in GMT time zone */
+static time_t my_timegm(struct tm * tm)
+{
+ 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;
+ month = tm->tm_mon;
+ if (month < 0) {
+ year += (11 - month) / 12;
+ month = 11 - (11 - month) % 12;
+ }
+ else if (month >= 12) {
+ year -= month / 12;
+ month = month % 12;
+ }
+
+ leap_days = year - (tm->tm_mon <= 1);
+ 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;
+}
+
static time_t parsedate(const char *date)
{
time_t t = 0;
@@ -247,7 +279,8 @@ static time_t parsedate(const char *date)
/* a name coming up */
char buf[32]="";
size_t len;
- sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]", buf);
+ sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]",
+ buf);
len = strlen(buf);
if(wdaynum == -1) {
@@ -374,45 +407,20 @@ static time_t parsedate(const char *date)
tm.tm_yday = 0;
tm.tm_isdst = 0;
- /* mktime() returns a time_t. time_t is often 32 bits, even on many
+ /* my_timegm() returns a time_t. time_t is often 32 bits, even on many
architectures that feature 64 bit 'long'.
Some systems have 64 bit time_t and deal with years beyond 2038. However,
- even some of the systems with 64 bit time_t returns -1 for dates beyond
- 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
+ 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)
*/
- t = mktime(&tm);
+ t = my_timegm(&tm);
/* time zone adjust (cast t to int to compare to negative one) */
if(-1 != (int)t) {
- struct tm *gmt;
- long delta;
- time_t t2;
-
-#ifdef HAVE_GMTIME_R
- /* thread-safe version */
- struct tm keeptime2;
- gmt = (struct tm *)gmtime_r(&t, &keeptime2);
- if(!gmt)
- return -1; /* illegal date/time */
- t2 = mktime(gmt);
-#else
- /* It seems that at least the MSVC version of mktime() doesn't work
- properly if it gets the 'gmt' pointer passed in (which is a pointer
- returned from gmtime() pointing to static memory), so instead we copy
- the tm struct to a local struct and pass a pointer to that struct as
- input to mktime(). */
- struct tm gmt2;
- gmt = gmtime(&t); /* use gmtime_r() if available */
- if(!gmt)
- return -1; /* illegal date/time */
- gmt2 = *gmt;
- t2 = mktime(&gmt2);
-#endif
- /* Add the time zone diff (between the given timezone and GMT) and the
- diff between the local time zone and GMT. */
- delta = (long)((tzoff!=-1?tzoff:0) + (t - t2));
+ /* 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 */
diff --git a/tests/data/test517 b/tests/data/test517
index cd5ecd14c..b7d2af607 100644
--- a/tests/data/test517
+++ b/tests/data/test517
@@ -21,7 +21,6 @@ curl_getdate() testing
# using one of the 'right' zones that take into account leap seconds
# which causes the cookie expiry times to be different.
<setenv>
-TZ=GMT
</setenv>
<command>
nothing