Use Escaped url in Django url regex mismatch

Viewed 40

I'm trying to use an escaped url as a re_path variable for an object identifier in my API. The logic to connect the escaped url to an object is there, but I can't figure out why the regex is not matching.

In my head, a GET request with the following url /objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo should be parsed into obj = 'http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1' and field = 'foo' for further processing. Ultimately, returning the object and 200. However I am getting a 404 with a very specific Django error that only proliferates when Django unfruitfully iterates through all the paths available.

<HttpResponseNotFound status_code=404, "text/html">
(Pdb) response.content
b'\n<!doctype html>\n<html lang="en">\n<head>\n  <title>Not Found</title>\n</head>\n<body>\n  <h1>Not Found</h1><p>The requested resource was not found on this server.</p>\n</body>\n</html>\n'

I know the path exists as when I examine the urlpatterns, the path is present:

(Pdb) pp object_router.get_urls()
[
    ...
    <URLPattern '^(?P<obj>https?[-a-zA-Z0-9%._\+~#=]+)/(?P<field>foo|bar)\/?$' [name='test-detail-foobar']>
]

The url is escaped with urllib.parse.quote(obj.url, safe="")

Regexs tried:

Edit: Based off the Django Path Convertor path regex, I've changed my regex to https?.+ with the compiled version as '(?P<obj>https?.+)/(?P<field>foo|bar)\\/?$'. This is moving in the right direction, however I've further identified some weirdness. Basically it seems that escaping the path variable url (obj) is partially to blame for the mismatch as an unescaped url (without query parameters) will return a differently handled API response. Further more, adding a query parameters/a question mark, once again returns us back to the Django 404.

1 Answers

If I am understanding your issue properly, it looks like you are attempting to get a regex match and immediately send a request to the resultant url?

If that is the case, you are sending the request to an improperly formatted url. The first regex you posted looks like it works just fine to get the result you are asking for, however it results in a url that is still encoded.

You need to "unquote" the url prior to making the request.

import re
from urllib.parse import unquote

path = '/objects/http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1/foo'

resp = re.search("https?[-a-zA-Z0-9%._+~#=]+", path)
url = resp[0]
print(url)
print(unquote(url))

results in and output of:

http%3A%2F%2F0.0.0.0%3A3030%2Fu%2F%3Fid%3Dc789793d-9538-4a27-9dd0-7bb487253da1

http://0.0.0.0:3030/u/?id=c789793d-9538-4a27-9dd0-7bb487253da1
Related