HTTP_HOST middleware for storefronts (bug 769421)

This commit is contained in:
Kumar McMillan 2012-07-02 17:10:18 -05:00
Родитель 23dfb11eef
Коммит 6b1bf8bc9f
8 изменённых файлов: 166 добавлений и 0 удалений

Просмотреть файл

@ -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

1
lib/httphost/__init__.py Normal file
Просмотреть файл

@ -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()}

48
lib/httphost/httphost.py Normal file
Просмотреть файл

@ -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', ''))

83
lib/httphost/tests.py Normal file
Просмотреть файл

@ -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: