Skip to content

Instantly share code, notes, and snippets.

@FelixWolf
Created December 18, 2022 22:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save FelixWolf/ef6fe37e95def57e90ab8136f82cf307 to your computer and use it in GitHub Desktop.
Save FelixWolf/ef6fe37e95def57e90ab8136f82cf307 to your computer and use it in GitHub Desktop.
import logging
from django.conf import settings
from django.urls import get_urlconf, set_urlconf
logger = logging.getLogger(__name__)
#We only really need the lower case variant, so cast it to lower case
#instead of doing it every time
ROOT_HOSTROOT = ("localhost",)
if hasattr(settings, "ROOT_HOSTROOT"):
t = type(settings.ROOT_HOSTROOT)
if t == str: #String
ROOT_HOSTROOT = (settings.ROOT_HOSTROOT.lower(),)
elif t in (tuple, list): #List or tuples
ROOT_HOSTROOT = (i.lower() for i in settings.ROOT_HOSTROOT)
else: #Allow for expanding with a class
ROOT_HOSTROOT = settings.ROOT_HOSTROOT
ROOT_HOSTCONF = {}
if hasattr(settings, "ROOT_HOSTCONF"):
ROOT_HOSTCONF = settings.ROOT_HOSTCONF
class HostnameMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
#If there is an port, this will split it off
host = request.get_host().split(":",1)
hostname = host[0]
port = 80
#If port is specified, extract it
if len(hostname) == 2:
try:
port = int(hostname[1])
except ValueError:
logger.error("Failed to parse port part '{}' of hostname '{}'" \
.format(hostname[1], host))
subdomain = []
if ROOT_HOSTROOT:
lh = hostname.lower()
match = None
for match in ROOT_HOSTROOT:
if lh == match:
break
if lh.endswith("." + match):
match = "." + match
break
match = None
if match == None:
subdomain = lh.split(".")
elif lh == match:
subdomain = []
else:
subdomain = lh[:-len(match)].split(".")
else:
subdomain = hostname.split(".")
subdomain = tuple(subdomain)
request.subdomain = subdomain
#Store the current urlconf so we don't refresh the cache
current_urlconf = get_urlconf()
new_urlconf = current_urlconf
#If we have exactly just the root level (EG: example.com, localhost, ..)
if len(subdomain) == 0:
if subdomain in ROOT_HOSTCONF:
new_urlconf = ROOT_HOSTCONF[subdomain]
else:
new_urlconf = settings.ROOT_URLCONF
#Else, if we have subdomains
else:
foundconf = None
for entry in ROOT_HOSTCONF:
#Prevent crashing, this would have matched previous
if len(entry) == 0:
continue
#If subdomain has less levels than entry, skip it
if len(subdomain) < len(entry):
continue
#If we are to match every higher level entry
match = 0
for i in reversed(range(len(entry))):
#Matched wildcard
if entry[i] == "*":
match += 1
continue
#Matched entry
if entry[i] == subdomain[i]:
match += 1
continue
#Match everything past this point
if entry[i] == "**":
match = len(subdomain)
break
#No match
match = -1
break
if match == len(subdomain):
foundconf = ROOT_HOSTCONF[entry]
break
if foundconf:
new_urlconf = foundconf
else:
new_urlconf = settings.ROOT_URLCONF
if current_urlconf != new_urlconf:
set_urlconf(new_urlconf)
request.urlconf = new_urlconf
return self.get_response(request)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment