177 lines
5.5 KiB
Python
177 lines
5.5 KiB
Python
"""
|
|
Mandaye HTTP object: Response, Request and Headers
|
|
"""
|
|
|
|
import copy
|
|
import Cookie
|
|
import gzip
|
|
import StringIO
|
|
import zlib
|
|
|
|
from mandaye.log import logger
|
|
|
|
class HTTPHeader(dict):
|
|
""" Mandaye class to manage HTTP header
|
|
"""
|
|
|
|
def load_httpmessage(self, headers):
|
|
""" headers: HTTPMessage (httplib)
|
|
"""
|
|
for key in headers.keys():
|
|
self[key.lower()] = headers.getheaders(key)
|
|
|
|
def load_from_list(self, headers):
|
|
""" headers: list with the headers
|
|
"""
|
|
for header in headers:
|
|
self[header[0].lower()] = [header[1]]
|
|
|
|
def load_from_dict(self, headers):
|
|
for key, value in headers.iteritems():
|
|
self.addheader(key, value)
|
|
|
|
def addheader(self, name, value):
|
|
""" name: field name
|
|
value: string with the field value """
|
|
self[name.lower()] = [value]
|
|
|
|
def delheader(self, name):
|
|
""" name: field name
|
|
"""
|
|
del self[name.lower()]
|
|
|
|
def addheaders(self, name, values):
|
|
""" name: field name
|
|
values: list of field values """
|
|
self[name.lower()] = value
|
|
|
|
def getheader(self, name):
|
|
if self.has_key(name.lower()):
|
|
return self[name.lower()][0]
|
|
else:
|
|
return None
|
|
|
|
def getheaders(self):
|
|
res = {}
|
|
for key, values in self.iteritems():
|
|
res[key.lower()] = ', '.join(values)
|
|
return res
|
|
|
|
def addsetcookies(self, cookies):
|
|
""" cookies: Cookie.SimpleCookie object """
|
|
self['set-cookie'] = []
|
|
for cookie in cookies.values():
|
|
self['set-cookie'].append(cookie.output(header=""))
|
|
|
|
def items(self):
|
|
items = super(HTTPHeader, self).items()
|
|
new_items = []
|
|
for (key, values) in items:
|
|
for value in values:
|
|
new_items.append((key, value))
|
|
return new_items
|
|
|
|
def copy(self):
|
|
return copy.deepcopy(self)
|
|
|
|
class HTTPRequest(object):
|
|
""" Mandaye HTTP Request
|
|
"""
|
|
|
|
def __init__(self, cookies=None, headers=None, req_method="GET", msg=None, target=None):
|
|
"""
|
|
cookies: BaseCookie object (http://docs.python.org/library/cookie.html)
|
|
headers: HTTPHeader object
|
|
req_method: GET or POST
|
|
msg: message body str
|
|
"""
|
|
self.cookies = cookies
|
|
self.headers = headers
|
|
self.msg = msg
|
|
self.req_method = req_method
|
|
if not headers:
|
|
self.headers = HTTPHeader()
|
|
if not cookies:
|
|
self.cookies = Cookie.BaseCookie()
|
|
self.target = target
|
|
|
|
def __repr__(self):
|
|
d = self.__dict__
|
|
return '<%s %s>' % (self.__class__.__name__, d)
|
|
|
|
def copy(self):
|
|
return copy.deepcopy(self)
|
|
|
|
class HTTPResponse(object):
|
|
""" Mandaye HTTP Response
|
|
"""
|
|
|
|
def __init__(self, code=None, reason=None, headers=None, msg=None, cookies=None):
|
|
"""
|
|
code: integer return code (200, 302, 404, ..)
|
|
reason: string with http status (ex: OK, Not Found, ...)
|
|
headers: dictionary with the headers
|
|
msg: message body str
|
|
cookies: BaseCookie object (http://docs.python.org/library/cookie.html)
|
|
"""
|
|
self.code = code
|
|
self.reason = reason
|
|
self.headers = headers
|
|
self.msg = msg
|
|
self.cookies = cookies
|
|
if not headers:
|
|
self.headers = HTTPHeader()
|
|
if not cookies:
|
|
self.cookies = Cookie.BaseCookie()
|
|
|
|
def decompress(self):
|
|
""" decompress response content when content-encoding is enable
|
|
"""
|
|
encoding = self.headers.getheader('Content-Encoding')
|
|
if not encoding:
|
|
return None
|
|
if encoding.lower() == 'gzip' or encoding.lower() == 'x-gzip':
|
|
self.msg = StringIO.StringIO(self.msg)
|
|
gzipper = gzip.GzipFile(fileobj=self.msg)
|
|
self.msg = gzipper.read()
|
|
del self.headers['content-encoding']
|
|
elif encoding.lower() == 'deflate':
|
|
try:
|
|
self.msg = zlib.decompress(self.msg, -zlib.MAX_WBITS)
|
|
except zlib.error:
|
|
try:
|
|
self.msg = zlib.decompress(self.msg)
|
|
except zlib.error:
|
|
logger.warning("Unable to decompress defalte response")
|
|
|
|
del self.headers['content-encoding']
|
|
else:
|
|
logger.warning("%s unsupported content encoding format" % encoding)
|
|
|
|
def load_from_urllib(self, response):
|
|
""" response: urrlib.addinfourl
|
|
"""
|
|
self.headers.load_httpmessage(response.headers)
|
|
for setcookie in response.headers.getheaders('set-cookie'):
|
|
try:
|
|
# WARNING hack for biblio.vincennes.fr
|
|
# during a basic login we have two set-coookie with the same key
|
|
# SimpleCookie will merge the 2 set-cookies by default
|
|
# this hack force to keep the second Set-cookie only
|
|
cookie = Cookie.SimpleCookie("Set-Cookie: %s" % setcookie)
|
|
cookie = cookie.values()[0]
|
|
if self.cookies.has_key(cookie.key):
|
|
del self.cookies[cookie.key]
|
|
self.cookies.load("Set-Cookie: %s" % setcookie)
|
|
except Cookie.CookieError:
|
|
logger.warning("can't parse cookie: %r", setcookie)
|
|
self.code = response.code
|
|
self.reason = response.msg
|
|
if self.code != 304:
|
|
self.msg = response.read()
|
|
|
|
def __repr__(self):
|
|
d = self.__dict__
|
|
return '<%s %s>' % (self.__class__.__name__, d)
|
|
|