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

Reduce the impact on every request #22

Merged
merged 3 commits into from
May 8, 2019
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 HISTORY.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Pending release
.. Insert new release notes below this line

* Fix interpretation of '*' by not automatically adding quotes.
* Optimize header generation to reduce impact on every request.

2.1.0 (2019-04-28)
------------------
Expand Down
22 changes: 17 additions & 5 deletions django_feature_policy.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.signals import setting_changed
from django.dispatch import receiver
from django.utils.functional import cached_property

__version__ = '2.1.0'

# Retrieved from Chrome document.featurePolicy.allowedFeatures()
FEATURE_NAMES = [
FEATURE_NAMES = {
'accelerometer',
'ambient-light-sensor',
'autoplay',
Expand Down Expand Up @@ -34,22 +37,24 @@
'vertical-scroll',
'vr',
'wake-lock',
]
}


class FeaturePolicyMiddleware:
def __init__(self, get_response):
self.get_response = get_response
self.get_header_value() # to check
self.header_value # Access at setup so ImproperlyConfigured can be raised
receiver(setting_changed)(self.clear_header_value)

def __call__(self, request):
response = self.get_response(request)
value = self.get_header_value()
value = self.header_value
if value:
response['Feature-Policy'] = value
return response

def get_header_value(self):
@cached_property
def header_value(self):
setting = getattr(settings, 'FEATURE_POLICY', {})
pieces = []
for feature, values in setting.items():
Expand All @@ -68,3 +73,10 @@ def get_header_value(self):
item.append(value)
pieces.append(' '.join(item))
return '; '.join(pieces)

def clear_header_value(self, setting, **kwargs):
if setting == 'FEATURE_POLICY':
try:
del self.header_value
except AttributeError:
pass
20 changes: 20 additions & 0 deletions tests/test_django_feature_policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,3 +81,23 @@ def test_unknown_feature(client, settings):

with pytest.raises(ImproperlyConfigured):
client.get('/')


def test_setting_changing(client, settings):
settings.FEATURE_POLICY = {}
client.get('/') # Forces middleware instantiation
settings.FEATURE_POLICY = {'geolocation': 'self'}

resp = client.get('/')

assert resp['Feature-Policy'] == "geolocation 'self'"


def test_other_setting_changing(client, settings):
settings.FEATURE_POLICY = {'geolocation': 'self'}
client.get('/') # Forces middleware instantiation
settings.SECRET_KEY = 'foobar'

resp = client.get('/')

assert resp['Feature-Policy'] == "geolocation 'self'"