Refactoring net.py to remove custom code and rely on httplib2 instead.
git-svn-id: https://svn.apache.org/repos/asf/chemistry/cmislib/trunk@1449593 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/setup.py b/setup.py
index 81aff09..c651632 100644
--- a/setup.py
+++ b/setup.py
@@ -29,7 +29,8 @@
description = 'Apache Chemistry CMIS client library for Python',
version = version,
install_requires = [
- 'iso8601'
+ 'iso8601',
+ 'httplib2'
],
author = 'Apache Chemistry Project',
author_email = 'dev@chemistry.apache.org',
diff --git a/src/cmislib.egg-info/PKG-INFO b/src/cmislib.egg-info/PKG-INFO
index 5696c19..29deee3 100644
--- a/src/cmislib.egg-info/PKG-INFO
+++ b/src/cmislib.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
Metadata-Version: 1.1
Name: cmislib
-Version: 0.5.1
+Version: 0.6dev
Summary: Apache Chemistry CMIS client library for Python
Home-page: http://chemistry.apache.org/
Author: Apache Chemistry Project
diff --git a/src/cmislib.egg-info/requires.txt b/src/cmislib.egg-info/requires.txt
index 9d296e6..302370d 100644
--- a/src/cmislib.egg-info/requires.txt
+++ b/src/cmislib.egg-info/requires.txt
@@ -1 +1,2 @@
-iso8601
\ No newline at end of file
+iso8601
+httplib2
\ No newline at end of file
diff --git a/src/cmislib/model.py b/src/cmislib/model.py
index 562f2ea..24c23c7 100644
--- a/src/cmislib/model.py
+++ b/src/cmislib/model.py
@@ -177,6 +177,7 @@
"""
doc = self.get(self.repositoryUrl, **self.extArgs)
+ moduleLogger.debug('type of returned obj: %s' % type(doc))
workspaceElements = doc.getElementsByTagNameNS(APP_NS, 'workspace')
# instantiate a Repository object with the first workspace
# element we find
@@ -200,16 +201,17 @@
if (len(self.extArgs) > 0):
kwargs.update(self.extArgs)
- result = Rest().get(url,
+ resp, content = Rest().get(url,
username=self.username,
password=self.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)
@@ -227,13 +229,13 @@
if (len(self.extArgs) > 0):
kwargs.update(self.extArgs)
- result = Rest().delete(url,
+ resp, content = Rest().delete(url,
username=self.username,
password=self.password,
**kwargs)
- if type(result) == HTTPError:
- self._processCommonErrors(result)
- return result
+ if resp['status'] != '200':
+ self._processCommonErrors(resp, url)
+ return content
else:
pass
@@ -252,25 +254,25 @@
if (len(self.extArgs) > 0):
kwargs.update(self.extArgs)
- result = Rest().post(url,
+ resp, content = Rest().post(url,
payload,
contentType,
username=self.username,
password=self.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, payload, contentType, **kwargs):
@@ -287,24 +289,25 @@
if (len(self.extArgs) > 0):
kwargs.update(self.extArgs)
- result = Rest().put(url,
+ resp, content = Rest().put(url,
payload,
contentType,
username=self.username,
password=self.password,
**kwargs)
- if type(result) == HTTPError:
- self._processCommonErrors(result)
- return result
+ moduleLogger.debug("Back from PUT, status:%s" % resp['status'])
+ 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
- def _processCommonErrors(self, error):
+ def _processCommonErrors(self, error, url):
"""
Maps HTTPErrors that are common to all to exceptions. Only errors
@@ -312,20 +315,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)
defaultRepository = property(getDefaultRepository)
repositories = property(getRepositories)
@@ -2465,13 +2468,14 @@
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
+ moduleLogger.debug('back from GET, status: %s' % result['status'])
+ 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:
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)