HTTP_HOST middleware for storefronts (bug 769421)
This commit is contained in:
Родитель
23dfb11eef
Коммит
6b1bf8bc9f
|
@ -41,6 +41,9 @@ DATABASES = {
|
|||
},
|
||||
}
|
||||
|
||||
# To get browser ID to work on your local dev instance, add this.
|
||||
#SITE_URL_OVERRIDE = 'http://localhost:8000'
|
||||
|
||||
# Skip indexing ES to speed things up?
|
||||
SKIP_SEARCH_INDEX = False
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
from .httphost import *
|
|
@ -0,0 +1,7 @@
|
|||
from lib import httphost
|
||||
|
||||
|
||||
def httphost_context(request):
|
||||
"""Exposes SITE_URL and SUBDOMAIN to the request context."""
|
||||
return {'SITE_URL': httphost.site_url(),
|
||||
'SUBDOMAIN': httphost.subdomain()}
|
|
@ -0,0 +1,48 @@
|
|||
import re
|
||||
import threading
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
|
||||
app = threading.local()
|
||||
non_host_chars = re.compile(r'[^a-zA-Z0-9\.-]+')
|
||||
|
||||
__all__ = ['site_url', 'subdomain']
|
||||
|
||||
|
||||
def site_url():
|
||||
"""
|
||||
Gets the full subdomain of the host serving the request.
|
||||
|
||||
Example: https://marketplace.mozilla.org
|
||||
"""
|
||||
if settings.SITE_URL_OVERRIDE:
|
||||
if not settings.DEBUG:
|
||||
raise ImproperlyConfigured('Cannot set SITE_URL_OVERRIDE in '
|
||||
'production; it is set from HTTP_HOST')
|
||||
return settings.SITE_URL_OVERRIDE
|
||||
try:
|
||||
return app.site_url
|
||||
except AttributeError:
|
||||
raise RuntimeError('Cannot access site_url() on a thread before a '
|
||||
'request has been made')
|
||||
|
||||
|
||||
def subdomain():
|
||||
"""
|
||||
Gets the top-most subdomain of the host serving the request.
|
||||
|
||||
Example telefonica from telefonica.marketplace.mozilla.org
|
||||
"""
|
||||
try:
|
||||
return app.subdomain
|
||||
except AttributeError:
|
||||
raise RuntimeError('Cannot access site_url() on a thread before a '
|
||||
'request has been made')
|
||||
|
||||
|
||||
def set_host_info(host):
|
||||
# In case someone is messing with the host header, scrub it.
|
||||
host = non_host_chars.sub('', host)
|
||||
app.site_url = 'https://%s' % host
|
||||
app.subdomain = host.split('.')[0]
|
|
@ -0,0 +1,13 @@
|
|||
from .httphost import set_host_info
|
||||
|
||||
|
||||
class HTTPHostMiddleware:
|
||||
"""
|
||||
Stores globally accessible metadata about the host.
|
||||
|
||||
This requires the server (Apache or whatever) to set HTTP_HOST.
|
||||
"""
|
||||
|
||||
def process_request(self, request):
|
||||
# e.g. telefonica.marketplace.mozilla.org
|
||||
set_host_info(request.META.get('HTTP_HOST', ''))
|
|
@ -0,0 +1,83 @@
|
|||
import unittest
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test.client import RequestFactory
|
||||
|
||||
import mock
|
||||
from nose.tools import raises, eq_
|
||||
|
||||
from lib import httphost
|
||||
from lib.httphost.context_processors import httphost_context
|
||||
from lib.httphost.middleware import HTTPHostMiddleware
|
||||
|
||||
|
||||
class UninitializedApp:
|
||||
"""stub for httphost.app"""
|
||||
|
||||
|
||||
class TestHTTPHost(unittest.TestCase):
|
||||
|
||||
def middleware(self, http_host):
|
||||
serv = RequestFactory()
|
||||
req = serv.get('/some/url')
|
||||
req.META['HTTP_HOST'] = http_host
|
||||
mw = HTTPHostMiddleware()
|
||||
mw.process_request(req)
|
||||
|
||||
def context(self):
|
||||
serv = RequestFactory()
|
||||
return httphost_context(serv.get('/some/url'))
|
||||
|
||||
@mock.patch('lib.httphost.httphost.app', UninitializedApp)
|
||||
@raises(RuntimeError)
|
||||
def test_not_set(self):
|
||||
httphost.site_url()
|
||||
|
||||
def test_site_url(self):
|
||||
self.middleware('telefonica.marketplace.mozilla.org')
|
||||
eq_(httphost.site_url(),
|
||||
'https://telefonica.marketplace.mozilla.org')
|
||||
|
||||
@mock.patch.object(settings, 'DEBUG', True)
|
||||
@mock.patch.object(settings, 'SITE_URL_OVERRIDE',
|
||||
'http://localhost:8000')
|
||||
def test_site_url_override(self):
|
||||
self.middleware('telefonica.marketplace.mozilla.org')
|
||||
eq_(httphost.site_url(), 'http://localhost:8000')
|
||||
|
||||
@raises(ImproperlyConfigured)
|
||||
@mock.patch.object(settings, 'DEBUG', False)
|
||||
@mock.patch.object(settings, 'SITE_URL_OVERRIDE',
|
||||
'http://localhost:8000')
|
||||
def test_cannot_override_site_url_in_prod(self):
|
||||
httphost.site_url()
|
||||
|
||||
def test_subdomain(self):
|
||||
self.middleware('telefonica.marketplace.mozilla.org')
|
||||
eq_(httphost.subdomain(), 'telefonica')
|
||||
|
||||
def test_subdomain_amo(self):
|
||||
self.middleware('addons.mozilla.org')
|
||||
eq_(httphost.subdomain(), 'addons')
|
||||
|
||||
@mock.patch('lib.httphost.httphost.app', UninitializedApp)
|
||||
@raises(RuntimeError)
|
||||
def test_subdomain_not_set(self):
|
||||
httphost.subdomain()
|
||||
|
||||
def test_subdomain_context(self):
|
||||
self.middleware('telefonica.marketplace.mozilla.org')
|
||||
eq_(self.context()['SUBDOMAIN'], 'telefonica')
|
||||
|
||||
def test_site_url_context(self):
|
||||
self.middleware('marketplace.mozilla.org')
|
||||
eq_(self.context()['SITE_URL'], 'https://marketplace.mozilla.org')
|
||||
|
||||
def test_site_url_is_scrubbed(self):
|
||||
self.middleware('file:///etc/passwd')
|
||||
eq_(httphost.site_url(), 'https://fileetcpasswd')
|
||||
|
||||
def test_subdomain_is_scrubbed(self):
|
||||
self.middleware('file:///etc/passwd')
|
||||
eq_(httphost.subdomain(), 'fileetcpasswd')
|
|
@ -163,8 +163,15 @@ DOMAIN = HOSTNAME
|
|||
|
||||
# Full base URL for your main site including protocol. No trailing slash.
|
||||
# Example: https://addons.mozilla.org
|
||||
# TODO(Kumar) when ready, remove this in place of httphost.site_url()
|
||||
SITE_URL = 'http://%s' % DOMAIN
|
||||
|
||||
# The site URL is automatically determined with lib.httphost.HTTPHostMiddleware.
|
||||
# However, if you want to explicitly set it for local development,
|
||||
# you can do so here. This setting only works when DEBUG is True.
|
||||
# Example: http://localhost:8000
|
||||
SITE_URL_OVERRIDE = None
|
||||
|
||||
# Domain of the services site. This is where your API, and in-product pages
|
||||
# live.
|
||||
SERVICES_DOMAIN = 'services.%s' % DOMAIN
|
||||
|
@ -268,6 +275,7 @@ TEMPLATE_CONTEXT_PROCESSORS = (
|
|||
'amo.context_processors.global_settings',
|
||||
'amo.context_processors.static_url',
|
||||
'jingo_minify.helpers.build_ids',
|
||||
'lib.httphost.context_processors.httphost_context',
|
||||
)
|
||||
|
||||
TEMPLATE_DIRS = (
|
||||
|
@ -328,6 +336,8 @@ MIDDLEWARE_CLASSES = (
|
|||
'access.middleware.ACLMiddleware',
|
||||
|
||||
'commonware.middleware.ScrubRequestOnException',
|
||||
# Set storefront related vars based on host.
|
||||
'lib.httphost.middleware.HTTPHostMiddleware',
|
||||
)
|
||||
|
||||
# Auth
|
||||
|
|
|
@ -52,6 +52,7 @@ PAYPAL_PERMISSIONS_URL = ''
|
|||
|
||||
STATIC_URL = ''
|
||||
SITE_URL = ''
|
||||
SITE_URL_OVERRIDE = None
|
||||
MOBILE_SITE_URL = ''
|
||||
MEDIA_URL = '/media/'
|
||||
# Reset these URLs to the defaults so your settings_local doesn't clobber them:
|
||||
|
|
Загрузка…
Ссылка в новой задаче