Repository: falconry/falcon
Pull request #1318 (2018-05-24 23:14:10)

Set auto_parse_qs_csv to False, instead True #842

MichaelYusko: @nZac No problems, I'll looking for new tickets!
vytas7: We have a couple of tests setting *auto_parse_qs_csv* to ``False``. I was thinking to myself if we could morph one of them, or add a new test, to check that the behaviour is corresponding to the new default even without setting it explicitly?
MichaelYusko: @vytas7 added one more test.

Patch:
diff --git a/falcon/request.py b/falcon/request.py
index 65eaaa2..74a1581 100644
--- a/falcon/request.py
+++ b/falcon/request.py
@@ -1779,14 +1779,15 @@ class RequestOptions(object):
                 encoded according to the standard W3C algorithm (see
                 also http://goo.gl/6rlcux).
 
-        auto_parse_qs_csv: Set to ``False`` to treat commas in a query
-            string value as literal characters, rather than as a comma-
-            separated list (default ``True``). When this option is
-            enabled, the value will be split on any non-percent-encoded
-            commas. Disable this option when encoding lists as multiple
-            occurrences of the same parameter, and when values may be
-            encoded in alternative formats in which the comma character
-            is significant.
+        auto_parse_qs_csv: Pass in ``True`` to split
+            a query string value on any non-percent-encoded commas,
+            this option is disabled by default (``False``).
+            When ``False`` query strings containing commas are untouched,
+            this enables encoding lists as multiple of the same parameter
+            and cases where the comma character is significant
+            such as alternate encodings (i.e. ``/?t=1,2,3&t=4`` becomes ``['1,2,3', '4']``).
+            When ``True``, the query string value is split on the commas
+            and returned as a list (i.e. ``/?t=1,2,3&t=4`` becomes ``['1', '2', '3', '4']``).
 
         strip_url_path_trailing_slash: Set to ``True`` in order to
             strip the trailing slash, if present, at the end of the URL
@@ -1821,7 +1822,7 @@ class RequestOptions(object):
     def __init__(self):
         self.keep_blank_qs_values = True
         self.auto_parse_form_urlencoded = False
-        self.auto_parse_qs_csv = True
+        self.auto_parse_qs_csv = False
         self.strip_url_path_trailing_slash = False
         self.default_media_type = DEFAULT_MEDIA_TYPE
         self.media_handlers = Handlers()


Test patch:
diff --git a/tests/test_options.py b/tests/test_options.py
index 32b5257..3f5b9ce 100644
--- a/tests/test_options.py
+++ b/tests/test_options.py
@@ -10,7 +10,7 @@ class TestRequestOptions(object):
 
         assert options.keep_blank_qs_values
         assert not options.auto_parse_form_urlencoded
-        assert options.auto_parse_qs_csv
+        assert not options.auto_parse_qs_csv
         assert not options.strip_url_path_trailing_slash
 
     @pytest.mark.parametrize('option_name', [
diff --git a/tests/test_query_params.py b/tests/test_query_params.py
index 8555c8f..5195045 100644
--- a/tests/test_query_params.py
+++ b/tests/test_query_params.py
@@ -137,6 +137,7 @@ class TestQueryParams(object):
     def test_percent_encoded(self, simulate_request, client, resource):
         query_string = 'id=23,42&q=%e8%b1%86+%e7%93%a3'
         client.app.add_route('/', resource)
+        client.app.req_options.auto_parse_qs_csv = True
         simulate_request(client=client, path='/', query_string=query_string)
 
         req = resource.captured_req
@@ -207,6 +208,17 @@ class TestQueryParams(object):
 
         assert req.get_param('thing') == decoded_json
 
+    def test_default_auto_parse_csv_behaviour(self, simulate_request, client, resource):
+        client.app.add_route('/', resource=resource)
+        query_string = 'id=1,2,,&id=3'
+
+        simulate_request(client=client, path='/', query_string=query_string)
+
+        req = resource.captured_req
+
+        assert req.get_param('id') == '3'
+        assert req.get_param_as_list('id') == ['1,2,,', '3']
+
     def test_bad_percentage(self, simulate_request, client, resource):
         client.app.add_route('/', resource)
         query_string = 'x=%%20%+%&y=peregrine&z=%a%z%zz%1%20e'
@@ -499,6 +511,7 @@ class TestQueryParams(object):
 
     def test_list_type(self, simulate_request, client, resource):
         client.app.add_route('/', resource)
+        client.app.req_options.auto_parse_qs_csv = True
         client.app.req_options.keep_blank_qs_values = False
         query_string = ('colors=red,green,blue&limit=1'
                         '&list-ish1=f,,x&list-ish2=,0&list-ish3=a,,,b'
@@ -550,6 +563,7 @@ class TestQueryParams(object):
                         '&empty4=&empty4&empty4='
                         '&empty5&empty5&empty5')
         client.app.req_options.keep_blank_qs_values = True
+        client.app.req_options.auto_parse_qs_csv = True
         simulate_request(client=client, path='/', query_string=query_string)
 
         req = resource.captured_req
@@ -589,6 +603,7 @@ class TestQueryParams(object):
 
     def test_list_transformer(self, simulate_request, client, resource):
         client.app.add_route('/', resource)
+        client.app.req_options.auto_parse_qs_csv = True
         client.app.req_options.keep_blank_qs_values = False
         query_string = 'coord=1.4,13,15.1&limit=100&things=4,,1'
         simulate_request(client=client, path='/', query_string=query_string)
diff --git a/tests/test_utils.py b/tests/test_utils.py
index d3e1f0d..9b2de13 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -486,6 +486,7 @@ class TestFalconTestingUtils(object):
                 resp.body = json.dumps(doc)
 
         app = falcon.API()
+        app.req_options.auto_parse_qs_csv = True
         app.add_route('/', SomeResource())
         client = testing.TestClient(app)