Эх сурвалжийг харах

[raz_abfs] Unquote relative_path and partition signed path with `.dfs.core.windows.net` (#3081)

* [raz_abfs] Unquote relative_path and partition path with '.dfs.core.windows.net'

- We are fully unquoting the relative_path now when preparing the request parameter for RAZ API call to get back SAS token. This is required for cases when there are whitespaces or non-ascii characters in the path.

- Previously, we were partioning the signed url with the original path to get only the `/container/path?action=something%&sas_token` type of signed path. But this approach was breaking during partitioning when signed url was quoted and the original path was not. Because of this, operations related to non-ascii characters or containing whitespaces were failing. Now we only partition the signed url with '.dfs.core.windows.net' for signed path consistency.

- Updated existing unit tests and added test cases handling path having whitespaces.
Harsh Gupta 3 жил өмнө
parent
commit
89e590d8a9

+ 3 - 2
desktop/core/src/desktop/lib/raz/raz_client.py

@@ -203,9 +203,10 @@ class RazClient(object):
       relative_path += resource_path[1]
       relative_path += resource_path[1]
 
 
     if relative_path == "/" and method == 'GET' and params.get('resource') == 'filesystem' and params.get('directory'):
     if relative_path == "/" and method == 'GET' and params.get('resource') == 'filesystem' and params.get('directory'):
-      relative_path += lib_urlunquote(params['directory'])
+      relative_path += params['directory']
 
 
-    return relative_path
+    # Unquoting the full relative_path to catch edge cases like path having whitespaces or non-ascii chars.
+    return lib_urlunquote(relative_path)
 
 
 
 
   def handle_adls_req_mapping(self, method, params):
   def handle_adls_req_mapping(self, method, params):

+ 16 - 1
desktop/core/src/desktop/lib/raz/raz_client_test.py

@@ -198,6 +198,13 @@ class RazClientTest(unittest.TestCase):
     access_type = client.handle_adls_req_mapping(method, url_params)
     access_type = client.handle_adls_req_mapping(method, url_params)
     assert_equal(access_type, 'get-status')
     assert_equal(access_type, 'get-status')
 
 
+    method = 'HEAD'
+    relative_path = '/user'
+    url_params = {'resource': 'filesystem'} # Stats call for first-level directories like /user
+
+    access_type = client.handle_adls_req_mapping(method, url_params)
+    assert_equal(access_type, 'get-status')
+
     # Delete path
     # Delete path
     method = 'DELETE'
     method = 'DELETE'
     relative_path = '/user/csso_hueuser/test_dir/customer.csv'
     relative_path = '/user/csso_hueuser/test_dir/customer.csv'
@@ -266,7 +273,7 @@ class RazClientTest(unittest.TestCase):
     relative_path = client._handle_relative_path(method, url_params, resource_path, "/")
     relative_path = client._handle_relative_path(method, url_params, resource_path, "/")
     assert_equal(relative_path, "/")
     assert_equal(relative_path, "/")
 
 
-    # When relative path present in URL
+    # When relative path is present in URL
     method = 'GET'
     method = 'GET'
     resource_path = ['gethue-container', 'user/csso_hueuser/customer.csv']
     resource_path = ['gethue-container', 'user/csso_hueuser/customer.csv']
     url_params = {}
     url_params = {}
@@ -274,6 +281,14 @@ class RazClientTest(unittest.TestCase):
     relative_path = client._handle_relative_path(method, url_params, resource_path, "/")
     relative_path = client._handle_relative_path(method, url_params, resource_path, "/")
     assert_equal(relative_path, "/user/csso_hueuser/customer.csv")
     assert_equal(relative_path, "/user/csso_hueuser/customer.csv")
 
 
+    # When relative path present in URL is having quoted whitespaces (%20)
+    method = 'GET'
+    resource_path = ['gethue-container', 'user/csso_hueuser/customer%20(1).csv']
+    url_params = {}
+
+    relative_path = client._handle_relative_path(method, url_params, resource_path, "/")
+    assert_equal(relative_path, "/user/csso_hueuser/customer (1).csv")
+
     # When list operation
     # When list operation
     method = 'GET'
     method = 'GET'
     resource_path = ['gethue-container']
     resource_path = ['gethue-container']

+ 3 - 2
desktop/core/src/desktop/lib/rest/raz_http_client.py

@@ -52,8 +52,9 @@ class RazHttpClient(HttpClient):
 
 
     signed_url = url + ('?' if '?' not in url else '&') + sas_token
     signed_url = url + ('?' if '?' not in url else '&') + sas_token
 
 
-    # Required because `self._make_url` is called in base class execute method also
-    signed_path = path + signed_url.partition(path)[2]
+    # self._make_url is called in base class execute method as well,
+    # so we remove https://{storageaccountname}.dfs.core.windows.net from the signed url here.
+    signed_path = signed_url.partition('.dfs.core.windows.net')[2]
 
 
     return super(RazHttpClient, self).execute(
     return super(RazHttpClient, self).execute(
         http_method=http_method,
         http_method=http_method,

+ 20 - 0
desktop/core/src/desktop/lib/rest/raz_http_client_test.py

@@ -60,6 +60,26 @@ class TestRazHttpClient():
             timeout=120
             timeout=120
         )
         )
 
 
+        # Check for path having whitespaces (#20)
+        f = client.execute(http_method='GET', path='/gethue/data/banks (1).csv', params={'action': 'getStatus'})
+
+        url = 'https://gethue.dfs.core.windows.net/gethue/data/banks%20(1).csv?action=getStatus'
+        assert_equal('my_file_content', f)
+        raz_get_url.assert_called_with(action='GET', path=url, headers=None)
+        raz_http_execute.assert_called_with(
+            http_method='GET',
+            path='/gethue/data/banks%20(1).csv?action=getStatus&sv=2014-02-14&sr=b&sig=pJL%2FWyed41tptiwBM5ymYre4qF8wzrO05tS5MCjkutc%3D' \
+              '&st=2015-01-02T01%3A40%3A51Z&se=2015-01-02T02%3A00%3A51Z&sp=r',
+            data=None,
+            headers=None,
+            allow_redirects=False,
+            urlencode=False,
+            files=None,
+            stream=False,
+            clear_cookies=False,
+            timeout=120
+        )
+
 
 
   def test_handle_raz_adls_response(self):
   def test_handle_raz_adls_response(self):
     with patch('desktop.lib.rest.raz_http_client.AdlsRazClient.get_url') as raz_get_url:
     with patch('desktop.lib.rest.raz_http_client.AdlsRazClient.get_url') as raz_get_url: