We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
subproject alias 302 redirect to top-level project sharing alias' name
## Details
I have set up a subproject,
Subproject: cloudify-openstack-plugin-fh
Alias: openstack

* Project URL: http://cfy-rtd-demo.readthedocs.io/
* Build URL (if applicable): https://readthedocs.org/projects/cfy-rtd-demo/builds/5162299/
* Read the Docs username (if applicable): funkyhat

## Expected Result
When navigating to http://cfy-rtd-demo.readthedocs.io/projects/openstack

I expect to see (presumably via a redirect to http://cfy-rtd-demo.readthedocs.io/projects/openstack/en/sphinxify-rtd-demo/) my subproject's docs (`sphinxify-rtd-demo` is the current "active branch" for the subproject).

## Actual Result
I am redirected to http://openstack.readthedocs.io/en/latest/ which is unrelated to my project:
```
< HTTP/1.1 302 Found
* Server nginx/1.10.0 (Ubuntu) is not blacklisted
< Server: nginx/1.10.0 (Ubuntu)
< Date: Fri, 17 Mar 2017 13:00:04 GMT
< Content-Type: text/html; charset=utf-8
< Transfer-Encoding: chunked
< Connection: keep-alive
< Vary: Accept-Language, Cookie
< Location: http://openstack.readthedocs.io/en/latest/
< Content-Language: en
< X-Fallback: True
< X-Served: Django
< X-Deity: web03
```

I have tried rebuilding the main project, which produced no change.

This seems potentially related to #1602 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `readthedocs/core/views/serve.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 """
3 Doc serving from Python.
4 
5 In production there are two modes,
6 * Serving from public symlinks in nginx (readthedocs.org & readthedocs.com)
7 * Serving from private symlinks in Python (readthedocs.com only)
8 
9 In development, we have two modes:
10 * Serving from public symlinks in Python
11 * Serving from private symlinks in Python
12 
13 This means we should only serve from public symlinks in dev,
14 and generally default to serving from private symlinks in Python only.
15 
16 Privacy
17 -------
18 
19 These views will take into account the version privacy level.
20 
21 Settings
22 --------
23 
24 PYTHON_MEDIA (False) - Set this to True to serve docs & media from Python
25 SERVE_DOCS (['private']) - The list of ['private', 'public'] docs to serve.
26 """
27 
28 from __future__ import (
29     absolute_import, division, print_function, unicode_literals)
30 
31 import logging
32 import mimetypes
33 import os
34 from functools import wraps
35 
36 from django.conf import settings
37 from django.http import Http404, HttpResponse, HttpResponseRedirect
38 from django.shortcuts import render
39 from django.views.static import serve
40 
41 from readthedocs.builds.models import Version
42 from readthedocs.core.permissions import AdminPermission
43 from readthedocs.core.resolver import resolve, resolve_path
44 from readthedocs.core.symlink import PrivateSymlink, PublicSymlink
45 from readthedocs.projects import constants
46 from readthedocs.projects.models import Project, ProjectRelationship
47 
48 log = logging.getLogger(__name__)
49 
50 
51 def map_subproject_slug(view_func):
52     """
53     A decorator that maps a ``subproject_slug`` URL param into a Project.
54 
55     :raises: Http404 if the Project doesn't exist
56 
57     .. warning:: Does not take into account any kind of privacy settings.
58     """
59     @wraps(view_func)
60     def inner_view(
61             request, subproject=None, subproject_slug=None, *args, **kwargs):
62         if subproject is None and subproject_slug:
63             try:
64                 subproject = Project.objects.get(slug=subproject_slug)
65             except Project.DoesNotExist:
66                 try:
67                     # Depends on a project passed into kwargs
68                     rel = ProjectRelationship.objects.get(
69                         parent=kwargs['project'],
70                         alias=subproject_slug,
71                     )
72                     subproject = rel.child
73                 except (ProjectRelationship.DoesNotExist, KeyError):
74                     raise Http404
75         return view_func(request, subproject=subproject, *args, **kwargs)
76 
77     return inner_view
78 
79 
80 def map_project_slug(view_func):
81     """
82     A decorator that maps a ``project_slug`` URL param into a Project.
83 
84     :raises: Http404 if the Project doesn't exist
85 
86     .. warning:: Does not take into account any kind of privacy settings.
87     """
88     @wraps(view_func)
89     def inner_view(request, project=None, project_slug=None, *args, **kwargs):
90         if project is None:
91             if not project_slug:
92                 project_slug = request.slug
93             try:
94                 project = Project.objects.get(slug=project_slug)
95             except Project.DoesNotExist:
96                 raise Http404('Project does not exist.')
97         return view_func(request, project=project, *args, **kwargs)
98 
99     return inner_view
100 
101 
102 @map_project_slug
103 @map_subproject_slug
104 def redirect_project_slug(request, project, subproject):  # pylint: disable=unused-argument
105     """Handle / -> /en/latest/ directs on subdomains."""
106     return HttpResponseRedirect(resolve(subproject or project))
107 
108 
109 @map_project_slug
110 @map_subproject_slug
111 def redirect_page_with_filename(request, project, subproject, filename):  # pylint: disable=unused-argument  # noqa
112     """Redirect /page/file.html to /en/latest/file.html."""
113     return HttpResponseRedirect(
114         resolve(subproject or project, filename=filename))
115 
116 
117 def _serve_401(request, project):
118     res = render(request, '401.html')
119     res.status_code = 401
120     log.error('Unauthorized access to {0} documentation'.format(project.slug))
121     return res
122 
123 
124 def _serve_file(request, filename, basepath):
125     # Serve the file from the proper location
126     if settings.DEBUG or getattr(settings, 'PYTHON_MEDIA', False):
127         # Serve from Python
128         return serve(request, filename, basepath)
129     else:
130         # Serve from Nginx
131         content_type, encoding = mimetypes.guess_type(
132             os.path.join(basepath, filename))
133         content_type = content_type or 'application/octet-stream'
134         response = HttpResponse(content_type=content_type)
135         if encoding:
136             response['Content-Encoding'] = encoding
137         try:
138             response['X-Accel-Redirect'] = os.path.join(
139                 basepath[len(settings.SITE_ROOT):],
140                 filename,
141             )
142         except UnicodeEncodeError:
143             raise Http404
144 
145         return response
146 
147 
148 @map_project_slug
149 @map_subproject_slug
150 def serve_docs(
151         request, project, subproject, lang_slug=None, version_slug=None,
152         filename=''):
153     """Exists to map existing proj, lang, version, filename views to the file format."""
154     if not version_slug:
155         version_slug = project.get_default_version()
156     try:
157         version = project.versions.public(request.user).get(slug=version_slug)
158     except Version.DoesNotExist:
159         # Properly raise a 404 if the version doesn't exist & a 401 if it does
160         if project.versions.filter(slug=version_slug).exists():
161             return _serve_401(request, project)
162         raise Http404('Version does not exist.')
163     filename = resolve_path(
164         subproject or project,  # Resolve the subproject if it exists
165         version_slug=version_slug,
166         language=lang_slug,
167         filename=filename,
168         subdomain=True,  # subdomain will make it a "full" path without a URL prefix
169     )
170     if (version.privacy_level == constants.PRIVATE and
171             not AdminPermission.is_member(user=request.user, obj=project)):
172         return _serve_401(request, project)
173     return _serve_symlink_docs(
174         request,
175         filename=filename,
176         project=project,
177         privacy_level=version.privacy_level,
178     )
179 
180 
181 @map_project_slug
182 def _serve_symlink_docs(request, project, privacy_level, filename=''):
183     """Serve a file by symlink, or a 404 if not found."""
184     # Handle indexes
185     if filename == '' or filename[-1] == '/':
186         filename += 'index.html'
187 
188     # This breaks path joining, by ignoring the root when given an "absolute" path
189     if filename[0] == '/':
190         filename = filename[1:]
191 
192     log.info('Serving %s for %s', filename, project)
193 
194     files_tried = []
195 
196     serve_docs = getattr(settings, 'SERVE_DOCS', [constants.PRIVATE])
197 
198     if (settings.DEBUG or constants.PUBLIC in serve_docs) and privacy_level != constants.PRIVATE:  # yapf: disable  # noqa
199         public_symlink = PublicSymlink(project)
200         basepath = public_symlink.project_root
201         if os.path.exists(os.path.join(basepath, filename)):
202             return _serve_file(request, filename, basepath)
203         else:
204             files_tried.append(os.path.join(basepath, filename))
205 
206     if (settings.DEBUG or constants.PRIVATE in serve_docs) and privacy_level == constants.PRIVATE:  # yapf: disable  # noqa
207         # Handle private
208         private_symlink = PrivateSymlink(project)
209         basepath = private_symlink.project_root
210 
211         if os.path.exists(os.path.join(basepath, filename)):
212             return _serve_file(request, filename, basepath)
213         else:
214             files_tried.append(os.path.join(basepath, filename))
215 
216     raise Http404(
217         'File not found. Tried these files: %s' % ','.join(files_tried))
218
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/readthedocs/core/views/serve.py b/readthedocs/core/views/serve.py
--- a/readthedocs/core/views/serve.py
+++ b/readthedocs/core/views/serve.py
@@ -34,7 +34,8 @@
 from functools import wraps
 
 from django.conf import settings
-from django.http import Http404, HttpResponse, HttpResponseRedirect
+from django.http import HttpResponse, HttpResponseRedirect, Http404
+from django.shortcuts import get_object_or_404
 from django.shortcuts import render
 from django.views.static import serve
 
@@ -60,18 +61,17 @@
     def inner_view(
             request, subproject=None, subproject_slug=None, *args, **kwargs):
         if subproject is None and subproject_slug:
+            # Try to fetch by subproject alias first, otherwise we might end up
+            # redirected to an unrelated project.
             try:
-                subproject = Project.objects.get(slug=subproject_slug)
-            except Project.DoesNotExist:
-                try:
-                    # Depends on a project passed into kwargs
-                    rel = ProjectRelationship.objects.get(
-                        parent=kwargs['project'],
-                        alias=subproject_slug,
-                    )
-                    subproject = rel.child
-                except (ProjectRelationship.DoesNotExist, KeyError):
-                    raise Http404
+                # Depends on a project passed into kwargs
+                rel = ProjectRelationship.objects.get(
+                    parent=kwargs['project'],
+                    alias=subproject_slug,
+                )
+                subproject = rel.child
+            except (ProjectRelationship.DoesNotExist, KeyError):
+                get_object_or_404(Project, slug=subproject_slug)
         return view_func(request, subproject=subproject, *args, **kwargs)
 
     return inner_view

{"golden_diff": "diff --git a/readthedocs/core/views/serve.py b/readthedocs/core/views/serve.py\n--- a/readthedocs/core/views/serve.py\n+++ b/readthedocs/core/views/serve.py\n@@ -34,7 +34,8 @@\n from functools import wraps\n \n from django.conf import settings\n-from django.http import Http404, HttpResponse, HttpResponseRedirect\n+from django.http import HttpResponse, HttpResponseRedirect, Http404\n+from django.shortcuts import get_object_or_404\n from django.shortcuts import render\n from django.views.static import serve\n \n@@ -60,18 +61,17 @@\n     def inner_view(\n             request, subproject=None, subproject_slug=None, *args, **kwargs):\n         if subproject is None and subproject_slug:\n+            # Try to fetch by subproject alias first, otherwise we might end up\n+            # redirected to an unrelated project.\n             try:\n-                subproject = Project.objects.get(slug=subproject_slug)\n-            except Project.DoesNotExist:\n-                try:\n-                    # Depends on a project passed into kwargs\n-                    rel = ProjectRelationship.objects.get(\n-                        parent=kwargs['project'],\n-                        alias=subproject_slug,\n-                    )\n-                    subproject = rel.child\n-                except (ProjectRelationship.DoesNotExist, KeyError):\n-                    raise Http404\n+                # Depends on a project passed into kwargs\n+                rel = ProjectRelationship.objects.get(\n+                    parent=kwargs['project'],\n+                    alias=subproject_slug,\n+                )\n+                subproject = rel.child\n+            except (ProjectRelationship.DoesNotExist, KeyError):\n+                get_object_or_404(Project, slug=subproject_slug)\n         return view_func(request, subproject=subproject, *args, **kwargs)\n \n     return inner_view\n", "issue": "subproject alias 302 redirect to top-level project sharing alias' name\n## Details\r\nI have set up a subproject,\r\nSubproject: cloudify-openstack-plugin-fh\r\nAlias: openstack\r\n\r\n* Project URL: http://cfy-rtd-demo.readthedocs.io/\r\n* Build URL (if applicable): https://readthedocs.org/projects/cfy-rtd-demo/builds/5162299/\r\n* Read the Docs username (if applicable): funkyhat\r\n\r\n## Expected Result\r\nWhen navigating to http://cfy-rtd-demo.readthedocs.io/projects/openstack\r\n\r\nI expect to see (presumably via a redirect to http://cfy-rtd-demo.readthedocs.io/projects/openstack/en/sphinxify-rtd-demo/) my subproject's docs (`sphinxify-rtd-demo` is the current \"active branch\" for the subproject).\r\n\r\n## Actual Result\r\nI am redirected to http://openstack.readthedocs.io/en/latest/ which is unrelated to my project:\r\n```\r\n< HTTP/1.1 302 Found\r\n* Server nginx/1.10.0 (Ubuntu) is not blacklisted\r\n< Server: nginx/1.10.0 (Ubuntu)\r\n< Date: Fri, 17 Mar 2017 13:00:04 GMT\r\n< Content-Type: text/html; charset=utf-8\r\n< Transfer-Encoding: chunked\r\n< Connection: keep-alive\r\n< Vary: Accept-Language, Cookie\r\n< Location: http://openstack.readthedocs.io/en/latest/\r\n< Content-Language: en\r\n< X-Fallback: True\r\n< X-Served: Django\r\n< X-Deity: web03\r\n```\r\n\r\nI have tried rebuilding the main project, which produced no change.\r\n\r\nThis seems potentially related to #1602 \n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nDoc serving from Python.\n\nIn production there are two modes,\n* Serving from public symlinks in nginx (readthedocs.org & readthedocs.com)\n* Serving from private symlinks in Python (readthedocs.com only)\n\nIn development, we have two modes:\n* Serving from public symlinks in Python\n* Serving from private symlinks in Python\n\nThis means we should only serve from public symlinks in dev,\nand generally default to serving from private symlinks in Python only.\n\nPrivacy\n-------\n\nThese views will take into account the version privacy level.\n\nSettings\n--------\n\nPYTHON_MEDIA (False) - Set this to True to serve docs & media from Python\nSERVE_DOCS (['private']) - The list of ['private', 'public'] docs to serve.\n\"\"\"\n\nfrom __future__ import (\n    absolute_import, division, print_function, unicode_literals)\n\nimport logging\nimport mimetypes\nimport os\nfrom functools import wraps\n\nfrom django.conf import settings\nfrom django.http import Http404, HttpResponse, HttpResponseRedirect\nfrom django.shortcuts import render\nfrom django.views.static import serve\n\nfrom readthedocs.builds.models import Version\nfrom readthedocs.core.permissions import AdminPermission\nfrom readthedocs.core.resolver import resolve, resolve_path\nfrom readthedocs.core.symlink import PrivateSymlink, PublicSymlink\nfrom readthedocs.projects import constants\nfrom readthedocs.projects.models import Project, ProjectRelationship\n\nlog = logging.getLogger(__name__)\n\n\ndef map_subproject_slug(view_func):\n    \"\"\"\n    A decorator that maps a ``subproject_slug`` URL param into a Project.\n\n    :raises: Http404 if the Project doesn't exist\n\n    .. warning:: Does not take into account any kind of privacy settings.\n    \"\"\"\n    @wraps(view_func)\n    def inner_view(\n            request, subproject=None, subproject_slug=None, *args, **kwargs):\n        if subproject is None and subproject_slug:\n            try:\n                subproject = Project.objects.get(slug=subproject_slug)\n            except Project.DoesNotExist:\n                try:\n                    # Depends on a project passed into kwargs\n                    rel = ProjectRelationship.objects.get(\n                        parent=kwargs['project'],\n                        alias=subproject_slug,\n                    )\n                    subproject = rel.child\n                except (ProjectRelationship.DoesNotExist, KeyError):\n                    raise Http404\n        return view_func(request, subproject=subproject, *args, **kwargs)\n\n    return inner_view\n\n\ndef map_project_slug(view_func):\n    \"\"\"\n    A decorator that maps a ``project_slug`` URL param into a Project.\n\n    :raises: Http404 if the Project doesn't exist\n\n    .. warning:: Does not take into account any kind of privacy settings.\n    \"\"\"\n    @wraps(view_func)\n    def inner_view(request, project=None, project_slug=None, *args, **kwargs):\n        if project is None:\n            if not project_slug:\n                project_slug = request.slug\n            try:\n                project = Project.objects.get(slug=project_slug)\n            except Project.DoesNotExist:\n                raise Http404('Project does not exist.')\n        return view_func(request, project=project, *args, **kwargs)\n\n    return inner_view\n\n\n@map_project_slug\n@map_subproject_slug\ndef redirect_project_slug(request, project, subproject):  # pylint: disable=unused-argument\n    \"\"\"Handle / -> /en/latest/ directs on subdomains.\"\"\"\n    return HttpResponseRedirect(resolve(subproject or project))\n\n\n@map_project_slug\n@map_subproject_slug\ndef redirect_page_with_filename(request, project, subproject, filename):  # pylint: disable=unused-argument  # noqa\n    \"\"\"Redirect /page/file.html to /en/latest/file.html.\"\"\"\n    return HttpResponseRedirect(\n        resolve(subproject or project, filename=filename))\n\n\ndef _serve_401(request, project):\n    res = render(request, '401.html')\n    res.status_code = 401\n    log.error('Unauthorized access to {0} documentation'.format(project.slug))\n    return res\n\n\ndef _serve_file(request, filename, basepath):\n    # Serve the file from the proper location\n    if settings.DEBUG or getattr(settings, 'PYTHON_MEDIA', False):\n        # Serve from Python\n        return serve(request, filename, basepath)\n    else:\n        # Serve from Nginx\n        content_type, encoding = mimetypes.guess_type(\n            os.path.join(basepath, filename))\n        content_type = content_type or 'application/octet-stream'\n        response = HttpResponse(content_type=content_type)\n        if encoding:\n            response['Content-Encoding'] = encoding\n        try:\n            response['X-Accel-Redirect'] = os.path.join(\n                basepath[len(settings.SITE_ROOT):],\n                filename,\n            )\n        except UnicodeEncodeError:\n            raise Http404\n\n        return response\n\n\n@map_project_slug\n@map_subproject_slug\ndef serve_docs(\n        request, project, subproject, lang_slug=None, version_slug=None,\n        filename=''):\n    \"\"\"Exists to map existing proj, lang, version, filename views to the file format.\"\"\"\n    if not version_slug:\n        version_slug = project.get_default_version()\n    try:\n        version = project.versions.public(request.user).get(slug=version_slug)\n    except Version.DoesNotExist:\n        # Properly raise a 404 if the version doesn't exist & a 401 if it does\n        if project.versions.filter(slug=version_slug).exists():\n            return _serve_401(request, project)\n        raise Http404('Version does not exist.')\n    filename = resolve_path(\n        subproject or project,  # Resolve the subproject if it exists\n        version_slug=version_slug,\n        language=lang_slug,\n        filename=filename,\n        subdomain=True,  # subdomain will make it a \"full\" path without a URL prefix\n    )\n    if (version.privacy_level == constants.PRIVATE and\n            not AdminPermission.is_member(user=request.user, obj=project)):\n        return _serve_401(request, project)\n    return _serve_symlink_docs(\n        request,\n        filename=filename,\n        project=project,\n        privacy_level=version.privacy_level,\n    )\n\n\n@map_project_slug\ndef _serve_symlink_docs(request, project, privacy_level, filename=''):\n    \"\"\"Serve a file by symlink, or a 404 if not found.\"\"\"\n    # Handle indexes\n    if filename == '' or filename[-1] == '/':\n        filename += 'index.html'\n\n    # This breaks path joining, by ignoring the root when given an \"absolute\" path\n    if filename[0] == '/':\n        filename = filename[1:]\n\n    log.info('Serving %s for %s', filename, project)\n\n    files_tried = []\n\n    serve_docs = getattr(settings, 'SERVE_DOCS', [constants.PRIVATE])\n\n    if (settings.DEBUG or constants.PUBLIC in serve_docs) and privacy_level != constants.PRIVATE:  # yapf: disable  # noqa\n        public_symlink = PublicSymlink(project)\n        basepath = public_symlink.project_root\n        if os.path.exists(os.path.join(basepath, filename)):\n            return _serve_file(request, filename, basepath)\n        else:\n            files_tried.append(os.path.join(basepath, filename))\n\n    if (settings.DEBUG or constants.PRIVATE in serve_docs) and privacy_level == constants.PRIVATE:  # yapf: disable  # noqa\n        # Handle private\n        private_symlink = PrivateSymlink(project)\n        basepath = private_symlink.project_root\n\n        if os.path.exists(os.path.join(basepath, filename)):\n            return _serve_file(request, filename, basepath)\n        else:\n            files_tried.append(os.path.join(basepath, filename))\n\n    raise Http404(\n        'File not found. Tried these files: %s' % ','.join(files_tried))\n", "path": "readthedocs/core/views/serve.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\"\"\"\nDoc serving from Python.\n\nIn production there are two modes,\n* Serving from public symlinks in nginx (readthedocs.org & readthedocs.com)\n* Serving from private symlinks in Python (readthedocs.com only)\n\nIn development, we have two modes:\n* Serving from public symlinks in Python\n* Serving from private symlinks in Python\n\nThis means we should only serve from public symlinks in dev,\nand generally default to serving from private symlinks in Python only.\n\nPrivacy\n-------\n\nThese views will take into account the version privacy level.\n\nSettings\n--------\n\nPYTHON_MEDIA (False) - Set this to True to serve docs & media from Python\nSERVE_DOCS (['private']) - The list of ['private', 'public'] docs to serve.\n\"\"\"\n\nfrom __future__ import (\n    absolute_import, division, print_function, unicode_literals)\n\nimport logging\nimport mimetypes\nimport os\nfrom functools import wraps\n\nfrom django.conf import settings\nfrom django.http import HttpResponse, HttpResponseRedirect, Http404\nfrom django.shortcuts import get_object_or_404\nfrom django.shortcuts import render\nfrom django.views.static import serve\n\nfrom readthedocs.builds.models import Version\nfrom readthedocs.core.permissions import AdminPermission\nfrom readthedocs.core.resolver import resolve, resolve_path\nfrom readthedocs.core.symlink import PrivateSymlink, PublicSymlink\nfrom readthedocs.projects import constants\nfrom readthedocs.projects.models import Project, ProjectRelationship\n\nlog = logging.getLogger(__name__)\n\n\ndef map_subproject_slug(view_func):\n    \"\"\"\n    A decorator that maps a ``subproject_slug`` URL param into a Project.\n\n    :raises: Http404 if the Project doesn't exist\n\n    .. warning:: Does not take into account any kind of privacy settings.\n    \"\"\"\n    @wraps(view_func)\n    def inner_view(\n            request, subproject=None, subproject_slug=None, *args, **kwargs):\n        if subproject is None and subproject_slug:\n            # Try to fetch by subproject alias first, otherwise we might end up\n            # redirected to an unrelated project.\n            try:\n                # Depends on a project passed into kwargs\n                rel = ProjectRelationship.objects.get(\n                    parent=kwargs['project'],\n                    alias=subproject_slug,\n                )\n                subproject = rel.child\n            except (ProjectRelationship.DoesNotExist, KeyError):\n                get_object_or_404(Project, slug=subproject_slug)\n        return view_func(request, subproject=subproject, *args, **kwargs)\n\n    return inner_view\n\n\ndef map_project_slug(view_func):\n    \"\"\"\n    A decorator that maps a ``project_slug`` URL param into a Project.\n\n    :raises: Http404 if the Project doesn't exist\n\n    .. warning:: Does not take into account any kind of privacy settings.\n    \"\"\"\n    @wraps(view_func)\n    def inner_view(request, project=None, project_slug=None, *args, **kwargs):\n        if project is None:\n            if not project_slug:\n                project_slug = request.slug\n            try:\n                project = Project.objects.get(slug=project_slug)\n            except Project.DoesNotExist:\n                raise Http404('Project does not exist.')\n        return view_func(request, project=project, *args, **kwargs)\n\n    return inner_view\n\n\n@map_project_slug\n@map_subproject_slug\ndef redirect_project_slug(request, project, subproject):  # pylint: disable=unused-argument\n    \"\"\"Handle / -> /en/latest/ directs on subdomains.\"\"\"\n    return HttpResponseRedirect(resolve(subproject or project))\n\n\n@map_project_slug\n@map_subproject_slug\ndef redirect_page_with_filename(request, project, subproject, filename):  # pylint: disable=unused-argument  # noqa\n    \"\"\"Redirect /page/file.html to /en/latest/file.html.\"\"\"\n    return HttpResponseRedirect(\n        resolve(subproject or project, filename=filename))\n\n\ndef _serve_401(request, project):\n    res = render(request, '401.html')\n    res.status_code = 401\n    log.error('Unauthorized access to {0} documentation'.format(project.slug))\n    return res\n\n\ndef _serve_file(request, filename, basepath):\n    # Serve the file from the proper location\n    if settings.DEBUG or getattr(settings, 'PYTHON_MEDIA', False):\n        # Serve from Python\n        return serve(request, filename, basepath)\n    else:\n        # Serve from Nginx\n        content_type, encoding = mimetypes.guess_type(\n            os.path.join(basepath, filename))\n        content_type = content_type or 'application/octet-stream'\n        response = HttpResponse(content_type=content_type)\n        if encoding:\n            response['Content-Encoding'] = encoding\n        try:\n            response['X-Accel-Redirect'] = os.path.join(\n                basepath[len(settings.SITE_ROOT):],\n                filename,\n            )\n        except UnicodeEncodeError:\n            raise Http404\n\n        return response\n\n\n@map_project_slug\n@map_subproject_slug\ndef serve_docs(\n        request, project, subproject, lang_slug=None, version_slug=None,\n        filename=''):\n    \"\"\"Exists to map existing proj, lang, version, filename views to the file format.\"\"\"\n    if not version_slug:\n        version_slug = project.get_default_version()\n    try:\n        version = project.versions.public(request.user).get(slug=version_slug)\n    except Version.DoesNotExist:\n        # Properly raise a 404 if the version doesn't exist & a 401 if it does\n        if project.versions.filter(slug=version_slug).exists():\n            return _serve_401(request, project)\n        raise Http404('Version does not exist.')\n    filename = resolve_path(\n        subproject or project,  # Resolve the subproject if it exists\n        version_slug=version_slug,\n        language=lang_slug,\n        filename=filename,\n        subdomain=True,  # subdomain will make it a \"full\" path without a URL prefix\n    )\n    if (version.privacy_level == constants.PRIVATE and\n            not AdminPermission.is_member(user=request.user, obj=project)):\n        return _serve_401(request, project)\n    return _serve_symlink_docs(\n        request,\n        filename=filename,\n        project=project,\n        privacy_level=version.privacy_level,\n    )\n\n\n@map_project_slug\ndef _serve_symlink_docs(request, project, privacy_level, filename=''):\n    \"\"\"Serve a file by symlink, or a 404 if not found.\"\"\"\n    # Handle indexes\n    if filename == '' or filename[-1] == '/':\n        filename += 'index.html'\n\n    # This breaks path joining, by ignoring the root when given an \"absolute\" path\n    if filename[0] == '/':\n        filename = filename[1:]\n\n    log.info('Serving %s for %s', filename, project)\n\n    files_tried = []\n\n    serve_docs = getattr(settings, 'SERVE_DOCS', [constants.PRIVATE])\n\n    if (settings.DEBUG or constants.PUBLIC in serve_docs) and privacy_level != constants.PRIVATE:  # yapf: disable  # noqa\n        public_symlink = PublicSymlink(project)\n        basepath = public_symlink.project_root\n        if os.path.exists(os.path.join(basepath, filename)):\n            return _serve_file(request, filename, basepath)\n        else:\n            files_tried.append(os.path.join(basepath, filename))\n\n    if (settings.DEBUG or constants.PRIVATE in serve_docs) and privacy_level == constants.PRIVATE:  # yapf: disable  # noqa\n        # Handle private\n        private_symlink = PrivateSymlink(project)\n        basepath = private_symlink.project_root\n\n        if os.path.exists(os.path.join(basepath, filename)):\n            return _serve_file(request, filename, basepath)\n        else:\n            files_tried.append(os.path.join(basepath, filename))\n\n    raise Http404(\n        'File not found. Tried these files: %s' % ','.join(files_tried))\n", "path": "readthedocs/core/views/serve.py"}]}