Django-rest-framework: Escaping (ampersand) in browsable API URLs.

Created on 20 Jun 2014  ·  26Comments  ·  Source: encode/django-rest-framework

When URLs with an escaped character (specifically in my case, and ampersand) is rendered in the browsable API, in the href it is improperly unescaped. This may only apply to ampersands.

For example, this URL:
http://localhost:8000/endpoint/?param1=Yes+%26+No&param2=something

Would be rendered as:
http://localhost:8000/endpoint/?param1=Yes+&+No&param2=something

The URL is rendered in the value of the a element correctly... this only applies to the href.

Bug

Most helpful comment

I just want to confirm it is working now :)

Love this library, it's already working great, but even then still getting better! 👍

All 26 comments

Apologies for the slow response.
Is it just the rendering that's different or is the source HTML itself unescaped?

Hi Tom, in the HTML it looked something like this:

<a href="http://localhost:8000/endpoint/?param1=Yes+&+No&param2=something">http://localhost:8000/endpoint/?param1=Yes+%26+No&param2=something</a>

Gotcha thanks - might be worth trying to write a failing test case for this.
Ideally that would just exercise BrowsableAPIRendererer, but would probably also be okay with a full integration test.

Sure, I'd be happy to. Looking through the test suite now... would the appropriate place be in RendererEndToEndTests in test_renderers.py?

Sounds okay.

This has to do with Django's smart_urlquote which is called by DRF's urlize_quoted_links, which is what handles the conversion within the browsable API. I _think_ the difference between the link text and the link itself may be a Django escaping thing, but I'm honestly not sure there.

smart_urlquote calls unquote before quote, which is what strips the original one. This was added in https://github.com/django/django/commit/b70c371fc1f18ea0c43b503122df3f311afc7105 and backported for Django 1.5+.

So do we care that this isn't _strictly_ what the client will see, or do we just close this off?
Semantically it's still correct.

Pushing this from bug to cleanup, as it's borderline.

DjangoCon guidance - general review of this ticket - what would you expect the behaviour to be, is it acceptable as-is?

I am at the django-con sprints and can work on this. I have not contributed before so I might need some initial guidance. I am currently reading the contributor guidelines for DRF and after I run the tests locally, I might go bug somebody in person or on irc.

Gotcha - feel free to ping me on IRC, or twitter if I'm not responsive there.

Closing due to low priority and lack of progress.
Happy to reconsider if someone's motivated to take this up again.

@tomchristie I understand it being a minor issue, but it's still a bug. If you click the link, it goes to the wrong URL. It seems more appropriate to tag as low priority than to close a valid issue.

I'll look into it when I have time.

Sorry I'd understood this differently - that the URL wasn't wrong, just that it rendered the link in an unescaped style, have I misunderstood that?

Ie. reason for the cleanup tag, understood this to be a cosmetic issue?

Oh, I see. Yes, that's correct. Basically, both the href and display value are being escaped, instead of just the display value.

Thanks for such a great library, btw!

Sorry, one more time :)

Yes, that's correct.

Correct that it's a cosmetic issue, or correct that I misunderstood and it's a bug? :)

Correct that it's a bug. :)

Closing, as this is fixed by https://code.djangoproject.com/ticket/22267

Haven't looked at this yet but do we need to pull anything else in given that we duplicate 'urlize'? Also what version is this resolved in? Also, great! Yay!

This doesn't appear to be fixed in 1.7.1, so 1.7.2 or 1.8? This is the behavior I see with django 1.7.1:

>>> from django.utils.html import smart_urlquote, escape
>>> escape(smart_urlquote('http://qwerty.com'))
u'http://qwerty.com'
>>> escape(smart_urlquote('http://qwerty.com?blah=Yes+%26+No'))
u'http://qwerty.com?blah=Yes+&amp;+No'

.. and current head of django master branch:

>>> from django.utils.html import smart_urlquote, escape
>>> escape(smart_urlquote('http://qwerty.com?blah=Yes+%26+No'))
u'http://qwerty.com?blah=Yes+%26+No'

Was urlize_quoted_links originally a modified copy of django.utils.html.urlize? https://github.com/django/django/blob/master/django/utils/html.py#L255-L352 is significantly different, but I can't tell reason for the separate version. It looks like it needs to be re-copied over.

Yes it was copied over, because the original wouldn't work for "http://example.org" style links that have single or double quotes enclosing them, and there's no easy override to allow it. If there's much difference that's prob due to gradual change of the django version while ours has stayed the same.

Going to reopen this to ensure we have a placeholder ticket to ensure this gets addressed.

Dropping the milestone on this as there are higher priority 3.0.1 items.

I wonder whether it's possible to pull the failing test case from #2014

This comment https://github.com/tomchristie/django-rest-framework/pull/2014#issuecomment-61525348 implies that that issue was fixed in upstream Django. Closing this, but will reopen if anyone confirms it remains an issue.

I just want to confirm it is working now :)

Love this library, it's already working great, but even then still getting better! 👍

Was this page helpful?
0 / 5 - 0 ratings