Merged httplib2 change from head into cmislib_refactor branch.
git-svn-id: https://svn.apache.org/repos/asf/chemistry/cmislib/branches/binding_refactor@1450920 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/src/cmislib/atompub_binding.py b/src/cmislib/atompub_binding.py
index 886d0ea..0f579d1 100644
--- a/src/cmislib/atompub_binding.py
+++ b/src/cmislib/atompub_binding.py
@@ -114,16 +114,16 @@
if (len(self.extArgs) > 0):
kwargs.update(self.extArgs)
- result = Rest().get(url,
+ resp, content = Rest().get(url,
username=username,
password=password,
**kwargs)
- if type(result) == HTTPError:
- self._processCommonErrors(result)
- return result
+ if resp['status'] != '200':
+ self._processCommonErrors(resp, url)
+ return content
else:
try:
- return minidom.parse(result)
+ return minidom.parseString(content)
except ExpatError:
raise CmisException('Could not parse server response', url)
@@ -141,13 +141,13 @@
if (len(self.extArgs) > 0):
kwargs.update(self.extArgs)
- result = Rest().delete(url,
+ resp, content = Rest().delete(url,
username=username,
password=password,
**kwargs)
- if type(result) == HTTPError:
- self._processCommonErrors(result)
- return result
+ if resp['status'] != '200':
+ self._processCommonErrors(resp, url)
+ return content
else:
pass
@@ -166,25 +166,25 @@
if (len(self.extArgs) > 0):
kwargs.update(self.extArgs)
- result = Rest().post(url,
+ resp, content = Rest().post(url,
payload,
contentType,
username=username,
password=password,
**kwargs)
- if type(result) != HTTPError:
+ if resp['status'] == '200':
try:
- return minidom.parse(result)
+ return minidom.parseString(content)
except ExpatError:
raise CmisException('Could not parse server response', url)
- elif result.code == 201:
+ elif resp['status'] == '201':
try:
- return minidom.parse(result)
+ return minidom.parseString(content)
except ExpatError:
raise CmisException('Could not parse server response', url)
else:
- self._processCommonErrors(result)
- return result
+ self._processCommonErrors(resp, url)
+ return resp
def put(self, url, username, password, payload, contentType, **kwargs):
@@ -201,19 +201,19 @@
if (len(self.extArgs) > 0):
kwargs.update(self.extArgs)
- result = Rest().put(url,
+ resp, content = Rest().put(url,
payload,
contentType,
username=username,
password=password,
**kwargs)
- if type(result) == HTTPError:
- self._processCommonErrors(result)
- return result
+ if resp['status'] != '200' and resp['status'] != '201':
+ self._processCommonErrors(resp, url)
+ return content
else:
#if result.headers['content-length'] != '0':
try:
- return minidom.parse(result)
+ return minidom.parseString(content)
except ExpatError:
# This may happen and is normal
return None
@@ -425,9 +425,6 @@
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# return the result set
return AtomPubResultSet(self._cmisClient, self._repository, result)
@@ -638,8 +635,6 @@
self.xmlDoc.toxml(encoding='utf-8'),
ATOM_XML_ENTRY_TYPE,
**args)
- if type(result) == HTTPError:
- raise CmisException(result.code)
def delete(self, **kwargs):
@@ -661,9 +656,6 @@
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
def applyPolicy(self, policyId):
"""
@@ -707,9 +699,6 @@
xmlDoc.toxml(encoding='utf-8'),
ATOM_XML_TYPE)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# instantiate CmisObject objects with the results and return the list
entryElements = result.getElementsByTagNameNS(ATOM_NS, 'entry')
assert(len(entryElements) == 1), "Expected entry element in result from relationship URL post"
@@ -746,9 +735,6 @@
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# return the result set
return AtomPubResultSet(self._cmisClient, self._repository, result)
@@ -795,8 +781,6 @@
result = self._cmisClient.binding.get(aclUrl.encode('utf-8'),
self._cmisClient.username,
self._cmisClient.password)
- if type(result) == HTTPError:
- raise CmisException(result.code)
return AtomPubACL(xmlDoc=result)
else:
raise NotSupportedException
@@ -828,8 +812,6 @@
self._cmisClient.password,
acl.getXmlDoc().toxml(encoding='utf-8'),
CMIS_ACL_TYPE)
- if type(result) == HTTPError:
- raise CmisException(result.code)
return AtomPubACL(xmlDoc=result)
else:
raise NotSupportedException
@@ -1523,8 +1505,6 @@
self._cmisClient.username,
self._cmisClient.password,
**addOptions)
- if type(result) == HTTPError:
- raise CmisException(result.code)
# instantiate CmisObject objects with the results and return the list
entryElements = result.getElementsByTagNameNS(ATOM_NS, 'entry')
@@ -1590,8 +1570,6 @@
self._cmisClient.password,
xmlDoc.toxml(encoding='utf-8'),
CMIS_QUERY_TYPE)
- if type(result) == HTTPError:
- raise CmisException(result.code)
# return the result set
return AtomPubResultSet(self._cmisClient, self, result)
@@ -1650,8 +1628,6 @@
self._cmisClient.username,
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
# return the result set
return AtomPubChangeEntryResultSet(self._cmisClient, self, result)
@@ -1757,8 +1733,6 @@
self._cmisClient.password,
xmlDoc.toxml(encoding='utf-8'),
ATOM_XML_ENTRY_TYPE)
- if type(result) == HTTPError:
- raise CmisException(result.code)
# what comes back is the XML for the new document,
# so use it to instantiate a new document
@@ -1903,8 +1877,6 @@
self._cmisClient.username,
self._cmisClient.password,
**kwargs)
- if (type(result) == HTTPError):
- raise CmisException(result.code)
# return the result set
return AtomPubResultSet(self._cmisClient, self, result)
@@ -2020,8 +1992,6 @@
result = self._cmisClient.binding.get(link.encode('utf-8'),
self._cmisClient.username,
self._cmisClient.password)
- if (type(result) == HTTPError):
- raise CmisException(result.code)
# return the result
self._xmlDoc = result
@@ -2249,9 +2219,6 @@
entryXmlDoc.toxml(encoding='utf-8'),
ATOM_XML_ENTRY_TYPE)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# now that the doc is checked out, we need to refresh the XML
# to pick up the prop updates related to a checkout
self.reload()
@@ -2372,9 +2339,6 @@
ATOM_XML_TYPE,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
return AtomPubDocument(self._cmisClient, self._repository, xmlDoc=result)
def getLatestVersion(self, **kwargs):
@@ -2443,9 +2407,6 @@
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# return the result set
return AtomPubResultSet(self._cmisClient, self._repository, result)
@@ -2479,13 +2440,13 @@
srcUrl = contentElements[0].attributes['src'].value
# the cmis client class parses non-error responses
- result = Rest().get(srcUrl.encode('utf-8'),
+ result, content = Rest().get(srcUrl.encode('utf-8'),
username=self._cmisClient.username,
password=self._cmisClient.password,
**self._cmisClient.extArgs)
- if result.code != 200:
- raise CmisException(result.code)
- return result
+ if result['status'] != '200':
+ raise CmisException(result['status'])
+ return StringIO.StringIO(content)
else:
# otherwise, try to return the value of the content element
if contentElements[0].childNodes:
@@ -2536,9 +2497,6 @@
mimetype,
**args)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# what comes back is the XML for the updated document,
# which is not required by the spec to be the same document
# we just updated, so use it to instantiate a new document
@@ -2576,8 +2534,6 @@
self._cmisClient.username,
self._cmisClient.password,
**args)
- if type(result) == HTTPError:
- raise CmisException(result.code)
def getRenditions(self):
@@ -2633,9 +2589,6 @@
filter='cmis:path',
includeRelativePathSegment=True)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
paths = []
rs = AtomPubResultSet(self._cmisClient, self._repository, result)
for res in rs:
@@ -2702,8 +2655,6 @@
self._cmisClient.password,
entryXml.toxml(encoding='utf-8'),
ATOM_XML_ENTRY_TYPE)
- if type(result) == HTTPError:
- raise CmisException(result.code)
# what comes back is the XML for the new folder,
# so use it to instantiate a new folder then return it
@@ -2809,9 +2760,6 @@
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# return the result set
return AtomPubResultSet(self._cmisClient, self._repository, result)
@@ -2897,9 +2845,6 @@
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# return the result set
return AtomPubResultSet(self._cmisClient, self._repository, result)
@@ -2937,9 +2882,6 @@
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# return the result set
return AtomPubResultSet(self._cmisClient, self, result)
@@ -2957,9 +2899,6 @@
self._cmisClient.username,
self._cmisClient.password)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
# return the result set
return AtomPubFolder(self._cmisClient, self._repository, xmlDoc=result)
@@ -2991,9 +2930,6 @@
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
-
def addObject(self, cmisObject, **kwargs):
"""
@@ -3029,8 +2965,6 @@
cmisObject.xmlDoc.toxml(encoding='utf-8'),
ATOM_XML_ENTRY_TYPE,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
def removeObject(self, cmisObject):
@@ -3053,8 +2987,6 @@
cmisObject.xmlDoc.toxml(encoding='utf-8'),
ATOM_XML_ENTRY_TYPE,
**args)
- if type(result) == HTTPError:
- raise CmisException(result.code)
def getPaths(self):
"""
@@ -3321,8 +3253,6 @@
self._cmisClient.username,
self._cmisClient.password,
**kwargs)
- if type(result) == HTTPError:
- raise CmisException(result.code)
# instantiate CmisObject objects with the results and return the list
entryElements = result.getElementsByTagNameNS(ATOM_NS, 'entry')
@@ -3758,8 +3688,6 @@
result = self._cmisClient.binding.get(aclUrl.encode('utf-8'),
self._cmisClient.username,
self._cmisClient.password)
- if type(result) == HTTPError:
- raise CmisException(result.code)
return AtomPubACL(xmlDoc=result)
def getChangeTime(self):
@@ -3908,8 +3836,6 @@
result = self._cmisClient.binding.get(aclUrl.encode('utf-8'),
self._cmisClient.username,
self._cmisClient.password)
- if type(result) == HTTPError:
- raise CmisException(result.code)
return AtomPubACL(xmlDoc=result)
def getChangeTime(self):
diff --git a/src/cmislib/cmis_services.py b/src/cmislib/cmis_services.py
index bea5212..a78ad8a 100644
--- a/src/cmislib/cmis_services.py
+++ b/src/cmislib/cmis_services.py
@@ -28,7 +28,7 @@
def getRepositoryService():
pass
- def _processCommonErrors(self, error):
+ def _processCommonErrors(self, error, url):
"""
Maps HTTPErrors that are common to all to exceptions. Only errors
@@ -36,20 +36,20 @@
here. Callers should handle the rest.
"""
- if error.status == 401:
- raise PermissionDeniedException(error.status, error.url)
- elif error.status == 400:
- raise InvalidArgumentException(error.status, error.url)
- elif error.status == 404:
- raise ObjectNotFoundException(error.status, error.url)
- elif error.status == 403:
- raise PermissionDeniedException(error.status, error.url)
- elif error.status == 405:
- raise NotSupportedException(error.status, error.url)
- elif error.status == 409:
- raise UpdateConflictException(error.status, error.url)
- elif error.status == 500:
- raise RuntimeException(error.status, error.url)
+ if error['status'] == '401':
+ raise PermissionDeniedException(error['status'], url)
+ elif error['status'] == '400':
+ raise InvalidArgumentException(error['status'], url)
+ elif error['status'] == '404':
+ raise ObjectNotFoundException(error['status'], url)
+ elif error['status'] == '403':
+ raise PermissionDeniedException(error['status'], url)
+ elif error['status'] == '405':
+ raise NotSupportedException(error['status'], url)
+ elif error['status'] == '409':
+ raise UpdateConflictException(error['status'], url)
+ elif error['status'] == '500':
+ raise RuntimeException(error['status'], url)
class RepositoryServiceIfc(object):
diff --git a/src/cmislib/model.py b/src/cmislib/model.py
index cc86368..cb055cc 100644
--- a/src/cmislib/model.py
+++ b/src/cmislib/model.py
@@ -98,28 +98,6 @@
return self.binding.getRepositoryService().getDefaultRepository(self)
- def _processCommonErrors(self, error):
-
- """
- Maps HTTPErrors that are common to all to exceptions. Only errors
- that are truly global, like 401 not authorized, should be handled
- here. Callers should handle the rest.
- """
-
- if error.status == 401:
- raise PermissionDeniedException(error.status, error.url)
- elif error.status == 400:
- raise InvalidArgumentException(error.status, error.url)
- elif error.status == 404:
- raise ObjectNotFoundException(error.status, error.url)
- elif error.status == 403:
- raise PermissionDeniedException(error.status, error.url)
- elif error.status == 405:
- raise NotSupportedException(error.status, error.url)
- elif error.status == 409:
- raise UpdateConflictException(error.status, error.url)
- elif error.status == 500:
- raise RuntimeException(error.status, error.url)
defaultRepository = property(getDefaultRepository)
repositories = property(getRepositories)
diff --git a/src/cmislib/net.py b/src/cmislib/net.py
index 11a757a..ab66717 100644
--- a/src/cmislib/net.py
+++ b/src/cmislib/net.py
@@ -21,77 +21,8 @@
'''
from urllib import urlencode
-from urllib2 import HTTPBasicAuthHandler, \
- HTTPPasswordMgrWithDefaultRealm, \
- HTTPRedirectHandler, \
- HTTPDefaultErrorHandler, \
- HTTPError, \
- Request, \
- build_opener, \
- AbstractBasicAuthHandler
import logging
-
-
-class SmartRedirectHandler(HTTPRedirectHandler):
-
- """ Handles 301 and 302 redirects """
-
- def http_error_301(self, req, fp, code, msg, headers):
- """ Handle a 301 error """
- result = HTTPRedirectHandler.http_error_301(
- self, req, fp, code, msg, headers)
- result.status = code
- return result
-
- def http_error_302(self, req, fp, code, msg, headers):
- """ Handle a 302 error """
- result = HTTPRedirectHandler.http_error_302(
- self, req, fp, code, msg, headers)
- result.status = code
- return result
-
-
-class DefaultErrorHandler(HTTPDefaultErrorHandler):
-
- """ Default error handler """
-
- def http_error_default(self, req, fp, code, msg, headers):
- """Provide an implementation for the default handler"""
- result = HTTPError(
- req.get_full_url(), code, msg, headers, fp)
- result.status = code
- return result
-
-
-class ContextualBasicAuthHandler(HTTPBasicAuthHandler):
-
- """
- Handles 401 errors without recursing indefinitely. The recursing
- behaviour has been introduced in Python 2.6.5 to handle 401 redirects
- used by some architectures of authentication.
- """
-
- def __init__(self, password_mgr):
- HTTPBasicAuthHandler.__init__(self, password_mgr)
- self.authContext = set([])
-
- def http_error_401(self, req, fp, code, msg, headers):
- """Override the default autoretry behaviour"""
- url = req.get_full_url()
- hdrs = req.header_items()
- hdrs = ', '.join(['%s: %s' % (key, value)
- for key, value in sorted(hdrs)])
- context = (url, hdrs)
- if context in self.authContext:
- self.authContext.clear()
- result = HTTPError(
- req.get_full_url(), code, msg, headers, fp)
- result.status = code
- return result
- self.authContext.add(context)
- return self.http_error_auth_reqed('www-authenticate',
- url, req, headers)
-
+import httplib2
class RESTService(object):
@@ -112,7 +43,7 @@
""" Makes a get request to the URL specified."""
- headers = None
+ headers = {}
if kwargs:
if 'headers' in kwargs:
headers = kwargs['headers']
@@ -125,30 +56,17 @@
self.logger.debug('About to do a GET on:' + url)
- request = RESTRequest(url, method='GET')
+ h = httplib2.Http()
+ h.add_credentials(username, password)
+ headers['User-Agent'] = self.user_agent
- # add a user-agent
- request.add_header('User-Agent', self.user_agent)
- if headers:
- for k, v in headers.items():
- self.logger.debug('Adding header:%s:%s' % (k, v))
- request.add_header(k, v)
-
- # create a password manager
- passwordManager = HTTPPasswordMgrWithDefaultRealm()
- passwordManager.add_password(None, url, username, password)
-
- opener = build_opener(SmartRedirectHandler(),
- DefaultErrorHandler(),
- ContextualBasicAuthHandler(passwordManager))
-
- return opener.open(request)
+ return h.request(url, method='GET', headers=headers)
def delete(self, url, username=None, password=None, **kwargs):
""" Makes a delete request to the URL specified. """
- headers = None
+ headers = {}
if kwargs:
if 'headers' in kwargs:
headers = kwargs['headers']
@@ -161,30 +79,11 @@
self.logger.debug('About to do a DELETE on:' + url)
- request = RESTRequest(url, method='DELETE')
+ h = httplib2.Http()
+ h.add_credentials(username, password)
+ headers['User-Agent'] = self.user_agent
- # add a user-agent
- request.add_header('User-Agent', self.user_agent)
- if headers:
- for k, v in headers.items():
- self.logger.debug('Adding header:%s:%s' % (k, v))
- request.add_header(k, v)
-
- # create a password manager
- passwordManager = HTTPPasswordMgrWithDefaultRealm()
- passwordManager.add_password(None, url, username, password)
-
- opener = build_opener(SmartRedirectHandler(),
- DefaultErrorHandler(),
- ContextualBasicAuthHandler(passwordManager))
-
- #try:
- # opener.open(request)
- #except urllib2.HTTPError, e:
- # if e.code is not 204:
- # raise e
- #return None
- return opener.open(request)
+ return h.request(url, method='DELETE', headers=headers)
def put(self,
url,
@@ -200,7 +99,7 @@
specified content type.
"""
- headers = None
+ headers = {}
if kwargs:
if 'headers' in kwargs:
headers = kwargs['headers']
@@ -213,27 +112,12 @@
self.logger.debug('About to do a PUT on:' + url)
- request = RESTRequest(url, payload, method='PUT')
-
- # set the content type header
- request.add_header('Content-Type', contentType)
-
- # add a user-agent
- request.add_header('User-Agent', self.user_agent)
- if headers:
- for k, v in headers.items():
- self.logger.debug('Adding header:%s:%s' % (k, v))
- request.add_header(k, v)
-
- # create a password manager
- passwordManager = HTTPPasswordMgrWithDefaultRealm()
- passwordManager.add_password(None, url, username, password)
-
- opener = build_opener(SmartRedirectHandler(),
- DefaultErrorHandler(),
- ContextualBasicAuthHandler(passwordManager))
-
- return opener.open(request)
+ h = httplib2.Http()
+ h.add_credentials(username, password)
+ headers['User-Agent'] = self.user_agent
+ if contentType != None:
+ headers['Content-Type'] = contentType
+ return h.request(url, body=payload, method='PUT', headers=headers)
def post(self,
url,
@@ -249,7 +133,7 @@
specified content type.
"""
- headers = None
+ headers = {}
if kwargs:
if 'headers' in kwargs:
headers = kwargs['headers']
@@ -262,47 +146,9 @@
self.logger.debug('About to do a POST on:' + url)
- request = RESTRequest(url, payload, method='POST')
-
- # set the content type header
- request.add_header('Content-Type', contentType)
-
- # add a user-agent
- request.add_header('User-Agent', self.user_agent)
- if headers:
- for k, v in headers.items():
- self.logger.debug('Adding header:%s:%s' % (k, v))
- request.add_header(k, v)
-
- # create a password manager
- passwordManager = HTTPPasswordMgrWithDefaultRealm()
- passwordManager.add_password(None, url, username, password)
-
- opener = build_opener(SmartRedirectHandler(),
- DefaultErrorHandler(),
- ContextualBasicAuthHandler(passwordManager))
-
- try:
- return opener.open(request)
- except HTTPError, e:
- if e.code is not 201:
- return e
- else:
- return e.read()
-
-
-class RESTRequest(Request):
-
- """
- Overrides urllib's request default behavior
- """
-
- def __init__(self, *args, **kwargs):
- """ Constructor """
- self._method = kwargs.pop('method', 'GET')
- assert self._method in ['GET', 'POST', 'PUT', 'DELETE']
- Request.__init__(self, *args, **kwargs)
-
- def get_method(self):
- """ Override the get method """
- return self._method
+ h = httplib2.Http()
+ h.add_credentials(username, password)
+ headers['User-Agent'] = self.user_agent
+ if contentType != None:
+ headers['Content-Type'] = contentType
+ return h.request(url, body=payload, method='POST', headers=headers)
diff --git a/src/tests/settings.py b/src/tests/settings.py
index c70d009..fe79a5f 100644
--- a/src/tests/settings.py
+++ b/src/tests/settings.py
@@ -48,7 +48,7 @@
# For repositories that support setting an ACL, the name of an existing
# principal ID to add to the ACL of a test object. Some repositories care
# if this ID doesn't exist. Some repositories don't.
-TEST_PRINCIPAL_ID = 'tuser1'
+TEST_PRINCIPAL_ID = 'anyone'
# For repositories that may index test content asynchronously, the number of
# times a query is retried before giving up.
MAX_FULL_TEXT_TRIES = 10