From e7cd68ba58b78309a342fbce68f6ef1edef3e5e5 Mon Sep 17 00:00:00 2001 From: Nina Zakharenko Date: Tue, 23 May 2017 16:07:07 -0700 Subject: [PATCH 1/2] Don't overwrite Vary header when setting for cookie access #2317 --- flask/sessions.py | 15 ++++++++++++++- tests/test_basic.py | 26 ++++++++++++++++++++++---- 2 files changed, 36 insertions(+), 5 deletions(-) diff --git a/flask/sessions.py b/flask/sessions.py index 2dbd8b32..9d937be0 100644 --- a/flask/sessions.py +++ b/flask/sessions.py @@ -405,7 +405,7 @@ class SecureCookieSessionInterface(SessionInterface): # Add a "Vary: Cookie" header if the session was accessed at all. if session.accessed: - response.headers.add('Vary', 'Cookie') + self._patch_vary_cookie_header(response) if not self.should_set_cookie(app, session): return @@ -423,3 +423,16 @@ class SecureCookieSessionInterface(SessionInterface): path=path, secure=secure ) + + def _patch_vary_cookie_header(self, response): + """ + Add a 'Cookie' value to the 'Vary' header if one is not already present. + """ + header = response.headers.get('Vary', '') + headers = [h.strip() for h in header.split(',') if h] + + if not any(h.lower() == 'cookie' for h in headers): + headers.append('Cookie') + + updated_header = ', '.join(headers) + response.headers['Vary'] = updated_header diff --git a/tests/test_basic.py b/tests/test_basic.py index de56cb43..e4d6b2f9 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -520,15 +520,31 @@ def test_session_vary_cookie(app, client): def setdefault(): return flask.session.setdefault('test', 'default') + @app.route('/vary-cookie-header-set') + def vary_cookie_header_set(): + response = flask.Response() + response.headers['Vary'] = 'Cookie' + flask.session['test'] = 'test' + return response + + @app.route('/vary-header-set') + def vary_header_set(): + response = flask.Response() + response.headers['Vary'] = 'Accept-Encoding, Accept-Language' + flask.session['test'] = 'test' + return response + @app.route('/no-vary-header') def no_vary_header(): return '' - def expect(path, header=True): + def expect(path, header_value='Cookie'): rv = client.get(path) - if header: - assert rv.headers['Vary'] == 'Cookie' + if header_value: + # The 'Vary' key should exist in the headers only once. + assert len(rv.headers.get_all('Vary')) == 1 + assert rv.headers['Vary'] == header_value else: assert 'Vary' not in rv.headers @@ -536,7 +552,9 @@ def test_session_vary_cookie(app, client): expect('/get') expect('/getitem') expect('/setdefault') - expect('/no-vary-header', False) + expect('/vary-cookie-header-set') + expect('/vary-header-set', 'Accept-Encoding, Accept-Language, Cookie') + expect('/no-vary-header', None) def test_flashes(app, req_ctx): From bdf31cd423a295de2f6956b2e8da1d8f26c91858 Mon Sep 17 00:00:00 2001 From: David Lord Date: Thu, 25 May 2017 10:26:02 -0700 Subject: [PATCH 2/2] extract patch_vary_header to helpers --- flask/helpers.py | 14 ++++++++++++++ flask/sessions.py | 29 +++++++++-------------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/flask/helpers.py b/flask/helpers.py index f37be677..2bcdc10b 100644 --- a/flask/helpers.py +++ b/flask/helpers.py @@ -1004,3 +1004,17 @@ def is_ip(value): return True return False + + +def patch_vary_header(response, value): + """Add a value to the ``Vary`` header if it is not already present.""" + + header = response.headers.get('Vary', '') + headers = [h for h in (h.strip() for h in header.split(',')) if h] + lower_value = value.lower() + + if not any(h.lower() == lower_value for h in headers): + headers.append(value) + + updated_header = ', '.join(headers) + response.headers['Vary'] = updated_header diff --git a/flask/sessions.py b/flask/sessions.py index 9d937be0..47f0b3fd 100644 --- a/flask/sessions.py +++ b/flask/sessions.py @@ -9,18 +9,20 @@ :license: BSD, see LICENSE for more details. """ -import uuid import hashlib +import uuid import warnings -from base64 import b64encode, b64decode +from base64 import b64decode, b64encode from datetime import datetime -from werkzeug.http import http_date, parse_date + +from itsdangerous import BadSignature, URLSafeTimedSerializer from werkzeug.datastructures import CallbackDict +from werkzeug.http import http_date, parse_date + +from flask.helpers import patch_vary_header from . import Markup, json from ._compat import iteritems, text_type -from .helpers import total_seconds, is_ip - -from itsdangerous import URLSafeTimedSerializer, BadSignature +from .helpers import is_ip, total_seconds class SessionMixin(object): @@ -405,7 +407,7 @@ class SecureCookieSessionInterface(SessionInterface): # Add a "Vary: Cookie" header if the session was accessed at all. if session.accessed: - self._patch_vary_cookie_header(response) + patch_vary_header(response, 'Cookie') if not self.should_set_cookie(app, session): return @@ -423,16 +425,3 @@ class SecureCookieSessionInterface(SessionInterface): path=path, secure=secure ) - - def _patch_vary_cookie_header(self, response): - """ - Add a 'Cookie' value to the 'Vary' header if one is not already present. - """ - header = response.headers.get('Vary', '') - headers = [h.strip() for h in header.split(',') if h] - - if not any(h.lower() == 'cookie' for h in headers): - headers.append('Cookie') - - updated_header = ', '.join(headers) - response.headers['Vary'] = updated_header