]> git.ipfire.org Git - thirdparty/starlette.git/commitdiff
Allow Session scoped cookies. (#1387)
authorAlex Oleshkevich <alex.oleshkevich@gmail.com>
Wed, 12 Jan 2022 09:57:47 +0000 (12:57 +0300)
committerGitHub <noreply@github.com>
Wed, 12 Jan 2022 09:57:47 +0000 (10:57 +0100)
* Allow Session scoped cookies.

* Update docs/middleware.md

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
* Improve typing.

Co-authored-by: Marcelo Trylesinski <marcelotryle@gmail.com>
docs/middleware.md
starlette/middleware/sessions.py
tests/middleware/test_session.py

index 6d4d1a611ebe3064ac3bc828eaa58352d0d2645c..5fe7ce516e3dfae3fc153bb0a0bcb4da5d66e36d 100644 (file)
@@ -98,7 +98,7 @@ The following arguments are supported:
 
 * `secret_key` - Should be a random string.
 * `session_cookie` - Defaults to "session".
-* `max_age` - Session expiry time in seconds. Defaults to 2 weeks.
+* `max_age` - Session expiry time in seconds. Defaults to 2 weeks. If set to `None` then the cookie will last as long as the browser session.
 * `same_site` - SameSite flag prevents the browser from sending session cookie along with cross-site requests. Defaults to `'lax'`.
 * `https_only` - Indicate that Secure flag should be set (can be used with HTTPS only). Defaults to `False`.
 
index ad7a6ee8995826b827f2fe00cd1dc664d961fafa..3ff1e3de12fc3b9c27c10a188c3efd8a55c5c4c5 100644 (file)
@@ -16,7 +16,7 @@ class SessionMiddleware:
         app: ASGIApp,
         secret_key: typing.Union[str, Secret],
         session_cookie: str = "session",
-        max_age: int = 14 * 24 * 60 * 60,  # 14 days, in seconds
+        max_age: typing.Optional[int] = 14 * 24 * 60 * 60,  # 14 days, in seconds
         same_site: str = "lax",
         https_only: bool = False,
     ) -> None:
@@ -55,12 +55,12 @@ class SessionMiddleware:
                     data = b64encode(json.dumps(scope["session"]).encode("utf-8"))
                     data = self.signer.sign(data)
                     headers = MutableHeaders(scope=message)
-                    header_value = "%s=%s; path=%s; Max-Age=%d; %s" % (
-                        self.session_cookie,
-                        data.decode("utf-8"),
-                        path,
-                        self.max_age,
-                        self.security_flags,
+                    header_value = "{session_cookie}={data}; path={path}; {max_age}{security_flags}".format(  # noqa E501
+                        session_cookie=self.session_cookie,
+                        data=data.decode("utf-8"),
+                        path=path,
+                        max_age=f"Max-Age={self.max_age}; " if self.max_age else "",
+                        security_flags=self.security_flags,
                     )
                     headers.append("Set-Cookie", header_value)
                 elif not initial_session_was_empty:
index 07296bcbb549e973c578f20b7a85cbb992bddb20..867a967359a197dcfb45c7084fc6088424b3aca2 100644 (file)
@@ -129,3 +129,20 @@ def test_invalid_session_cookie(test_client_factory):
     # we expect it to not raise an exception if we provide a bogus session cookie
     response = client.get("/view_session", cookies={"session": "invalid"})
     assert response.json() == {"session": {}}
+
+
+def test_session_cookie(test_client_factory):
+    app = create_app()
+    app.add_middleware(SessionMiddleware, secret_key="example", max_age=None)
+    client = test_client_factory(app)
+
+    response = client.post("/update_session", json={"some": "data"})
+    assert response.json() == {"session": {"some": "data"}}
+
+    # check cookie max-age
+    set_cookie = response.headers["set-cookie"]
+    assert "Max-Age" not in set_cookie
+
+    client.cookies.clear_session_cookies()
+    response = client.get("/view_session")
+    assert response.json() == {"session": {}}