diff --git a/django/contrib/contenttypes/views.py b/django/contrib/contenttypes/views.py index 430ed800da..6bc3aa04dd 100644 --- a/django/contrib/contenttypes/views.py +++ b/django/contrib/contenttypes/views.py @@ -34,7 +34,7 @@ def shortcut(request, content_type_id, object_id): # if necessary. # If the object actually defines a domain, we're done. - if absurl.startswith('http://') or absurl.startswith('https://'): + if absurl.startswith(('http://', 'https://', '//')): return http.HttpResponseRedirect(absurl) # Otherwise, we need to introspect the object's relationships for a diff --git a/docs/releases/1.7.txt b/docs/releases/1.7.txt index 305cf6da66..a8bf154421 100644 --- a/docs/releases/1.7.txt +++ b/docs/releases/1.7.txt @@ -1147,6 +1147,9 @@ Miscellaneous ``django.utils.translation.trans_real.get_supported_language_variant()`` now no longer have a ``supported`` argument. +* The ``shortcut`` view in ``django.contrib.contenttypes.views`` now supports + protocol-relative URLs (e.g. ``//example.com``). + .. _deprecated-features-1.7: Features deprecated in 1.7 diff --git a/tests/contenttypes_tests/fixtures/testdata.json b/tests/contenttypes_tests/fixtures/testdata.json index 52510bfe90..114b1e262f 100644 --- a/tests/contenttypes_tests/fixtures/testdata.json +++ b/tests/contenttypes_tests/fixtures/testdata.json @@ -36,6 +36,27 @@ "date_created": "3000-01-01 21:22:23" } }, + { + "pk": 1, + "model": "contenttypes_tests.schemeincludedurl", + "fields": { + "url": "http://test_scheme_included_http/" + } + }, + { + "pk": 2, + "model": "contenttypes_tests.schemeincludedurl", + "fields": { + "url": "https://test_scheme_included_https/" + } + }, + { + "pk": 3, + "model": "contenttypes_tests.schemeincludedurl", + "fields": { + "url": "//test_default_scheme_kept/" + } + }, { "pk": 1, "model": "sites.site", diff --git a/tests/contenttypes_tests/models.py b/tests/contenttypes_tests/models.py index d47cfac7f7..dadc40d3d9 100644 --- a/tests/contenttypes_tests/models.py +++ b/tests/contenttypes_tests/models.py @@ -24,3 +24,14 @@ class Article(models.Model): def __str__(self): return self.title + + +@python_2_unicode_compatible +class SchemeIncludedURL(models.Model): + url = models.URLField(max_length=100) + + def __str__(self): + return self.url + + def get_absolute_url(self): + return self.url diff --git a/tests/contenttypes_tests/tests.py b/tests/contenttypes_tests/tests.py index af2cedd8b3..085ad2ec89 100644 --- a/tests/contenttypes_tests/tests.py +++ b/tests/contenttypes_tests/tests.py @@ -12,7 +12,7 @@ from django.test import TestCase from django.test.utils import override_settings from django.utils.encoding import force_str -from .models import Author, Article +from .models import Author, Article, SchemeIncludedURL class ContentTypesViewsTests(TestCase): @@ -27,6 +27,19 @@ class ContentTypesViewsTests(TestCase): self.assertRedirects(response, 'http://testserver%s' % obj.get_absolute_url(), status_code=302, target_status_code=404) + def test_shortcut_with_absolute_url_including_scheme(self): + """ + Can view a shortcut when object's get_absolute_url returns a full URL + the tested URLs are in fixtures/testdata.json : + "http://...", "https://..." and "//..." + """ + for obj in SchemeIncludedURL.objects.all(): + short_url = '/shortcut/%s/%s/' % (ContentType.objects.get_for_model(SchemeIncludedURL).id, obj.pk) + response = self.client.get(short_url) + self.assertRedirects(response, obj.get_absolute_url(), + status_code=302, + fetch_redirect_response=False) + def test_shortcut_no_absolute_url(self): "Shortcuts for an object that has no get_absolute_url method raises 404" for obj in Article.objects.all():