Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

web: Restore case-insensitivity of set_cookie args #3254

Merged
merged 1 commit into from
Apr 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/releases.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Release notes
.. toctree::
:maxdepth: 2

releases/v6.3.1
releases/v6.3.0
releases/v6.2.0
releases/v6.1.0
Expand Down
12 changes: 12 additions & 0 deletions docs/releases/v6.3.1.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
What's new in Tornado 6.3.1
===========================

Apr 21, 2023
------------

``tornado.web``
~~~~~~~~~~~~~~~

- `.RequestHandler.set_cookie` once again accepts capitalized keyword arguments
for backwards compatibility. This is deprecated and in Tornado 7.0 only lowercase
arguments will be accepted.
13 changes: 13 additions & 0 deletions tornado/test/web_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from tornado.simple_httpclient import SimpleAsyncHTTPClient
from tornado.template import DictLoader
from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test
from tornado.test.util import ignore_deprecation
from tornado.util import ObjectDict, unicode_type
from tornado.web import (
Application,
Expand Down Expand Up @@ -318,6 +319,11 @@ def get(self):
self.set_cookie("c", "1", httponly=True)
self.set_cookie("d", "1", httponly=False)

class SetCookieDeprecatedArgs(RequestHandler):
def get(self):
# Mixed case is supported, but deprecated
self.set_cookie("a", "b", HttpOnly=True, pATH="/foo")

return [
("/set", SetCookieHandler),
("/get", GetCookieHandler),
Expand All @@ -327,6 +333,7 @@ def get(self):
("/set_max_age", SetCookieMaxAgeHandler),
("/set_expires_days", SetCookieExpiresDaysHandler),
("/set_falsy_flags", SetCookieFalsyFlags),
("/set_deprecated", SetCookieDeprecatedArgs),
]

def test_set_cookie(self):
Expand Down Expand Up @@ -413,6 +420,12 @@ def test_set_cookie_false_flags(self):
self.assertEqual(headers[2].lower(), "c=1; httponly; path=/")
self.assertEqual(headers[3].lower(), "d=1; path=/")

def test_set_cookie_deprecated(self):
with ignore_deprecation():
response = self.fetch("/set_deprecated")
header = response.headers.get("Set-Cookie")
self.assertEqual(header, "a=b; HttpOnly; Path=/foo")


class AuthRedirectRequestHandler(RequestHandler):
def initialize(self, login_url):
Expand Down
17 changes: 17 additions & 0 deletions tornado/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ async def main():
import sys
import threading
import time
import warnings
import tornado
import traceback
import types
Expand Down Expand Up @@ -607,6 +608,7 @@ def set_cookie(
httponly: bool = False,
secure: bool = False,
samesite: Optional[str] = None,
**kwargs: Any,
) -> None:
"""Sets an outgoing cookie name/value with the given options.

Expand All @@ -623,6 +625,10 @@ def set_cookie(
to set an expiration time in days from today (if both are set, ``expires``
is used).

.. deprecated:: 6.3
Keyword arguments are currently accepted case-insensitively.
In Tornado 7.0 this will be changed to only accept lowercase
arguments.
"""
# The cookie library only accepts type str, in both python 2 and 3
name = escape.native_str(name)
Expand Down Expand Up @@ -657,6 +663,17 @@ def set_cookie(
morsel["secure"] = True
if samesite:
morsel["samesite"] = samesite
if kwargs:
# The setitem interface is case-insensitive, so continue to support
# kwargs for backwards compatibility until we can remove deprecated
# features.
for k, v in kwargs.items():
morsel[k] = v
warnings.warn(
f"Deprecated arguments to set_cookie: {set(kwargs.keys())} "
"(should be lowercase)",
DeprecationWarning,
)

def clear_cookie(self, name: str, **kwargs: Any) -> None:
"""Deletes the cookie with the given name.
Expand Down