Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Add exemption for lang param in locale middleware. #55

Merged
merged 1 commit into from

3 participants

Paul McLanahan Josh Mize Michael Kelly
Paul McLanahan
Owner

There may be some URLs which have other uses for a
'lang' query parameter. This allows you to set such URLs as exempt.

This is mostly for bedrock, as we need the /firefox/download/ page
to accept a ?lang= parameter that refers to the language of the
Fx build you wish to download. That param for that page has existed
for a long time and we're trying to port it from the PHP side
to bedrock.

funfactory/middleware.py
@@ -18,6 +18,9 @@
from .helpers import urlparams
+EXEMPT_URLS = getattr(settings, 'FF_EXEMPT_LANG_PARAM_URLS', None)
Josh Mize Owner
jgmize added a note

I would default this to an empty list instead of None here so you can always iterate through it.

Josh Mize Owner
jgmize added a note

I also wonder if s/URL/PATH/g would make more sense here.

Paul McLanahan Owner

There are just other settings that use URL. Figured it was more consistent.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
funfactory/middleware.py
@@ -31,12 +34,24 @@ def __init__(self):
"loaded. Consider removing funfactory.middleware."
"LocaleURLMiddleware from your MIDDLEWARE_CLASSES setting.")
+ def _is_lang_change(self, request):
+ """Return True if the lang param is present and URL isn't exempt."""
+ if 'lang' not in request.GET:
+ return False
+
+ if EXEMPT_URLS:
Josh Mize Owner
jgmize added a note

This becomes unecessary if you make the change I recommended on line 21.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
funfactory/middleware.py
@@ -31,12 +34,24 @@ def __init__(self):
"loaded. Consider removing funfactory.middleware."
"LocaleURLMiddleware from your MIDDLEWARE_CLASSES setting.")
+ def _is_lang_change(self, request):
+ """Return True if the lang param is present and URL isn't exempt."""
+ if 'lang' not in request.GET:
+ return False
+
+ if EXEMPT_URLS:
+ for url in EXEMPT_URLS:
+ if request.path.endswith(url):
Josh Mize Owner
jgmize added a note

Why are you using endswith here?

Paul McLanahan Owner

So you don't have to list every locale to exempt.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Josh Mize jgmize commented on the diff
funfactory/middleware.py
((16 lines not shown))
def process_request(self, request):
prefixer = urlresolvers.Prefixer(request)
urlresolvers.set_url_prefix(prefixer)
full_path = prefixer.fix(prefixer.shortened_path)
- if 'lang' in request.GET:
+ if self._is_lang_change(request):
Josh Mize Owner
jgmize added a note

Why not just change this to

if 'lang' in request.GET and request.path not in EXEMPT_PATHS:

instead of using the separate function? wouldn't that accomplish the same purpose?

(This only works with the changes recommended on line 21)

Paul McLanahan Owner

Because of what I said earlier. This also leaves the possibility open of someone improving this later by adding optional regex support doing some kind of isinstance check.

Josh Mize Owner
jgmize added a note

Good ideas, I like it. Bonus points for pointing out that it currently matches the end of the path in a docstring, double bonus points if you go ahead and use regex matching-- I don't think an isinstance check is necessary for that, you can just iterate through and feed each string to re.search, which would accomplish the same thing as endswith, effectively.

Josh Mize Owner
jgmize added a note

On second thought, scratch the double bonus points for using regex-- I don't think the performance and maintainability tradeoff would be worth it for something there isn't a clear use case for. This is good just the way it is.

Paul McLanahan Owner

That's what I thought as well. I doubt it'll need to be that flexible. Someone can always change it if so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
funfactory/middleware.py
@@ -31,12 +34,23 @@ def __init__(self):
"loaded. Consider removing funfactory.middleware."
"LocaleURLMiddleware from your MIDDLEWARE_CLASSES setting.")
+ def _is_lang_change(self, request):
+ """Return True if the lang param is present and URL isn't exempt."""
+ if 'lang' not in request.GET:
Josh Mize Owner
jgmize added a note

