Skip to content

Commit

Permalink
Fixed #8997 -- Prevented the contenttypes shortcut view to hide err…
Browse files Browse the repository at this point in the history
…ors occurring inside the `get_absolute_url()` method. Thanks to Rob for the report and to joshlory, Aymeric Augustin and Claude Paroz for the patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17328 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information
jphalip committed Jan 2, 2012
1 parent 07132fb commit 6fa62b8
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 6 deletions.
23 changes: 23 additions & 0 deletions django/contrib/contenttypes/tests.py
Expand Up @@ -30,6 +30,13 @@ class FooWithUrl(FooWithoutUrl):
def get_absolute_url(self):
return "/users/%s/" % urllib.quote(smart_str(self.name))

class FooWithBrokenAbsoluteUrl(FooWithoutUrl):
"""
Fake model defining a ``get_absolute_url`` method containing an error
"""

def get_absolute_url(self):
return "/users/%s/" % self.unknown_field

class ContentTypesTests(TestCase):

Expand Down Expand Up @@ -135,6 +142,22 @@ def test_shortcut_view_without_get_absolute_url(self):

self.assertRaises(Http404, shortcut, request, user_ct.id, obj.id)

def test_shortcut_view_with_broken_get_absolute_url(self):
"""
Check that the shortcut view does not catch an AttributeError raised
by the model's get_absolute_url method.
Refs #8997.
"""
request = HttpRequest()
request.META = {
"SERVER_NAME": "Example.com",
"SERVER_PORT": "80",
}
user_ct = ContentType.objects.get_for_model(FooWithBrokenAbsoluteUrl)
obj = FooWithBrokenAbsoluteUrl.objects.create(name="john")

self.assertRaises(AttributeError, shortcut, request, user_ct.id, obj.id)

def test_missing_model(self):
"""
Ensures that displaying content types in admin (or anywhere) doesn't
Expand Down
19 changes: 13 additions & 6 deletions django/contrib/contenttypes/views.py
Expand Up @@ -4,19 +4,25 @@
from django.core.exceptions import ObjectDoesNotExist

def shortcut(request, content_type_id, object_id):
"Redirect to an object's page based on a content-type ID and an object ID."
"""
Redirect to an object's page based on a content-type ID and an object ID.
"""
# Look up the object, making sure it's got a get_absolute_url() function.
try:
content_type = ContentType.objects.get(pk=content_type_id)
if not content_type.model_class():
raise http.Http404("Content type %s object has no associated model" % content_type_id)
raise http.Http404("Content type %s object has no associated model"
% content_type_id)
obj = content_type.get_object_for_this_type(pk=object_id)
except (ObjectDoesNotExist, ValueError):
raise http.Http404("Content type %s object %s doesn't exist" % (content_type_id, object_id))
raise http.Http404("Content type %s object %s doesn't exist"
% (content_type_id, object_id))
try:
absurl = obj.get_absolute_url()
get_absolute_url = obj.get_absolute_url
except AttributeError:
raise http.Http404("%s objects don't have get_absolute_url() methods" % content_type.name)
raise http.Http404("%s objects don't have a get_absolute_url() method"
% content_type.name)
absurl = get_absolute_url()

# Try to figure out the object's domain, so we can do a cross-site redirect
# if necessary.
Expand Down Expand Up @@ -66,6 +72,7 @@ def shortcut(request, content_type_id, object_id):
# to whatever get_absolute_url() returned.
if object_domain is not None:
protocol = request.is_secure() and 'https' or 'http'
return http.HttpResponseRedirect('%s://%s%s' % (protocol, object_domain, absurl))
return http.HttpResponseRedirect('%s://%s%s'
% (protocol, object_domain, absurl))
else:
return http.HttpResponseRedirect(absurl)

0 comments on commit 6fa62b8

Please sign in to comment.