Merge pull request #3207 from takluyver/clearing-cookies

Fix clearing two cookies with the same name
This commit is contained in:
Thomas Kluyver 2018-01-16 14:57:27 +00:00 committed by GitHub
commit 64bde3e888
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -3,6 +3,7 @@
# Copyright (c) Jupyter Development Team.
# Distributed under the terms of the Modified BSD License.
import datetime
import functools
import json
import mimetypes
@ -15,15 +16,17 @@ import warnings
try:
# py3
from http.client import responses
from http.cookies import Morsel
except ImportError:
from httplib import responses
from Cookie import Morsel
try:
from urllib.parse import urlparse # Py 3
except ImportError:
from urlparse import urlparse # Py 2
from jinja2 import TemplateNotFound
from tornado import web, gen, escape
from tornado import web, gen, escape, httputil
from tornado.log import app_log
from notebook._sysinfo import get_sys_info
@ -91,14 +94,41 @@ class AuthenticatedHandler(web.RequestHandler):
# for example, so just ignore)
self.log.debug(e)
def force_clear_cookie(self, name, path="/", domain=None):
"""Deletes the cookie with the given name.
Tornado's cookie handling currently (Jan 2018) stores cookies in a dict
keyed by name, so it can only modify one cookie with a given name per
response. The browser can store multiple cookies with the same name
but different domains and/or paths. This method lets us clear multiple
cookies with the same name.
Due to limitations of the cookie protocol, you must pass the same
path and domain to clear a cookie as were used when that cookie
was set (but there is no way to find out on the server side
which values were used for a given cookie).
"""
name = escape.native_str(name)
expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)
morsel = Morsel()
morsel.set(name, '', '""')
morsel['expires'] = httputil.format_timestamp(expires)
morsel['path'] = path
if domain:
morsel['domain'] = domain
self.add_header("Set-Cookie", morsel.OutputString())
def clear_login_cookie(self):
cookie_options = self.settings.get('cookie_options', {})
path = cookie_options.setdefault('path', self.base_url)
self.clear_cookie(self.cookie_name, path=path)
if path and path != '/':
# also clear cookie on / to ensure old cookies
# are cleared after the change in path behavior.
self.clear_cookie(self.cookie_name)
# also clear cookie on / to ensure old cookies are cleared
# after the change in path behavior (changed in notebook 5.2.2).
# N.B. This bypasses the normal cookie handling, which can't update
# two cookies with the same name. See the method above.
self.force_clear_cookie(self.cookie_name)
def get_current_user(self):
if self.login_handler is None: