Forráskód Böngészése

HUE-9153 [core] Avoid logging failure when data contains non unicode in REST resource lib

This is for Python 2 behavior and not 3.
Romain 5 éve
szülő
commit
ec67365087

+ 10 - 8
desktop/core/src/desktop/lib/rest/resource.py

@@ -21,7 +21,7 @@ import posixpath
 import urllib
 import time
 
-from django.utils.encoding import iri_to_uri, smart_str
+from django.utils.encoding import iri_to_uri
 from django.utils.http import urlencode
 
 from desktop import conf
@@ -118,19 +118,21 @@ class Resource(object):
       log_length = conf.REST_RESPONSE_SIZE.get() != -1 and conf.REST_RESPONSE_SIZE.get() if log_response else 0
       duration = time.time() - start_time
       try:
-        message = '%s %s %s%s%s %s%s returned in %dms %s %s %s%s' % (
+        req_data = smart_unicode(data, errors='replace')
+        resp_content = smart_unicode(resp.content, errors='replace')
+        message = u'%s %s %s%s%s %s%s returned in %dms %s %s %s%s' % (
           method,
           type(self._client._session.auth) if self._client._session and self._client._session.auth else None,
           self._client._base_url,
-          smart_str(path, errors='replace'),
+          smart_unicode(path, errors='replace'),
           iri_to_uri('?' + urlencode(params)) if params else '',
-          smart_str(data, errors='replace')[:log_length] if data else '',
-          log_length and len(data) > log_length and '...' or '' if data else '',
+          req_data[:log_length] if data else '',
+          log_length and len(req_data) > log_length and '...' or '' if data else '',
           (duration * 1000),
           resp.status_code if resp else 0,
-          len(resp.content) if resp else 0,
-          smart_str(resp.content, errors='replace')[:log_length] if resp else '',
-          log_length and len(resp.content) > log_length and '...' or '' if resp else ''
+          len(resp_content) if resp else 0,
+          resp_content[:log_length] if resp else '',
+          log_length and len(resp_content) > log_length and '...' or '' if resp else ''
         )
       except:
         short_call_name = '%s %s' % (method, self._client._base_url)

+ 64 - 11
desktop/core/src/desktop/lib/rest/resource_test.py

@@ -16,10 +16,12 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import json
 import sys
 
-from nose.tools import assert_equal, assert_false, assert_true
+from nose.tools import assert_equal, assert_false, assert_true, assert_raises
 
+from desktop.lib.i18n import smart_unicode, smart_str
 from desktop.lib.rest.resource import Resource
 
 
@@ -29,18 +31,69 @@ else:
   from mock import patch, Mock
 
 
-def test_resource_ascii():
+def test_concat_unicode_with_ascii_python2():
+  try:
+    u'The currency is: %s' % '€'
+    if sys.version_info[0] == 2:
+      raise Exception('Should have failed.')
+  except UnicodeDecodeError:
+    pass
+
+  assert_equal(u'The currency is: €', u'The currency is: %s' % smart_unicode('€'))
+
+
+  try:
+    u'%s' % '/user/domain/Джейкоб'
+    if sys.version_info[0] == 2:
+      raise Exception('Should have failed.')
+  except UnicodeDecodeError:
+    pass
+
+  try:
+    u'%s' % smart_str('/user/domain/Джейкоб')
+    if sys.version_info[0] == 2:
+      raise Exception('Should have failed.')
+  except UnicodeDecodeError:
+    pass
+
+  u'%s' % smart_unicode('/user/domain/Джейкоб')
+
+
+def test_avoid_concat_unicode_with_ascii():
+  '''
+  Without smart_unicode() we get:
+  UnicodeDecodeError: 'ascii' codec can't decode byte 0xd0 in position 39: ordinal not in range(128)
+  '''
 
   with patch('desktop.lib.rest.http_client.HttpClient') as HttpClient:
-    client = HttpClient()
-    client.execute = Mock(
-      return_value=Mock(
-        headers={},
-        content='{"FileStatus":{"pathSuffix":"/user/hue/Джейкоб","type":"DIRECTORY","length":0,"owner":"admin","group":"admin","permission":"755","accessTime":0,"modificationTime":1578458822492,"blockSize":0,"replication":0,"childrenNum":0,"fileId":149137,"storagePolicy":0}}'
+    with patch('desktop.lib.rest.resource.LOG.exception') as exception:
+      client = HttpClient()
+      client.execute = Mock(
+        return_value=Mock(
+          headers={},
+          content='Good'
+        )
       )
-    )
 
-    resource = Resource(client)
-    resource.get('/user/domain/Джейкоб')
+      resource = Resource(client)
+      resp = resource.get('/user/domain/')
+
+      assert_false(exception.called)
+      assert_equal('Good', resp)
+
+      client.execute = Mock(
+        return_value=Mock(
+          headers={},
+          content='{"FileStatus":{"pathSuffix":"/user/hue/Джейкоб","type":"DIRECTORY","length":0,"owner":"admin","group":"admin","permission":"755","accessTime":0,"modificationTime":1578458822492,"blockSize":0,"replication":0,"childrenNum":0,"fileId":149137,"storagePolicy":0}}'
+        )
+      )
+
+      resp = resource.get('/user/domain/Джейкоб')
+
+      assert_true(client.execute.called)
+      assert_false(exception.called)  # Should not fail anymore now
+
+      resp = resource.post('/user/domain/Джейкоб', data=json.dumps({'€': '€'}))
 
-    assert_true(client._session)
+      assert_true(client.execute.called)
+      assert_false(exception.called)