You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@chemistry.apache.org by jp...@apache.org on 2016/12/29 18:36:08 UTC

svn commit: r1776460 - in /chemistry/cmislib/trunk/src: cmislib/ cmislib/atompub/ cmislib/browser/ tests/

Author: jpotts
Date: Thu Dec 29 18:36:08 2016
New Revision: 1776460

URL: http://svn.apache.org/viewvc?rev=1776460&view=rev
Log:
Improve UTF-8 handling in cmislib to close #CMIS-996

Modified:
    chemistry/cmislib/trunk/src/cmislib/atompub/binding.py
    chemistry/cmislib/trunk/src/cmislib/browser/binding.py
    chemistry/cmislib/trunk/src/cmislib/cmis_services.py
    chemistry/cmislib/trunk/src/cmislib/domain.py
    chemistry/cmislib/trunk/src/cmislib/exceptions.py
    chemistry/cmislib/trunk/src/cmislib/messages.py
    chemistry/cmislib/trunk/src/cmislib/model.py
    chemistry/cmislib/trunk/src/cmislib/net.py
    chemistry/cmislib/trunk/src/cmislib/util.py
    chemistry/cmislib/trunk/src/tests/cmislibtest.py

Modified: chemistry/cmislib/trunk/src/cmislib/atompub/binding.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/atompub/binding.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/atompub/binding.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/atompub/binding.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file
@@ -27,7 +28,7 @@ from cmislib.net import RESTService as R
 from cmislib.exceptions import CmisException, \
     ObjectNotFoundException, InvalidArgumentException, \
     NotSupportedException
-from cmislib.util import multiple_replace, parsePropValue, parseBoolValue, toCMISValue, parseDateTimeValue
+from cmislib.util import multiple_replace, parsePropValue, parseBoolValue, toCMISValue, parseDateTimeValue, safe_quote
 
 from urllib import quote
 from urlparse import urlparse, urlunparse
@@ -1540,7 +1541,7 @@ class AtomPubRepository(object):
         template = self.getUriTemplates()['objectbypath']['template']
 
         # fill in the template with the path provided
