This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: cookielib uses time.time(), making incorrect checks of expiration times in cookies
Type: behavior Stage: resolved
Components: Library (Lib) Versions: Python 2.7
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: akira, pitrou, regu0004, terry.reedy
Priority: normal Keywords:

Created on 2014-08-29 10:00 by regu0004, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Files
File name Uploaded Description Edit
cookie_timestamp_test.py regu0004, 2014-08-29 10:00 Example of incorrect expiration check in the cookielib module
cookie_timestamp_test_3.4.py regu0004, 2014-09-01 07:02 Example of incorrect expiration check in the http.cookiejar module in 3.4
Messages (8)
msg226056 - (view) Author: Rebecka (regu0004) Date: 2014-08-29 10:00
The cookielib module uses time.time(), which produces a timestamp in the local timezone (as read from the system time?), as the timestamp against which expiration dates in cookies are compared.

However, typical usage of HTTP cookies would be specifying the expiration date in UTC. This assumption seems to be supported for example by the inclusion of cookielib.http2time, which (only) supports UTC timestamps.

This behaviour is also included in e.g. MozillaCookieJar, which (erroneously) excludes cookies from being saved/loaded based on the local timestamp from time.time().

See the attached file for a small example where the check if a cookie is expired against a UTC time is correct but the check against local time fails (simulating the behaviour of the cookielib module).
msg226097 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2014-08-29 22:53
If you have not, please check if this issue applies to 3.4, and post a 3.4 version of the test file.

In the absence of a standard, I am not sure if this is a bug, and even if we call it such, whether 2.7 should be changed.
msg226213 - (view) Author: Rebecka (regu0004) Date: 2014-09-01 07:02
I've checked and an updated test file for 3.4 shows the same behaviour in the renamed module http.cookiejar.

Even though no standard exists I hope 3.4+ would be changed to simplify the cookie handling, since there is a lot of hassle converting UTC times to local times (which in general should be avoided to avoid introducing further problems with e.g. daylight savings).
msg226222 - (view) Author: Akira Li (akira) * Date: 2014-09-01 09:17
time.time() returns the current time in seconds since Epoch
it is neither local nor UTC time. It can be converted to both.

You can get local time using datetime.fromtimestamp(ts).
You can get UTC time using datetime.utcfromtimestamp(ts) or
to get an aware datetime object: datetime.fromtimestamp(ts, timezone.utc), where ts is the timestamp in seconds since Epoch.

I don't know whether there is an issue with cookie.is_expired() but it
is incorrect to use time.mktime() with UTC time tuple unless the local
time is UTC. To get the timestamp from a datetime object, you could
use .timestamp() method instead:

  from datetime import datetime, timezone

  now = datetime.now(timezone.utc) # the current time
  seconds_since_epoch = now.timestamp()
  seconds_since_epoch = time.time() # might be less precise
msg226225 - (view) Author: Antoine Pitrou (pitrou) * (Python committer) Date: 2014-09-01 12:24
Note the .timestamp() method will work correctly if the datetime object is expressed in *local time*, which is not what Rebecka's code uses. Otherwise the incantation is a bit more complex:

https://docs.python.org/3/library/datetime.html#datetime.datetime.timestamp

(also .timestamp() doesn't exist in 2.7, in which case the manual computation must also be used)
msg226226 - (view) Author: Akira Li (akira) * Date: 2014-09-01 12:36
timestamp() method works correctly for an aware datetime objects
as in my example (notice: timezone.utc in the code).

The issue is not that it is a manual computation,
the issue is that it is incorrect:

  #XXX WRONG, DO NOT DO IT
  time.mktime(datetime.datetime.utcnow().timetuple())

On older Python versions, given a utc time as a naive datetime
object, POSIX timestamp is:

  ts = (utc_dt - datetime(1970, 1, 1)).total_seconds()
  utc_dt = datetime(1970, 1, 1) + timedelta(seconds=ts) # in reverse
msg226227 - (view) Author: Akira Li (akira) * Date: 2014-09-01 12:41
The last example assumes that time.gmtime(0) is 1970-01-01 00:00:00Z
(otherwise time.time() may return different timestamp)
msg226261 - (view) Author: Rebecka (regu0004) Date: 2014-09-02 06:15
Akira is correct: using time.mktime to produce the expiration date for the cookie is wrong (thank you very much for the pointers!).

Using e.g. http.cookiejar.http2time with a HTTP formatted date string gives a correct time stamp (with which cookie.is_expired succeeds), so this was not a bug (just user error...).
History
Date User Action Args
2022-04-11 14:58:07adminsetgithub: 66492
2014-09-02 07:22:16berker.peksagsetstage: needs patch -> resolved
2014-09-02 06:15:27regu0004setstatus: open -> closed
resolution: not a bug
messages: + msg226261
2014-09-01 12:41:26akirasetmessages: + msg226227
2014-09-01 12:36:54akirasetmessages: + msg226226
2014-09-01 12:24:29pitrousetnosy: + pitrou
messages: + msg226225
2014-09-01 09:17:05akirasetnosy: + akira
messages: + msg226222
2014-09-01 07:02:03regu0004setfiles: + cookie_timestamp_test_3.4.py

messages: + msg226213
2014-08-29 22:53:05terry.reedysetnosy: + terry.reedy

messages: + msg226097
stage: needs patch
2014-08-29 10:00:50regu0004create