blob: 8d54c69f0c763cff649b27dd475870c5b710d7e9 [file] [log] [blame]
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Authors:
# Jeff Potts, Optaros
#
'''
Module that knows how to connect to the AtomPub Binding of a CMIS repo
'''
from urllib import urlencode
from urllib2 import HTTPBasicAuthHandler, \
HTTPPasswordMgrWithDefaultRealm, \
HTTPRedirectHandler, \
HTTPDefaultErrorHandler, \
HTTPError, \
Request, \
build_opener
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 RESTService(object):
"""
Generic service for interacting with an HTTP end point. Sets headers
such as the USER_AGENT and builds the basic auth handler.
"""
def __init__(self):
self.user_agent = 'cmislib/%s +http://code.google.com/p/cmislib/'
def get(self,
url,
username=None,
password=None,
**kwargs):
""" Makes a get request to the URL specified."""
if kwargs:
if url.find('?') >= 0:
url = url + '&' + urlencode(kwargs)
else:
url = url + '?' + urlencode(kwargs)
request = RESTRequest(url, method='GET')
# add a user-agent
request.add_header('User-Agent', self.user_agent)
# create a password manager
passwordManager = HTTPPasswordMgrWithDefaultRealm()
passwordManager.add_password(None, url, username, password)
opener = build_opener(SmartRedirectHandler(),
DefaultErrorHandler(),
HTTPBasicAuthHandler(passwordManager))
return opener.open(request)
def delete(self, url, username=None, password=None, **kwargs):
""" Makes a delete request to the URL specified. """
if kwargs:
if url.find('?') >= 0:
url = url + '&' + urlencode(kwargs)
else:
url = url + '?' + urlencode(kwargs)
request = RESTRequest(url, method='DELETE')
# add a user-agent
request.add_header('User-Agent', self.user_agent)
# create a password manager
passwordManager = HTTPPasswordMgrWithDefaultRealm()
passwordManager.add_password(None, url, username, password)
opener = build_opener(SmartRedirectHandler(),
DefaultErrorHandler(),
HTTPBasicAuthHandler(passwordManager))
#try:
# opener.open(request)
#except urllib2.HTTPError, e:
# if e.code is not 204:
# raise e
#return None
return opener.open(request)
def put(self,
url,
payload,
contentType,
username=None,
password=None,
**kwargs):
"""
Makes a PUT request to the URL specified and includes the payload
that gets passed in. The content type header gets set to the
specified content type.
"""
if kwargs:
if url.find('?') >= 0:
url = url + '&' + urlencode(kwargs)
else:
url = url + '?' + urlencode(kwargs)
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)
# create a password manager
passwordManager = HTTPPasswordMgrWithDefaultRealm()
passwordManager.add_password(None, url, username, password)
opener = build_opener(SmartRedirectHandler(),
DefaultErrorHandler(),
HTTPBasicAuthHandler(passwordManager))
return opener.open(request)
def post(self,
url,
payload,
contentType,
username=None,
password=None,
**kwargs):
"""
Makes a POST request to the URL specified and posts the payload
that gets passed in. The content type header gets set to the
specified content type.
"""
if kwargs:
if url.find('?') >= 0:
url = url + '&' + urlencode(kwargs)
else:
url = url + '?' + urlencode(kwargs)
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)
# create a password manager
passwordManager = HTTPPasswordMgrWithDefaultRealm()
passwordManager.add_password(None, url, username, password)
opener = build_opener(SmartRedirectHandler(),
DefaultErrorHandler(),
HTTPBasicAuthHandler(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