suggested replacement:

if not request.GET.get('lang'):

That way a url like /?lang=&dude=abides won't cause the middleware to ignore the Accept-Language header. Also, the hash lookup is theoretically more performant than iterating (yes, in practice the O(1) vs O(n) doesn't really matter b/c it's a small n, but still...)

Josh Mize Owner
jgmize added a note

On further relection, how about this instead?

return request.GET.get('lang') and not any(request.path.endswith(url) for url in EXEMPT_URLS)
Paul McLanahan Owner

I don't think the hit to readability is worth it.

Paul McLanahan Owner

Also the original middleware would attempt to use the ?lang parameter even if it was just /path/?lang. I'm pretty sure no one is counting on that, but my intent is not to change the default operation.

Michael Kelly Owner
Osmose added a note

Why not Zoidberg?

return 'lang' in request.GET and not any(request.path.endswith(url) for url in EXEMPT_URLS)
Paul McLanahan Owner

I'd be fine using:

return not any(request.path.endswith(url) for url in EXEMPT_URLS)

As a replacement for line 42. But I'm not sure it won't be slightly slower due to it finishing all the urls before returning. A reasonable list likely won't matter though, and I can't imaging the EXEMPT_URLS growing past 2 or 3.

Michael Kelly Owner
Osmose added a note

any short circuits: http://stackoverflow.com/questions/14730046/is-the-shortcircuit-behaviour-of-pythons-any-all-explicit

Also why are we arguing about performance when there's databases people.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
funfactory/middleware.py
@@ -18,6 +18,9 @@
from .helpers import urlparams
+EXEMPT_URLS = getattr(settings, 'FF_EXEMPT_LANG_PARAM_URLS', ())
Michael Kelly Owner
Osmose added a note

In general it's a bad idea to read a setting on module import, as it makes testing difficult and anything else that may modify the settings at runtime (not that that should happen, but it could).

I'd change this to be a property on the class.

Paul McLanahan Owner

I had it like that. Should do that again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
funfactory/middleware.py
@@ -31,12 +34,19 @@ def __init__(self):
"loaded. Consider removing funfactory.middleware."
"LocaleURLMiddleware from your MIDDLEWARE_CLASSES setting.")
+ def _is_lang_change(self, request):
+ """Return True if the lang param is present and URL isn't exempt."""
+ if 'lang' not in request.GET:
+ return False
+
+ return not any(request.path.endswith(url) for url in EXEMPT_URLS)
Paul McLanahan Owner

What do y'all think of this?

Michael Kelly Owner
Osmose added a note

I think you're worrying way too much about this.

Paul McLanahan Owner

I'm not. I liked what I had. I'm just following the review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Paul McLanahan
Owner

If no one else has any objections I'm going to rebase and merge.

Paul McLanahan pmclanahan Add exemption for lang param in locale middleware.
There may be some URLs which have other uses for a
'lang' query parameter. This allows you to set such
URLs as exempt.
7a1472a
Josh Mize
Owner

r+

Paul McLanahan pmclanahan merged commit 31bd1b4 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Sep 13, 2013
  1. Paul McLanahan

    Add exemption for lang param in locale middleware.

    pmclanahan authored
    There may be some URLs which have other uses for a
    'lang' query parameter. This allows you to set such
    URLs as exempt.
This page is out of date. Refresh to see the latest.
Showing with 57 additions and 1 deletion.
  1. +10 −1 funfactory/middleware.py
  2. +47 −0 tests/test_middleware.py
11 funfactory/middleware.py
View
@@ -31,12 +31,21 @@ def __init__(self):
"loaded. Consider removing funfactory.middleware."
"LocaleURLMiddleware from your MIDDLEWARE_CLASSES setting.")
+ self.exempt_urls = getattr(settings, 'FF_EXEMPT_LANG_PARAM_URLS', ())
+
+ def _is_lang_change(self, request):
+ """Return True if the lang param is present and URL isn't exempt."""
+ if 'lang' not in request.GET:
+ return False
+
+ return not any(request.path.endswith(url) for url in self.exempt_urls)
+
def process_request(self, request):
prefixer = urlresolvers.Prefixer(request)
urlresolvers.set_url_prefix(prefixer)
full_path = prefixer.fix(prefixer.shortened_path)
- if 'lang' in request.GET:
+ if self._is_lang_change(request):
Josh Mize Owner
jgmize added a note

