summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hellkamp <marc@gsites.de>2017-07-14 10:02:42 +0200
committerGitHub <noreply@github.com>2017-07-14 10:02:42 +0200
commit160765cce97b43d7110432562a20bf11eace9a47 (patch)
tree72dce649230a3afc04822c6ad047c4eef76cc1f7
parentef5d2f41a109d0e3eb00b7c1786656a1cfb51962 (diff)
parent2d96ee2f40b55d576ae2810bf30b4417c976162b (diff)
downloadbottle-160765cce97b43d7110432562a20bf11eace9a47.tar.gz
Merge pull request #983 from provinzkraut/samesite-cookie
"SameSite" cookie feature (from issue #982)
-rwxr-xr-xbottle.py14
-rwxr-xr-xdocs/tutorial.rst1
2 files changed, 13 insertions, 2 deletions
diff --git a/bottle.py b/bottle.py
index 4b816f6..f0eb9f3 100755
--- a/bottle.py
+++ b/bottle.py
@@ -128,7 +128,7 @@ if py3k:
from urllib.parse import urljoin, SplitResult as UrlSplitResult
from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote
urlunquote = functools.partial(urlunquote, encoding='latin1')
- from http.cookies import SimpleCookie
+ from http.cookies import SimpleCookie, Morsel, CookieError
from collections import MutableMapping as DictMixin
import pickle
from io import BytesIO
@@ -1813,6 +1813,10 @@ class BaseResponse(object):
:param secure: limit the cookie to HTTPS connections (default: off).
:param httponly: prevents client-side javascript to read this cookie
(default: off, requires Python 2.6 or newer).
+ :param same_site: disables third-party use for a cookie.
+ Allowed attributes: `lax` and `strict`.
+ In strict mode the cookie will never be sent.
+ In lax mode the cookie is only sent with a top-level GET request.
If neither `expires` nor `max_age` is set (default), the cookie will
expire at the end of the browser session (as soon as the browser
@@ -1834,7 +1838,10 @@ class BaseResponse(object):
"""
if not self._cookies:
self._cookies = SimpleCookie()
-
+
+ # To add "SameSite" cookie support.
+ Morsel._reserved['same-site'] = 'SameSite'
+
if secret:
if not isinstance(value, basestring):
depr(0, 13, "Pickling of arbitrary objects into cookies is "
@@ -1863,6 +1870,9 @@ class BaseResponse(object):
elif isinstance(value, (int, float)):
value = time.gmtime(value)
value = time.strftime("%a, %d %b %Y %H:%M:%S GMT", value)
+ # check values for SameSite cookie, because it's not natively supported by http.cookies.
+ if key == 'same_site' and value.lower() not in ('lax', 'strict'):
+ raise CookieError("Invalid attribute %r" % (key,))
if key in ('secure', 'httponly') and not value:
continue
self._cookies[name][key.replace('_', '-')] = value
diff --git a/docs/tutorial.rst b/docs/tutorial.rst
index 363c255..326e05d 100755
--- a/docs/tutorial.rst
+++ b/docs/tutorial.rst
@@ -420,6 +420,7 @@ The :meth:`Response.set_cookie` method accepts a number of additional keyword ar
* **path:** Limit the cookie to a given path (default: ``/``)
* **secure:** Limit the cookie to HTTPS connections (default: off).
* **httponly:** Prevent client-side javascript to read this cookie (default: off, requires Python 2.7 or newer).
+* **same_site:** Disables third-party use for a cookie. Allowed attributes: `lax` and `strict`. In strict mode the cookie will never be sent. In lax mode the cookie is only sent with a top-level GET request.
If neither `expires` nor `max_age` is set, the cookie expires at the end of the browser session or as soon as the browser window is closed. There are some other gotchas you should consider when using cookies: