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)