-        params = {'{path}': quote(path, '/'),
+        params = {'{path}': safe_quote(path),
                   '{filter}': '',
                   '{includeAllowableActions}': 'false',
                   '{includePolicyIds}': 'false',

Modified: chemistry/cmislib/trunk/src/cmislib/browser/binding.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/browser/binding.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/browser/binding.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/browser/binding.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file
@@ -25,7 +26,7 @@ from cmislib.domain import CmisId, CmisO
 from cmislib.exceptions import CmisException, InvalidArgumentException,\
                                NotSupportedException, ObjectNotFoundException
 from cmislib.net import RESTService as Rest
-from cmislib.util import parsePropValueByType, parseDateTimeValue
+from cmislib.util import parsePropValueByType, parseDateTimeValue, safe_quote
 import json
 import logging
 import StringIO
@@ -715,7 +716,7 @@ class BrowserRepository(object):
          - includeAllowableActions
         """
 
-        byPathUrl = self.getRootFolderUrl() + quote(path) + "?cmisselector=object"
+        byPathUrl = self.getRootFolderUrl() + safe_quote(path) + "?cmisselector=object"
         result = self._cmisClient.binding.get(byPathUrl.encode('utf-8'),
                                               self._cmisClient.username,
                                               self._cmisClient.password,
@@ -926,7 +927,7 @@ class BrowserRepository(object):
         typesUrl = self.getRepositoryUrl() + "?cmisselector=typeChildren"
 
         if typeId is not None:
-            typesUrl += "&typeId=%s" % (quote(typeId))
+            typesUrl += "&typeId=%s" % (safe_quote(typeId))
 
         result = self._cmisClient.binding.get(typesUrl,
                                               self._cmisClient.username,
@@ -986,7 +987,7 @@ class BrowserRepository(object):
         typesUrl = self.getRepositoryUrl() + "?cmisselector=typeDescendants"
 
         if typeId is not None:
-            typesUrl += "&typeId=%s" % (quote(typeId))
+            typesUrl += "&typeId=%s" % (safe_quote(typeId))
         if depth is not None:
             typesUrl += "&depth=%s" % (depth)
         print typesUrl
@@ -1180,7 +1181,7 @@ class BrowserRepository(object):
         """
 
         # build the CMIS query XML that we're going to POST
-        queryUrl = self.getRepositoryUrl() + "?cmisaction=query&q=" + quote(statement)
+        queryUrl = self.getRepositoryUrl() + "?cmisaction=query&q=" + safe_quote(statement)
 
         # do the POST
         result = self._cmisClient.binding.post(queryUrl.encode('utf-8'),
@@ -3161,27 +3162,6 @@ def encode_multipart_formdata(fields, co
     return content_type, body
 
 
-def safe_urlencode(in_dict):
-
-    """
-    Safe encoding of values taking care of unicode values
-    urllib.urlencode doesn't like unicode values
-    """
-
-    def encoded_dict(in_dict):
-        out_dict = {}
-        for k, v in in_dict.iteritems():
-            if isinstance(v, unicode):
-                v = v.encode('utf8')
-            elif isinstance(v, str):
-                # Must be encoded in UTF-8
-                v.decode('utf8')
-            out_dict[k] = v
-        return out_dict
-
-    return urlencode(encoded_dict(in_dict))
-
-
 class ResultsSerializer(object):
 
     """

Modified: chemistry/cmislib/trunk/src/cmislib/cmis_services.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/cmis_services.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/cmis_services.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/cmis_services.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file

Modified: chemistry/cmislib/trunk/src/cmislib/domain.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/domain.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/domain.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/domain.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file

Modified: chemistry/cmislib/trunk/src/cmislib/exceptions.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/exceptions.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/exceptions.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/exceptions.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file

Modified: chemistry/cmislib/trunk/src/cmislib/messages.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/messages.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/messages.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/messages.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file

Modified: chemistry/cmislib/trunk/src/cmislib/model.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/model.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/model.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/model.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file

Modified: chemistry/cmislib/trunk/src/cmislib/net.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/net.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/net.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/net.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file

Modified: chemistry/cmislib/trunk/src/cmislib/util.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/cmislib/util.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/cmislib/util.py (original)
+++ chemistry/cmislib/trunk/src/cmislib/util.py Thu Dec 29 18:36:08 2016
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 #      Licensed to the Apache Software Foundation (ASF) under one
 #      or more contributor license agreements.  See the NOTICE file
@@ -24,10 +25,46 @@ import iso8601
 import logging
 import datetime
 from cmislib.domain import CmisId
+from urllib import quote
 
 moduleLogger = logging.getLogger('cmislib.util')
 
 
+def to_utf8(value):
+
+    """ Safe encodng of value to utf-8 taking care of unicode values
+    """
+    if isinstance(value, unicode):
+        value = value.encode('utf8')
+    return value
+
+
+def safe_urlencode(in_dict):
+
+    """
+    Safe encoding of values taking care of unicode values
+    urllib.urlencode doesn't like unicode values
+    """
+
+    def encoded_dict(in_dict):
+        out_dict = {}
+        for k, v in in_dict.iteritems():
+            out_dict[k] = to_utf8(v)
+        return out_dict
+
+    return urlencode(encoded_dict(in_dict))
+
+
+def safe_quote(value):
+
+    """
+    Safe encoding of value taking care of unicode value
+    urllib.quote doesn't like unicode values
+    """
+
+    return quote(to_utf8(value))
+
+
 def multiple_replace(aDict, text):
 
     """

Modified: chemistry/cmislib/trunk/src/tests/cmislibtest.py
URL: http://svn.apache.org/viewvc/chemistry/cmislib/trunk/src/tests/cmislibtest.py?rev=1776460&r1=1776459&r2=1776460&view=diff
==============================================================================
--- chemistry/cmislib/trunk/src/tests/cmislibtest.py (original)
+++ chemistry/cmislib/trunk/src/tests/cmislibtest.py Thu Dec 29 18:36:08 2016
@@ -346,33 +346,34 @@ class RepositoryTest(CmisTestBase):
     def testGetObjectByPath(self):
         """Create test objects (one folder, one document) then try to get
         them by path"""
-        # names of folders and test docs
-        parentFolderName = 'testGetObjectByPath folder'
-        subFolderName = 'subfolder'
-        docName = 'testdoc'
+        # names of folders and test docs (without and with unicode char)
+        for suffix in ['', u'_éà€$']:
+            parentFolderName = 'testGetObjectByPath folder' + suffix
+            subFolderName = 'subfolder' + suffix
+            docName = 'testdoc' + suffix
 
-        # create the folder structure
-        parentFolder = self._testFolder.createFolder(parentFolderName)
-        subFolder = parentFolder.createFolder(subFolderName)
-        # use the subfolder path to get the folder by path
-        subFolderPath = subFolder.getProperties().get("cmis:path")
-        searchFolder = self._repo.getObjectByPath(subFolderPath)
-        self.assertEquals(subFolder.getObjectId(), searchFolder.getObjectId())
+            # create the folder structure
+            parentFolder = self._testFolder.createFolder(parentFolderName)
+            subFolder = parentFolder.createFolder(subFolderName)
+            # use the subfolder path to get the folder by path
+            subFolderPath = subFolder.getProperties().get("cmis:path")
+            searchFolder = self._repo.getObjectByPath(subFolderPath)
+            self.assertEquals(subFolder.getObjectId(), searchFolder.getObjectId())
 
-        # create a test doc
-        doc = subFolder.createDocument(docName)
-        # ask the doc for its paths
-        searchDocPaths = doc.getPaths()
-        # for each path in the list, try to get the object by path
-        # this is better than building a path with the doc's name b/c the name
-        # isn't guaranteed to be used as the path segment (see CMIS-232)
-        for path in searchDocPaths:
-            searchDoc = self._repo.getObjectByPath(path)
-            self.assertEquals(doc.getObjectId(), searchDoc.getObjectId())
+            # create a test doc
+            doc = subFolder.createDocument(docName)
+            # ask the doc for its paths
+            searchDocPaths = doc.getPaths()
+            # for each path in the list, try to get the object by path
+            # this is better than building a path with the doc's name b/c the name
+            # isn't guaranteed to be used as the path segment (see CMIS-232)
+            for path in searchDocPaths:
+                searchDoc = self._repo.getObjectByPath(path)
+                self.assertEquals(doc.getObjectId(), searchDoc.getObjectId())
 
-        # get the subfolder by path, then ask for its children
-        subFolder = self._repo.getObjectByPath(subFolderPath)
-        self.assertEquals(len(subFolder.getChildren().getResults()), 1)
+            # get the subfolder by path, then ask for its children
+            subFolder = self._repo.getObjectByPath(subFolderPath)
+            self.assertEquals(len(subFolder.getChildren().getResults()), 1)
 
     # getting unfiled documents may work for the atom pub binding for some servers
     # but it isn't part of the spec so removing this test for now