Skip to content

Commit 5d8becd

Browse files
authored
Merge pull request #4483 from rtfd/davidfischer/custom-domains-use-https
Allow enforcing HTTPS for custom domains
2 parents d5f9c5f + 570ce61 commit 5d8becd

File tree

6 files changed

+51
-11
lines changed

6 files changed

+51
-11
lines changed

readthedocs/core/resolver.py

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ def resolve_path(self, project, filename='', version_slug=None,
129129
def resolve_domain(self, project, private=None):
130130
# pylint: disable=unused-argument
131131
canonical_project = self._get_canonical_project(project)
132-
domain = canonical_project.domains.filter(canonical=True).first()
132+
domain = self._get_project_custom_domain(canonical_project)
133133
if domain:
134134
return domain.domain
135135
elif self._use_subdomain():
@@ -144,13 +144,26 @@ def resolve(self, project, protocol='http', filename='', private=None,
144144
version_slug = project.get_default_version()
145145
private = self._get_private(project, version_slug)
146146

147-
domain = self.resolve_domain(project, private=private)
147+
canonical_project = self._get_canonical_project(project)
148+
custom_domain = self._get_project_custom_domain(canonical_project)
148149

149-
# Use HTTPS if settings specify
150-
public_domain = getattr(settings, 'PUBLIC_DOMAIN', None)
151-
use_https = getattr(settings, 'PUBLIC_DOMAIN_USES_HTTPS', False)
152-
if use_https and public_domain and public_domain in domain:
153-
protocol = 'https'
150+
# This duplication from resolve_domain is for performance purposes
151+
# in order to check whether a custom domain should be HTTPS
152+
if custom_domain:
153+
domain = custom_domain.domain
154+
elif self._use_subdomain():
155+
domain = self._get_project_subdomain(canonical_project)
156+
else:
157+
domain = getattr(settings, 'PRODUCTION_DOMAIN')
158+
159+
if custom_domain:
160+
protocol = 'https' if custom_domain.https else 'http'
161+
else:
162+
# Use HTTPS if settings specify
163+
public_domain = getattr(settings, 'PUBLIC_DOMAIN', None)
164+
use_https = getattr(settings, 'PUBLIC_DOMAIN_USES_HTTPS', False)
165+
if use_https and public_domain and public_domain in domain:
166+
protocol = 'https'
154167

155168
return '{protocol}://{domain}{path}'.format(
156169
protocol=protocol,
@@ -196,6 +209,9 @@ def _get_project_subdomain(self, project):
196209
subdomain_slug = project.slug.replace('_', '-')
197210
return "%s.%s" % (subdomain_slug, public_domain)
198211

212+
def _get_project_custom_domain(self, project):
213+
return project.domains.filter(canonical=True).first()
214+
199215
def _get_private(self, project, version_slug):
200216
from readthedocs.builds.models import Version
201217
try:

readthedocs/projects/admin.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ class DomainAdmin(admin.ModelAdmin):
184184
list_display = ('domain', 'project', 'https', 'count')
185185
search_fields = ('domain', 'project__slug')
186186
raw_id_fields = ('project',)
187-
list_filter = ('canonical',)
187+
list_filter = ('canonical', 'https')
188188
model = Domain
189189

190190

readthedocs/projects/forms.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -634,7 +634,7 @@ class DomainForm(forms.ModelForm):
634634

635635
class Meta(object):
636636
model = Domain
637-
exclude = ['machine', 'cname', 'count', 'https']
637+
exclude = ['machine', 'cname', 'count']
638638

639639
def __init__(self, *args, **kwargs):
640640
self.project = kwargs.pop('project', None)

readthedocs/projects/models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,7 +985,7 @@ class Domain(models.Model):
985985
https = models.BooleanField(
986986
_('Use HTTPS'),
987987
default=False,
988-
help_text=_('SSL is enabled for this domain')
988+
help_text=_('Always use HTTPS for this domain')
989989
)
990990
count = models.IntegerField(default=0, help_text=_(
991991
'Number of times this domain has been hit'),)

readthedocs/rtd_tests/tests/test_resolver.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,22 @@ def test_resolver_domain(self):
471471
url = resolve(project=self.pip)
472472
self.assertEqual(url, 'http://docs.foobar.com/en/latest/')
473473

474+
@override_settings(PRODUCTION_DOMAIN='readthedocs.org')
475+
def test_resolver_domain_https(self):
476+
self.domain = fixture.get(
477+
Domain,
478+
domain='docs.foobar.com',
479+
project=self.pip,
480+
https=True,
481+
canonical=True,
482+
)
483+
with override_settings(USE_SUBDOMAIN=False):
484+
url = resolve(project=self.pip)
485+
self.assertEqual(url, 'https://docs.foobar.com/en/latest/')
486+
with override_settings(USE_SUBDOMAIN=True):
487+
url = resolve(project=self.pip)
488+
self.assertEqual(url, 'https://docs.foobar.com/en/latest/')
489+
474490
@override_settings(PRODUCTION_DOMAIN='readthedocs.org')
475491
def test_resolver_subproject(self):
476492
with override_settings(USE_SUBDOMAIN=False):
@@ -740,7 +756,7 @@ def test_subproject_with_translation_with_custom_domain(self):
740756
domain='docs.example.com',
741757
canonical=True,
742758
cname=True,
743-
https=True,
759+
https=False,
744760
project=self.superproject_en,
745761
)
746762

readthedocs/templates/projects/domain_form.html

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@
2121
{% endblock %}
2222

2323
{% block project_edit_content %}
24+
{% if domain.domainssl %}
25+
{# This references optional code to get the SSL certificate status #}
26+
<p>
27+
<strong>HTTPS status: </strong>
28+
<span>{{ domain.domainssl.status }}</span>
29+
</p>
30+
{% endif %}
31+
2432
{% if domain %}
2533
{% url 'projects_domains_edit' project.slug domain.pk as action_url %}
2634
{% else %}

0 commit comments

Comments
 (0)