Repository: oppia/oppia

Issue:
Normalized values for url path elements are not passed on to the handler
During normalization using schemas in the function `validate_and_normalize_args()`, in `core/controllers/base.py`, the normalized values for url path elements are not passed on to their handlers. Currently the normalized values for url path elements are assigned like this (line 391):

```
normalized_arg_values, errors = (
    payload_validator.validate(
        url_path_args, schema_for_url_path_args, extra_args_are_allowed)
)
```

But `normalized_arg_values` is overwritten and the normalized values for url path elements are not made available to the handler. The behavior that probably is expected for url path elements(in my opinion) is that when they enter a handler like this 

```
class ExampleHandler(base.BaseHandler):
    @acl_decorators.open_access
    def get(self, url_path_arg):
        """Handles GET requests."""
```  
The value of `url_path_arg` is normalized (if there is schema for it).


Discussion:

Resolving patch:
diff --git a/core/controllers/base.py b/core/controllers/base.py
--- a/core/controllers/base.py
+++ b/core/controllers/base.py
@@ -389,7 +389,7 @@ def validate_and_normalize_args(self):
                     handler_class_name))
 
         schema_for_url_path_args = self.URL_PATH_ARGS_SCHEMAS
-        normalized_arg_values, errors = (
+        self.request.route_kwargs, errors = (
             payload_validator.validate(
                 url_path_args, schema_for_url_path_args, extra_args_are_allowed)
         )


Test patch:
diff --git a/core/controllers/base_test.py b/core/controllers/base_test.py
--- a/core/controllers/base_test.py
+++ b/core/controllers/base_test.py
@@ -1984,3 +1984,53 @@ def test_image_upload_and_download(self):
             )
             filename = response_dict['filename']
         self.logout()
+
+
+class UrlPathNormalizationTest(test_utils.GenericTestBase):
+    """Tests that ensure url path arguments are normalized"""
+
+    class MockHandler(base.BaseHandler):
+        URL_PATH_ARGS_SCHEMAS = {
+            'mock_list': {
+                'schema': {
+                    'type': 'custom',
+                    'obj_type': 'JsonEncodedInString'
+                }
+            },
+            'mock_int': {
+                'schema': {
+                    'type': 'int'
+                }
+            }
+        }
+        HANDLER_ARGS_SCHEMAS = {
+            'GET': {}
+        }
+
+        def get(self, mock_list, mock_int):
+            if not isinstance(mock_list, list):
+                raise self.InvalidInputException(
+                    'Expected arg mock_list to be a list. Was type %s' %
+                    type(mock_list))
+            if not isinstance(mock_int, int):
+                raise self.InvalidInputException(
+                    'Expected arg mock_int to be a int. Was type %s' %
+                    type(mock_int))
+            self.render_json({'mock_list': mock_list, 'mock_int': mock_int})
+
+    def setUp(self):
+        super(UrlPathNormalizationTest, self).setUp()
+        self.testapp = webtest.TestApp(webapp2.WSGIApplication(
+            [webapp2.Route('/mock_normalization/<mock_int>/<mock_list>',
+            self.MockHandler, name='MockHandler')],
+            debug=feconf.DEBUG,
+        ))
+
+    def test_url_path_arg_normalization_is_successful(self):
+        list_string = '["id1", "id2", "id3"]'
+        int_string = '1'
+
+        with self.swap(self, 'testapp', self.testapp):
+            self.get_json(
+                '/mock_normalization/%s/%s' % (int_string, list_string),
+                expected_status_int=200)