def cname(request): """ Get the slug that a particular hostname resolves to. This is useful for debugging your DNS settings, or for getting the backing project name on Read the Docs for a URL. Example:: GET https://readthedocs.org/api/v2/cname/?host=docs.python-requests.org This will return information about ``docs.python-requests.org`` """ host = request.GET.get('host') if not host: return Response({'error': 'host GET arg required'}, status=status.HTTP_400_BAD_REQUEST) host = clean_url(host) slug = cname_to_slug(host) return Response({ 'host': host, 'slug': slug, })
def process_request(self, request): """Process requests for unhandled domains If the request is not for our ``PUBLIC_DOMAIN``, or if ``PUBLIC_DOMAIN`` is not set and the request is for a subdomain on ``PRODUCTION_DOMAIN``, process the request as a request a documentation project. """ if not getattr(settings, 'USE_SUBDOMAIN', False): return None full_host = host = request.get_host().lower() path = request.get_full_path() log_kwargs = dict(host=host, path=path) public_domain = getattr(settings, 'PUBLIC_DOMAIN', None) production_domain = getattr(settings, 'PRODUCTION_DOMAIN', 'readthedocs.org') if public_domain is None: public_domain = production_domain if ':' in host: host = host.split(':')[0] domain_parts = host.split('.') # Serve subdomains - but don't depend on the production domain only having 2 parts if len(domain_parts) == len(public_domain.split('.')) + 1: subdomain = domain_parts[0] is_www = subdomain.lower() == 'www' if not is_www and ( # Support ports during local dev public_domain in host or public_domain in full_host): request.subdomain = True request.slug = subdomain request.urlconf = SUBDOMAIN_URLCONF return None # Serve CNAMEs if (public_domain not in host and production_domain not in host and 'localhost' not in host and 'testserver' not in host): request.cname = True domains = Domain.objects.filter(domain=host) if domains.count(): for domain in domains: if domain.domain == host: request.slug = domain.project.slug request.urlconf = SUBDOMAIN_URLCONF request.domain_object = True log.debug( LOG_TEMPLATE.format( msg='Domain Object Detected: %s' % domain.domain, **log_kwargs)) break if (not hasattr(request, 'domain_object') and 'HTTP_X_RTD_SLUG' in request.META): request.slug = request.META['HTTP_X_RTD_SLUG'].lower() request.urlconf = SUBDOMAIN_URLCONF request.rtdheader = True log.debug( LOG_TEMPLATE.format(msg='X-RTD-Slug header detected: %s' % request.slug, **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: # Some crazy person is CNAMEing to us. 404. log.exception( 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)) return HttpResponseBadRequest(_('Invalid hostname')) log.debug( LOG_TEMPLATE.format(msg='Allowing long domain name', **log_kwargs)) # raise Http404(_('Invalid hostname')) # Normal request. return None
def process_request(self, request): """ Process requests for unhandled domains. If the request is not for our ``PUBLIC_DOMAIN``, or if ``PUBLIC_DOMAIN`` is not set and the request is for a subdomain on ``PRODUCTION_DOMAIN``, process the request as a request a documentation project. """ if not getattr(settings, 'USE_SUBDOMAIN', False): return None full_host = host = request.get_host().lower() path = request.get_full_path() log_kwargs = dict(host=host, path=path) public_domain = getattr(settings, 'PUBLIC_DOMAIN', None) production_domain = getattr( settings, 'PRODUCTION_DOMAIN', 'readthedocs.org' ) if public_domain is None: public_domain = production_domain if ':' in host: host = host.split(':')[0] domain_parts = host.split('.') # Serve subdomains - but don't depend on the production domain only having 2 parts if len(domain_parts) == len(public_domain.split('.')) + 1: subdomain = domain_parts[0] is_www = subdomain.lower() == 'www' if not is_www and ( # Support ports during local dev public_domain in host or public_domain in full_host ): request.subdomain = True request.slug = subdomain request.urlconf = SUBDOMAIN_URLCONF return None # Serve CNAMEs if (public_domain not in host and production_domain not in host and 'localhost' not in host and 'testserver' not in host): request.cname = True domains = Domain.objects.filter(domain=host) if domains.count(): for domain in domains: if domain.domain == host: request.slug = domain.project.slug request.urlconf = SUBDOMAIN_URLCONF request.domain_object = True log.debug(LOG_TEMPLATE.format( msg='Domain Object Detected: %s' % domain.domain, **log_kwargs)) break if (not hasattr(request, 'domain_object') and 'HTTP_X_RTD_SLUG' in request.META): request.slug = request.META['HTTP_X_RTD_SLUG'].lower() request.urlconf = SUBDOMAIN_URLCONF request.rtdheader = True log.debug(LOG_TEMPLATE.format( msg='X-RTD-Slug header detected: %s' % request.slug, **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: # Some crazy person is CNAMEing to us. 404. log.exception(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)) return HttpResponseBadRequest(_('Invalid hostname')) log.debug(LOG_TEMPLATE.format(msg='Allowing long domain name', **log_kwargs)) # raise Http404(_('Invalid hostname')) # Normal request. return None