cURL / Mailing Lists / curl-library / Single Mail

curl-library

Re: 7.18.2: Possible bug in converting a cookie's expires attribute to unix timestamp ?

From: Jamie Lokier <jamie_at_shareable.org>
Date: Mon, 8 Sep 2008 09:44:11 +0100

Daniel Stenberg wrote:
> >libCurl 7.18.2 was used. I set a cookie with an expiration date <= Thu,
> >01-Jan-1970 00:59:59 GMT. That is converted to -1 (should be 3599, or ?).
>
> It is only 3599 if you're in the GMT time zone.
>
> I assume you're in CEST land (time zone wise)? Then it isn't. We could of
> course argue how we can fix the -1 from not happening when you're close to
> the border of what mktime() can fix - the reason this fails is that the
> code adds the specific time using your local timezone and then it
> compensates for the time zone in the data. Thus, it tries to get
> 01-Jan-1970 00:59:59 CEST first, which occurred _before_ time_t 0.

A related class of bugs comes from converting a string, which is in
GMT, "as if" it were a localtime using `mktime' except that `tm_isdst'
is forced zero, then the output of that to global time using `gmtime',
then the output of that interpreted as a local time again through
`mktime', finally adjusting for tzoffset (which is the only sane bit
:-). I have read there are some borderline cases on some systems,
where times around the daylight-savings transitions don't pass
properly through this baroque pipeline.

Some platforms have a `timegm' function to convert `struct tm' to
`time_t' yet their implementation does similar baroque things, and
occasionally suffers the same borderline cases.

It seems better, faster, simpler and less likely to trip over
environment and platform issues to just convert the `struct tm'
directly to a `time_t' in GMT using a simple algorithm.

And it is a very simple algorithm. Here's one I prepared earlier,
you're welcome to adapt it, though it's not much tested and it was
written in a rush. (Just used it to parse some log files.)
It should handle the case which provoked this thread :-)

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;

  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;
}

Enjoy,
-- Jamie
Received on 2008-09-08