#
# ElementSOAP
# $Id: HTTPClient.py 2924 2006-11-19 22:24:22Z fredrik $
#
# a simple XML-over-HTTP client
#
# for more information, see:
#
# http://effbot.org/zone/http-xml.htm
#
# history:
# 2002-07-12 fl created
# 2002-07-14 fl added to the xmltoys library
# 2002-07-17 fl changed constructor to take a full URI
# 2003-05-13 fl added parser argument
# 2003-11-16 fl added HTTPError exception
# 2006-11-19 fl added HTTPS support (based on a patch by Florent Aide).
# 2006-11-19 fl use parser as callable, not parser class
#
# Copyright (c) 1999-2006 by Fredrik Lundh. All rights reserved.
#
# fredrik@pythonware.com
# http://www.pythonware.com
#
# --------------------------------------------------------------------
# The ElementSOAP library is
#
# Copyright (c) 1999-2006 by Fredrik Lundh
#
# By obtaining, using, and/or copying this software and/or its
# associated documentation, you agree that you have read, understood,
# and will comply with the following terms and conditions:
#
# Permission to use, copy, modify, and distribute this software and
# its associated documentation for any purpose and without fee is
# hereby granted, provided that the above copyright notice appears in
# all copies, and that both that copyright notice and this permission
# notice appear in supporting documentation, and that the name of
# Secret Labs AB or the author not be used in advertising or publicity
# pertaining to distribution of the software without specific, written
# prior permission.
#
# SECRET LABS AB AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
# TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT-
# ABILITY AND FITNESS. IN NO EVENT SHALL SECRET LABS AB OR THE AUTHOR
# BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
# OF THIS SOFTWARE.
# --------------------------------------------------------------------
##
# This module implements a simple XML-over-HTTP transport layer.
##
from httplib import HTTP, HTTPS
import StringIO, urlparse
import ElementTree as ET
##
# HTTP exception. This exception contains the error code, the error
# message, an HTTP header dictionary, and a file handle, in that
# order. The file handle can be used to read the error response.
class HTTPError(Exception):
pass
##
# HTTP client class.
#
# @param url Target URL.
class HTTPClient:
user_agent = "HTTPClient.py (from effbot.org)"
def __init__(self, url):
scheme, host, path, params, query, fragment = urlparse.urlparse(url)
if scheme != "http" and scheme != "https":
raise ValueError("unsupported scheme (%s)" % scheme)
self.host = host
self.scheme = scheme
if not path:
path = "/"
if params:
path = path + ";" + params
if query:
path = path + "?" + query
self.path = path
##
# Issues an HTTP request.
#
# @param body Request body (a string or an ElementTree object).
# @keyparam path Optional path. If omitted, the path is derived
# from the host URL.
# @keyparam method Optional HTTP method. The default is POST.
# @keyparam content_type Optional Content-Type setting. The
# default is text/xml.
# @keyparam extra_headers List of additional HTTP header fields.
# The list should contain (field, value)-tuples.
# @keyparam parser Optional parser function. If omitted, the
# standard ElementTree parse function is used.
# @return An ElementTree instance containing the HTTP response.
# @defreturn ElementTree
# @throws HTTPError If the server returned an HTTP error code.
# The error code and other details can be obtained from the
# exception object.
def do_request(self, body,
path=None,
method="POST",
content_type="text/xml",
extra_headers=None,
parser=None):
if path is None:
# use default path from constructor
path = self.path
if isinstance(body, ET.ElementTree):
# serialize element tree
file = StringIO.StringIO()
body.write(file)
body = file.getvalue()
# send request
if self.scheme == "https":
h = HTTPS(self.host)
else:
h = HTTP(self.host)
h.putrequest(method, path)
h.putheader("User-Agent", self.user_agent)
h.putheader("Host", self.host)
h.putheader("Content-Type", content_type)
h.putheader("Content-Length", str(len(body)))
if extra_headers:
for key, value in extra_headers:
h.putheader(key, value)
h.endheaders()
h.send(body)
# fetch the reply
errcode, errmsg, headers = h.getreply()
if errcode != 200:
raise HTTPError(errcode, errmsg, headers, h.getfile())
if parser:
return parser(h.getfile())
return ET.parse(h.getfile())