Beispiel #1
0
    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
Beispiel #2
0
    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)
Beispiel #3
0
    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)
Beispiel #4
0
    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,
        )