Skip to content

Remove logic for guessing slug from an unregistered domain #4730

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
34 changes: 10 additions & 24 deletions readthedocs/core/middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from django.contrib.sessions.middleware import SessionMiddleware
from django.core.cache import cache
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.core.urlresolvers import set_urlconf, get_urlconf
from django.core.urlresolvers import set_urlconf
from django.http import Http404, HttpResponseBadRequest

from readthedocs.core.utils import cname_to_slug
from readthedocs.projects.models import Project, Domain

log = logging.getLogger(__name__)
Expand Down Expand Up @@ -101,33 +99,21 @@ def process_request(self, request):
**log_kwargs))
# Try header first, then DNS
elif not hasattr(request, 'domain_object'):
try:
slug = cache.get(host)
if not slug:
slug = cname_to_slug(host)
cache.set(host, slug, 60 * 60)
# Cache the slug -> host mapping permanently.
log.debug(LOG_TEMPLATE.format(
msg='CNAME cached: %s->%s' % (slug, host),
**log_kwargs))
request.slug = slug
request.urlconf = SUBDOMAIN_URLCONF
log.debug(LOG_TEMPLATE.format(
msg='CNAME detected: %s' % request.slug,
**log_kwargs))
except: # noqa
# Some crazy person is CNAMEing to us. 404.
log.debug(LOG_TEMPLATE.format(msg='CNAME 404', **log_kwargs))
raise Http404(_('Invalid hostname'))
# Some person is CNAMEing to us. 404.
log.debug(LOG_TEMPLATE.format(msg='CNAME 404', **log_kwargs))
raise Http404(_('Invalid hostname'))
# Google was finding crazy www.blah.readthedocs.org domains.
# Block these explicitly after trying CNAME logic.
if len(domain_parts) > 3 and not settings.DEBUG:
# Stop www.fooo.readthedocs.org
if domain_parts[0] == 'www':
log.debug(LOG_TEMPLATE.format(msg='404ing long domain', **log_kwargs))
log.debug(LOG_TEMPLATE.format(
msg='404ing long domain', **log_kwargs
))
return HttpResponseBadRequest(_('Invalid hostname'))
log.debug(LOG_TEMPLATE.format(msg='Allowing long domain name', **log_kwargs))
# raise Http404(_('Invalid hostname'))
log.debug(LOG_TEMPLATE.format(
msg='Allowing long domain name', **log_kwargs
))
# Normal request.
return None

Expand Down
47 changes: 25 additions & 22 deletions readthedocs/rtd_tests/tests/test_middleware.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

from django.http import Http404
from django.conf import settings
from django.core.cache import cache
from django.core.urlresolvers import get_urlconf, set_urlconf
from django.test import TestCase
from django.test.client import RequestFactory
Expand All @@ -13,7 +12,8 @@
from django_dynamic_fixture import get

from corsheaders.middleware import CorsMiddleware
from mock import patch
import pytest


from readthedocs.core.middleware import SubdomainMiddleware
from readthedocs.projects.models import Project, ProjectRelationship, Domain
Expand All @@ -31,9 +31,15 @@ def setUp(self):
self.middleware = SubdomainMiddleware()
self.url = '/'
self.owner = create_user(username='owner', password='test')
self.pip = get(Project, slug='pip', users=[self.owner], privacy_level='public')
self.pip = get(
Project,
slug='pip',
users=[self.owner],
privacy_level='public'
)

def test_failey_cname(self):
self.assertFalse(Domain.objects.filter(domain='my.host.com').exists())
request = self.factory.get(self.url, HTTP_HOST='my.host.com')
with self.assertRaises(Http404):
self.middleware.process_request(request)
Expand Down Expand Up @@ -72,7 +78,9 @@ def test_restore_urlconf_after_request(self):

@override_settings(PRODUCTION_DOMAIN='prod.readthedocs.org')
def test_subdomain_different_length(self):
request = self.factory.get(self.url, HTTP_HOST='pip.prod.readthedocs.org')
request = self.factory.get(
self.url, HTTP_HOST='pip.prod.readthedocs.org'
)
self.middleware.process_request(request)
self.assertEqual(request.urlconf, self.urlconf_subdomain)
self.assertEqual(request.subdomain, True)
Expand All @@ -93,16 +101,10 @@ def test_domain_object_missing(self):
with self.assertRaises(Http404):
self.middleware.process_request(request)

def test_proper_cname(self):
cache.get = lambda x: 'my_slug'
request = self.factory.get(self.url, HTTP_HOST='my.valid.homename')
self.middleware.process_request(request)
self.assertEqual(request.urlconf, self.urlconf_subdomain)
self.assertEqual(request.cname, True)
self.assertEqual(request.slug, 'my_slug')

def test_request_header(self):
request = self.factory.get(self.url, HTTP_HOST='some.random.com', HTTP_X_RTD_SLUG='pip')
request = self.factory.get(
self.url, HTTP_HOST='some.random.com', HTTP_X_RTD_SLUG='pip'
)
self.middleware.process_request(request)
self.assertEqual(request.urlconf, self.urlconf_subdomain)
self.assertEqual(request.cname, True)
Expand All @@ -111,28 +113,29 @@ def test_request_header(self):

@override_settings(PRODUCTION_DOMAIN='readthedocs.org')
def test_proper_cname_uppercase(self):
cache.get = lambda x: x.split('.')[0]
get(Domain, project=self.pip, domain='pip.random.com')
request = self.factory.get(self.url, HTTP_HOST='PIP.RANDOM.COM')
self.middleware.process_request(request)
self.assertEqual(request.urlconf, self.urlconf_subdomain)
self.assertEqual(request.cname, True)
self.assertEqual(request.slug, 'pip')

def test_request_header_uppercase(self):
request = self.factory.get(self.url, HTTP_HOST='some.random.com', HTTP_X_RTD_SLUG='PIP')
request = self.factory.get(
self.url, HTTP_HOST='some.random.com', HTTP_X_RTD_SLUG='PIP'
)
self.middleware.process_request(request)
self.assertEqual(request.urlconf, self.urlconf_subdomain)
self.assertEqual(request.cname, True)
self.assertEqual(request.rtdheader, True)
self.assertEqual(request.slug, 'pip')

@override_settings(USE_SUBDOMAIN=True)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We already put this on the class

# no need to do a real dns query so patch cname_to_slug
@patch('readthedocs.core.middleware.cname_to_slug', new=lambda x: 'doesnt')
def test_use_subdomain_on(self):
request = self.factory.get(self.url, HTTP_HOST='doesnt.really.matter')
ret_val = self.middleware.process_request(request)
self.assertIsNone(ret_val, None)
def test_use_subdomain(self):
domain = 'doesnt.exists.org'
get(Domain, project=self.pip, domain=domain)
request = self.factory.get(self.url, HTTP_HOST=domain)
res = self.middleware.process_request(request)
self.assertIsNone(res)


class TestCORSMiddleware(TestCase):
Expand Down