Skip to content

Commit 3cada1d

Browse files
committed
Add a CNAME -> slug API endpoint
1 parent 7fc4e19 commit 3cada1d

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

readthedocs/core/utils.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import os
44
import shutil
55

6+
from dns import resolver
7+
from urlparse import urlparse
8+
69
from django.conf import settings
710

811
log = logging.getLogger(__name__)
@@ -123,3 +126,20 @@ def make_latest(project):
123126
verbose_name='latest',
124127
identifier=branch,
125128
)
129+
130+
131+
def clean_url(url):
132+
parsed = urlparse(url)
133+
if parsed.scheme:
134+
scheme, netloc = parsed.scheme, parsed.netloc
135+
elif parsed.netloc:
136+
scheme, netloc = "http", parsed.netloc
137+
else:
138+
scheme, netloc = "http", parsed.path
139+
return netloc
140+
141+
def cname_to_slug(host):
142+
answer = [ans for ans in resolver.query(host, 'CNAME')][0]
143+
domain = answer.target.to_unicode()
144+
slug = domain.split('.')[0]
145+
return slug

readthedocs/restapi/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
urlpatterns = patterns(
1313
'',
1414
url(r'^', include(router.urls)),
15+
url(r'cname/', 'restapi.views.core_views.cname', name='cname'),
1516
url(r'footer_html/', 'restapi.views.footer_views.footer_html', name='footer_html'),
1617
url(r'quick_search/', 'restapi.views.search_views.quick_search', name='quick_search'),
1718
url(r'index_search/', 'restapi.views.search_views.index_search', name='index_search'),
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from rest_framework import decorators, permissions, status
2+
from rest_framework.renderers import JSONPRenderer, JSONRenderer, BrowsableAPIRenderer
3+
from rest_framework.response import Response
4+
5+
from core.utils import clean_url, cname_to_slug
6+
from projects.models import Project
7+
8+
@decorators.api_view(['GET'])
9+
@decorators.permission_classes((permissions.AllowAny,))
10+
@decorators.renderer_classes((JSONRenderer, JSONPRenderer, BrowsableAPIRenderer))
11+
def cname(request):
12+
"""
13+
Get the slug that a particular hostname resolves to.
14+
This is useful for debugging your DNS settings,
15+
or for getting the backing project name on Read the Docs for a URL.
16+
17+
Example::
18+
19+
GET https://readthedocs.org/api/v2/cname/?host=docs.python-requests.org
20+
21+
This will return information about ``docs.python-requests.org``
22+
"""
23+
host = request.GET.get('host')
24+
if not host:
25+
return Response({'error': 'host GET arg required'}, status=status.HTTP_400_BAD_REQUEST)
26+
host = clean_url(host)
27+
slug = cname_to_slug(host)
28+
return Response({
29+
'host': host,
30+
'slug': slug,
31+
})
32+
33+

0 commit comments

Comments
 (0)