Why not just change this to

if 'lang' in request.GET and request.path not in EXEMPT_PATHS:

instead of using the separate function? wouldn't that accomplish the same purpose?

(This only works with the changes recommended on line 21)

Paul McLanahan Owner

Because of what I said earlier. This also leaves the possibility open of someone improving this later by adding optional regex support doing some kind of isinstance check.

Josh Mize Owner
jgmize added a note

Good ideas, I like it. Bonus points for pointing out that it currently matches the end of the path in a docstring, double bonus points if you go ahead and use regex matching-- I don't think an isinstance check is necessary for that, you can just iterate through and feed each string to re.search, which would accomplish the same thing as endswith, effectively.

Josh Mize Owner
jgmize added a note

On second thought, scratch the double bonus points for using regex-- I don't think the performance and maintainability tradeoff would be worth it for something there isn't a clear use case for. This is good just the way it is.

Paul McLanahan Owner

That's what I thought as well. I doubt it'll need to be that flexible. Someone can always change it if so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
# Blank out the locale so that we can set a new one. Remove lang
# from the query params so we don't have an infinite loop.
prefixer.locale = ''
47 tests/test_middleware.py
View
@@ -0,0 +1,47 @@
+from django.test import TestCase, RequestFactory
+from django.test.utils import override_settings
+
+from funfactory.middleware import LocaleURLMiddleware
+
+
+class TestLocaleURLMiddleware(TestCase):
+ def setUp(self):
+ self.rf = RequestFactory()
+ self.middleware = LocaleURLMiddleware()
+
+ @override_settings(DEV_LANGUAGES=('de', 'fr'),
+ FF_EXEMPT_LANG_PARAM_URLS=())
+ def test_redirects_to_correct_language(self):
+ """Should redirect to lang prefixed url."""
+ path = '/the/dude/'
+ req = self.rf.get(path, HTTP_ACCEPT_LANGUAGE='de')
+ resp = LocaleURLMiddleware().process_request(req)
+ self.assertEqual(resp['Location'], '/de' + path)
+
+ @override_settings(DEV_LANGUAGES=('es', 'fr'),
+ LANGUAGE_CODE='en-US',
+ FF_EXEMPT_LANG_PARAM_URLS=())
+ def test_redirects_to_default_language(self):
+ """Should redirect to default lang if not in settings."""
+ path = '/the/dude/'
+ req = self.rf.get(path, HTTP_ACCEPT_LANGUAGE='de')
+ resp = LocaleURLMiddleware().process_request(req)
+ self.assertEqual(resp['Location'], '/en-US' + path)
+
+ @override_settings(DEV_LANGUAGES=('de', 'fr'),
+ FF_EXEMPT_LANG_PARAM_URLS=('/other/',))
+ def test_redirects_lang_param(self):
+ """Middleware should remove the lang param on redirect."""
+ path = '/fr/the/dude/'
+ req = self.rf.get(path, {'lang': 'de'})
+ resp = LocaleURLMiddleware().process_request(req)
+ self.assertEqual(resp['Location'], '/de/the/dude/')
+
+ @override_settings(DEV_LANGUAGES=('de', 'fr'),
+ FF_EXEMPT_LANG_PARAM_URLS=('/dude/',))
+ def test_no_redirect_lang_param(self):
+ """Middleware should not redirect when exempt."""
+ path = '/fr/the/dude/'
+ req = self.rf.get(path, {'lang': 'de'})
+ resp = LocaleURLMiddleware().process_request(req)
+ self.assertIs(resp, None) # no redirect
Something went wrong with that request. Please try again.