Skip to content

Commit 7a278b3

Browse files
nikulincarltongibson
authored andcommitted
fix processing unicode symbols in query_string by Python 2 (#5552)
* fix processing unicode symbols in query_string by Python 2 * Add comments for encoded test strings. * Add file encoding for Python 2.
1 parent d49d796 commit 7a278b3

File tree

2 files changed

+69
-3
lines changed

2 files changed

+69
-3
lines changed

Diff for: rest_framework/utils/urls.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
from django.utils.encoding import force_str
12
from django.utils.six.moves.urllib import parse as urlparse
23

34

@@ -6,9 +7,9 @@ def replace_query_param(url, key, val):
67
Given a URL and a key/val pair, set or replace an item in the query
78
parameters of the URL, and return the new URL.
89
"""
9-
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(url)
10+
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(force_str(url))
1011
query_dict = urlparse.parse_qs(query, keep_blank_values=True)
11-
query_dict[key] = [val]
12+
query_dict[force_str(key)] = [force_str(val)]
1213
query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True)
1314
return urlparse.urlunsplit((scheme, netloc, path, query, fragment))
1415

@@ -18,7 +19,7 @@ def remove_query_param(url, key):
1819
Given a URL and a key/val pair, remove an item in the query
1920
parameters of the URL, and return the new URL.
2021
"""
21-
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(url)
22+
(scheme, netloc, path, query, fragment) = urlparse.urlsplit(force_str(url))
2223
query_dict = urlparse.parse_qs(query, keep_blank_values=True)
2324
query_dict.pop(key, None)
2425
query = urlparse.urlencode(sorted(list(query_dict.items())), doseq=True)

Diff for: tests/test_utils.py

+65
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# -*- coding: utf-8 -*-
12
from __future__ import unicode_literals
23

34
from django.conf.urls import url
@@ -11,6 +12,7 @@
1112
from rest_framework.serializers import ModelSerializer
1213
from rest_framework.utils import json
1314
from rest_framework.utils.breadcrumbs import get_breadcrumbs
15+
from rest_framework.utils.urls import remove_query_param, replace_query_param
1416
from rest_framework.views import APIView
1517
from rest_framework.viewsets import ModelViewSet
1618
from tests.models import BasicModel
@@ -205,3 +207,66 @@ class NonStrictJsonFloatTests(JsonFloatTests):
205207
"""
206208
'STRICT_JSON = False' should not somehow affect internal json behavior
207209
"""
210+
211+
212+
class UrlsReplaceQueryParamTests(TestCase):
213+
"""
214+
Tests the replace_query_param functionality.
215+
"""
216+
def test_valid_unicode_preserved(self):
217+
# Encoded string: '查询'
218+
q = '/?q=%E6%9F%A5%E8%AF%A2'
219+
new_key = 'page'
220+
new_value = 2
221+
value = '%E6%9F%A5%E8%AF%A2'
222+
223+
assert new_key in replace_query_param(q, new_key, new_value)
224+
assert value in replace_query_param(q, new_key, new_value)
225+
226+
def test_valid_unicode_replaced(self):
227+
q = '/?page=1'
228+
value = '1'
229+
new_key = 'q'
230+
new_value = '%E6%9F%A5%E8%AF%A2'
231+
232+
assert new_key in replace_query_param(q, new_key, new_value)
233+
assert value in replace_query_param(q, new_key, new_value)
234+
235+
def test_invalid_unicode(self):
236+
# Encoded string: '��<script>alert(313)</script>=1'
237+
q = '/e/?%FF%FE%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%33%31%33%29%3C%2F%73%63%72%69%70%74%3E=1'
238+
key = 'from'
239+
value = 'login'
240+
241+
assert key in replace_query_param(q, key, value)
242+
243+
244+
class UrlsRemoveQueryParamTests(TestCase):
245+
"""
246+
Tests the remove_query_param functionality.
247+
"""
248+
def test_valid_unicode_preserved(self):
249+
q = '/?q=%E6%9F%A5%E8%AF%A2'
250+
new_key = 'page'
251+
new_value = 2
252+
value = '%E6%9F%A5%E8%AF%A2'
253+
254+
assert new_key in replace_query_param(q, new_key, new_value)
255+
assert value in replace_query_param(q, new_key, new_value)
256+
257+
def test_valid_unicode_removed(self):
258+
q = '/?page=2345&q=%E6%9F%A5%E8%AF%A2'
259+
key = 'page'
260+
value = '2345'
261+
removed_key = 'q'
262+
263+
assert key in remove_query_param(q, removed_key)
264+
assert value in remove_query_param(q, removed_key)
265+
assert '%' not in remove_query_param(q, removed_key)
266+
267+
def test_invalid_unicode(self):
268+
q = '/?from=login&page=2&%FF%FE%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%33%31%33%29%3C%2F%73%63%72%69%70%74%3E=1'
269+
key = 'from'
270+
removed_key = 'page'
271+
272+
assert key in remove_query_param(q, removed_key)

0 commit comments

Comments
 (0)