From feb78498686b272affaa5b3773d1b2e6f41fabc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Us=C3=A1n?= <5434104+andruten@users.noreply.github.com> Date: Mon, 28 Oct 2024 12:31:06 +0100 Subject: [PATCH] feat: Introduced new REVPROXY_QUOTE_SPACES_AS_PLUS setting (#191) * feat: declared new revproxy settings section * feat: allow both quote and quote_plus depending on QUOTE_SPACES_AS_PLUS setting * chore: added test * chore: renamed variable * chore: updated docs --------- Co-authored-by: andruten --- CHANGELOG.rst | 6 ++++++ docs/index.rst | 1 + docs/quickstart.rst | 2 +- docs/settings.rst | 4 ++++ revproxy/__init__.py | 2 ++ revproxy/apps.py | 18 ++++++++++++++++++ revproxy/settings.py | 3 +++ revproxy/views.py | 13 ++++++++++--- tests/test_views.py | 23 +++++++++++++++++++++-- 9 files changed, 66 insertions(+), 6 deletions(-) create mode 100644 docs/settings.rst create mode 100644 revproxy/apps.py create mode 100644 revproxy/settings.py diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2544b1e..b0cd58c 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,3 +1,9 @@ +0.13.0 (Unreleased) +=================== + +* Added new `REVPROXY_QUOTE_SPACES_AS_PLUS` setting + + 0.12.0 (2023-10-19) =================== diff --git a/docs/index.rst b/docs/index.rst index e7a8cd4..a663c99 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -16,6 +16,7 @@ Contents: quickstart proxyview modules + settings changelog diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 96eff06..602d25c 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -27,7 +27,7 @@ Start by adding revproxy to your ``settings.py`` file as follows: INSTALLED_APPS = ( # ... 'django.contrib.auth', - 'revproxy', + 'revproxy.apps.RevProxyConfig', # ... ) diff --git a/docs/settings.rst b/docs/settings.rst new file mode 100644 index 0000000..3dd3b2c --- /dev/null +++ b/docs/settings.rst @@ -0,0 +1,4 @@ +Settings +================== + +`REVPROXY_QUOTE_SPACES_AS_PLUS`: Tells revproxy if it spaces should be replaced by `+` or `%20`. diff --git a/revproxy/__init__.py b/revproxy/__init__.py index 2c7bffb..74c952d 100644 --- a/revproxy/__init__.py +++ b/revproxy/__init__.py @@ -1 +1,3 @@ __version__ = '0.12.0' + +default_app_config = 'revproxy.apps.RevProxyConfig' diff --git a/revproxy/apps.py b/revproxy/apps.py new file mode 100644 index 0000000..ab840a9 --- /dev/null +++ b/revproxy/apps.py @@ -0,0 +1,18 @@ +from django.apps import AppConfig +from django.conf import settings +from django.utils.translation import gettext_lazy as _ +from .settings import REVPROXY_DEFAULT_SETTINGS + + +class RevProxyConfig(AppConfig): + name = 'revproxy' + verbose_name = _('Revproxy') + + def ready(self): + super().ready() + for setting, default_value in REVPROXY_DEFAULT_SETTINGS.items(): + setattr( + settings, + setting, + getattr(settings, setting, default_value), + ) diff --git a/revproxy/settings.py b/revproxy/settings.py new file mode 100644 index 0000000..96405f1 --- /dev/null +++ b/revproxy/settings.py @@ -0,0 +1,3 @@ +REVPROXY_DEFAULT_SETTINGS = { + 'REVPROXY_QUOTE_SPACES_AS_PLUS': True, +} diff --git a/revproxy/views.py b/revproxy/views.py index 5a56704..f0676d8 100644 --- a/revproxy/views.py +++ b/revproxy/views.py @@ -10,11 +10,15 @@ try: from django.utils.six.moves.urllib.parse import ( - urlparse, urlencode, quote_plus) + urlparse, urlencode, quote_plus, quote + ) except ImportError: # Django 3 has no six - from urllib.parse import urlparse, urlencode, quote_plus + from urllib.parse import ( + urlparse, urlencode, quote_plus, quote + ) +from django.conf import settings from django.shortcuts import redirect from django.views.generic import View from django.utils.decorators import classonlymethod @@ -165,7 +169,10 @@ def get_request_headers(self): def get_quoted_path(self, path): """Return quoted path to be used in proxied request""" - return quote_plus(path.encode('utf8'), QUOTE_SAFE) + if settings.REVPROXY_QUOTE_SPACES_AS_PLUS: + return quote_plus(path.encode('utf8'), QUOTE_SAFE) + else: + return quote(path.encode('utf8'), QUOTE_SAFE) def get_encoded_query_params(self): """Return encoded query params to be used in proxied request""" diff --git a/tests/test_views.py b/tests/test_views.py index 0b49634..66bf6ed 100644 --- a/tests/test_views.py +++ b/tests/test_views.py @@ -2,7 +2,7 @@ from unittest.mock import patch from django.conf import settings -from django.test import TestCase, RequestFactory +from django.test import TestCase, RequestFactory, override_settings try: from django.utils.six.moves.urllib.parse import ParseResult except ImportError: @@ -194,7 +194,7 @@ class CustomProxyView(ProxyView): decode_content=False, headers=headers) - def test_space_is_escaped(self): + def test_space_is_escaped_enabled(self): class CustomProxyView(ProxyView): upstream = 'http://example.com' @@ -212,6 +212,25 @@ class CustomProxyView(ProxyView): decode_content=False, headers=headers) + @override_settings(REVPROXY_QUOTE_SPACES_AS_PLUS=False) + def test_space_is_escaped_disabled(self): + class CustomProxyView(ProxyView): + upstream = 'http://example.com' + + path = ' test test' + request = self.factory.get(path) + CustomProxyView.as_view()(request, path) + + url = 'http://example.com/%20test%20test' + headers = {u'Cookie': u''} + self.urlopen.assert_called_with('GET', url, + body=b'', + redirect=False, + retries=None, + preload_content=False, + decode_content=False, + headers=headers) + def test_extending_headers(self): class CustomProxyView(ProxyView): upstream = 'http://example.com'