def _version_same_domain_url( self, request, type_, lang_slug, version_slug, subproject_slug=None, ): """ Return the version to be served (new-style URLs). It uses the request to get the ``project``. The rest of arguments come from the URL. """ final_project, lang_slug, version_slug, filename = _get_project_data_from_request( # noqa request, project_slug=None, subproject_slug=subproject_slug, lang_slug=lang_slug, version_slug=version_slug, ) version = get_object_or_404( final_project.versions.public(user=request.user), slug=version_slug, ) return version
def unresolve(self, url): """ Turn a URL into the component parts that our views would use to process them. This is useful for lots of places, like where we want to figure out exactly what file a URL maps to. """ parsed = urlparse(url) domain = parsed.netloc.split(':', 1)[0] path = parsed.path # TODO: Make this not depend on the request object, # but instead move all this logic here working on strings. request = RequestFactory().get(path=path, HTTP_HOST=domain) project_slug = request.host_project_slug = map_host_to_project_slug(request) # Handle returning a response if hasattr(project_slug, 'status_code'): return None _, __, kwargs = url_resolve( path, urlconf='readthedocs.proxito.urls', ) mixin = ServeDocsMixin() version_slug = mixin.get_version_from_host(request, kwargs.get('version_slug')) final_project, lang_slug, version_slug, filename = _get_project_data_from_request( # noqa request, project_slug=project_slug, subproject_slug=kwargs.get('subproject_slug'), lang_slug=kwargs.get('lang_slug'), version_slug=version_slug, filename=kwargs.get('filename', ''), ) # Handle our backend storage not supporting directory indexes, # so we need to append index.html when appropriate. if not filename or filename.endswith('/'): # We need to add the index.html to find this actual file filename += 'index.html' log.info( 'Unresolver parsed: ' 'url=%s project=%s lang_slug=%s version_slug=%s filename=%s', url, final_project.slug, lang_slug, version_slug, filename ) return UnresolvedObject(final_project, lang_slug, version_slug, filename, parsed.fragment)
def unresolve_from_request(self, request, path): """ Unresolve using a request. ``path`` can be a full URL, but the domain will be ignored, since that information is already in the request object. None is returned if the request isn't valid. """ parsed = urlparse(path) path = parsed.path project_slug = getattr(request, 'host_project_slug', None) if not project_slug: return None _, __, kwargs = url_resolve( path, urlconf='readthedocs.proxito.urls', ) mixin = ServeDocsMixin() version_slug = mixin.get_version_from_host(request, kwargs.get('version_slug')) final_project, lang_slug, version_slug, filename = _get_project_data_from_request( # noqa request, project_slug=project_slug, subproject_slug=kwargs.get('subproject_slug'), lang_slug=kwargs.get('lang_slug'), version_slug=version_slug, filename=kwargs.get('filename', ''), ) # Handle our backend storage not supporting directory indexes, # so we need to append index.html when appropriate. if not filename or filename.endswith('/'): # We need to add the index.html to find this actual file filename += 'index.html' log.debug( 'Unresolver parsed.', project_slug=final_project.slug, lang_slug=lang_slug, version_slug=version_slug, filename=filename, ) return UnresolvedObject(final_project, lang_slug, version_slug, filename, parsed.fragment)
def get( self, request, project_slug=None, type_=None, version_slug=None, lang_slug=None, subproject_slug=None, ): """ Download a specific piece of media. Perform an auth check if serving in private mode. This view is used to download a file using old-style URLs (download from the dashboard) and new-style URLs (download from the same domain as docs). Basically, the parameters received by the GET view are different (``project_slug`` does not come in the new-style URLs, for example) and we need to take it from the request. Once we get the final ``version`` to be served, everything is the same for both paths. .. warning:: This is linked directly from the HTML pages. It should only care about the Version permissions, not the actual Project permissions. """ if self.same_domain_url: # It uses the request to get the ``project``. The rest of arguments come # from the URL. final_project, lang_slug, version_slug, filename = _get_project_data_from_request( # noqa request, project_slug=None, subproject_slug=subproject_slug, lang_slug=lang_slug, version_slug=version_slug, ) if not self.allowed_user(request, final_project, version_slug): return self.get_unauthed_response(request, final_project) # We don't use ``.public`` in this filter because the access # permission was already granted by ``.allowed_user`` version = get_object_or_404( final_project.versions, slug=version_slug, ) else: # All the arguments come from the URL. version = get_object_or_404( Version.objects.public(user=request.user), project__slug=project_slug, slug=version_slug, ) # Send media download to analytics - sensitive data is anonymized analytics_event.delay( event_category='Build Media', event_action=f'Download {type_}', event_label=str(version), ua=request.META.get('HTTP_USER_AGENT'), uip=get_client_ip(request), ) storage = get_storage_class(settings.RTD_BUILD_MEDIA_STORAGE)() storage_path = version.project.get_storage_path( type_=type_, version_slug=version_slug, version_type=version.type, ) # URL without scheme and domain to perform an NGINX internal redirect url = storage.url(storage_path) url = urlparse(url)._replace(scheme='', netloc='').geturl() return self._serve_docs( request, final_project=version.project, version_slug=version.slug, path=url, download=True, )