| 1 | # This program is free software; you can redistribute it and/or modify it under |
|---|
| 2 | # the terms of the GNU General Public License as published by the Free Software |
|---|
| 3 | # Foundation; either version 2 of the License, or (at your option) any later |
|---|
| 4 | # version. |
|---|
| 5 | # |
|---|
| 6 | # This program is distributed in the hope that it will be useful, but WITHOUT |
|---|
| 7 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
|---|
| 8 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details |
|---|
| 9 | # |
|---|
| 10 | # You should have received a copy of the GNU General Public License along with |
|---|
| 11 | # this program; if not, write to the Free Software Foundation, Inc., |
|---|
| 12 | # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 13 | """XML-RPC utilities |
|---|
| 14 | |
|---|
| 15 | Copyright (c) 2003-2004 LOGILAB S.A. (Paris, FRANCE). |
|---|
| 16 | http://www.logilab.fr/ -- mailto:contact@logilab.fr |
|---|
| 17 | """ |
|---|
| 18 | |
|---|
| 19 | __revision__ = "$Id: xmlrpcutils.py,v 1.3 2005-11-22 13:13:03 syt Exp $" |
|---|
| 20 | |
|---|
| 21 | import xmlrpclib |
|---|
| 22 | from base64 import encodestring |
|---|
| 23 | #from cStringIO import StringIO |
|---|
| 24 | |
|---|
| 25 | ProtocolError = xmlrpclib.ProtocolError |
|---|
| 26 | |
|---|
| 27 | ## class BasicAuthTransport(xmlrpclib.Transport): |
|---|
| 28 | ## def __init__(self, username=None, password=None): |
|---|
| 29 | ## self.username = username |
|---|
| 30 | ## self.password = password |
|---|
| 31 | ## self.verbose = None |
|---|
| 32 | ## self.has_ssl = httplib.__dict__.has_key("HTTPConnection") |
|---|
| 33 | |
|---|
| 34 | ## def request(self, host, handler, request_body, verbose=None): |
|---|
| 35 | ## # issue XML-RPC request |
|---|
| 36 | ## if self.has_ssl: |
|---|
| 37 | ## if host.startswith("https:"): h = httplib.HTTPSConnection(host) |
|---|
| 38 | ## else: h = httplib.HTTPConnection(host) |
|---|
| 39 | ## else: h = httplib.HTTP(host) |
|---|
| 40 | |
|---|
| 41 | ## h.putrequest("POST", handler) |
|---|
| 42 | |
|---|
| 43 | ## # required by HTTP/1.1 |
|---|
| 44 | ## if not self.has_ssl: # HTTPConnection already does 1.1 |
|---|
| 45 | ## h.putheader("Host", host) |
|---|
| 46 | ## h.putheader("Connection", "close") |
|---|
| 47 | |
|---|
| 48 | ## if request_body: h.send(request_body) |
|---|
| 49 | ## if self.has_ssl: |
|---|
| 50 | ## response = h.getresponse() |
|---|
| 51 | ## if response.status != 200: |
|---|
| 52 | ## raise xmlrpclib.ProtocolError(host + handler, |
|---|
| 53 | ## response.status, |
|---|
| 54 | ## response.reason, |
|---|
| 55 | ## response.msg) |
|---|
| 56 | ## file = response.fp |
|---|
| 57 | ## else: |
|---|
| 58 | ## errcode, errmsg, headers = h.getreply() |
|---|
| 59 | ## if errcode != 200: |
|---|
| 60 | ## raise xmlrpclib.ProtocolError(host + handler, errcode, |
|---|
| 61 | ## errmsg, headers) |
|---|
| 62 | |
|---|
| 63 | ## file = h.getfile() |
|---|
| 64 | |
|---|
| 65 | ## return self.parse_response(file) |
|---|
| 66 | |
|---|
| 67 | |
|---|
| 68 | |
|---|
| 69 | class AuthMixin: |
|---|
| 70 | """basic http authentication mixin for xmlrpc transports""" |
|---|
| 71 | |
|---|
| 72 | def __init__(self, username, password, encoding): |
|---|
| 73 | self.verbose = 0 |
|---|
| 74 | self.username = username |
|---|
| 75 | self.password = password |
|---|
| 76 | self.encoding = encoding |
|---|
| 77 | |
|---|
| 78 | def request(self, host, handler, request_body, verbose=0): |
|---|
| 79 | """issue XML-RPC request""" |
|---|
| 80 | h = self.make_connection(host) |
|---|
| 81 | h.putrequest("POST", handler) |
|---|
| 82 | # required by XML-RPC |
|---|
| 83 | h.putheader("User-Agent", self.user_agent) |
|---|
| 84 | h.putheader("Content-Type", "text/xml") |
|---|
| 85 | h.putheader("Content-Length", str(len(request_body))) |
|---|
| 86 | h.putheader("Host", host) |
|---|
| 87 | h.putheader("Connection", "close") |
|---|
| 88 | # basic auth |
|---|
| 89 | if self.username is not None and self.password is not None: |
|---|
| 90 | h.putheader("AUTHORIZATION", "Basic %s" % encodestring( |
|---|
| 91 | "%s:%s" % (self.username, self.password)).replace("\012", "")) |
|---|
| 92 | h.endheaders() |
|---|
| 93 | # send body |
|---|
| 94 | if request_body: |
|---|
| 95 | h.send(request_body) |
|---|
| 96 | # get and check reply |
|---|
| 97 | errcode, errmsg, headers = h.getreply() |
|---|
| 98 | if errcode != 200: |
|---|
| 99 | raise ProtocolError(host + handler, errcode, errmsg, headers) |
|---|
| 100 | file = h.getfile() |
|---|
| 101 | ## # FIXME: encoding ??? iirc, this fix a bug in xmlrpclib but... |
|---|
| 102 | ## data = h.getfile().read() |
|---|
| 103 | ## if self.encoding != 'UTF-8': |
|---|
| 104 | ## data = data.replace("version='1.0'", |
|---|
| 105 | ## "version='1.0' encoding='%s'" % self.encoding) |
|---|
| 106 | ## result = StringIO() |
|---|
| 107 | ## result.write(data) |
|---|
| 108 | ## result.seek(0) |
|---|
| 109 | ## return self.parse_response(result) |
|---|
| 110 | return self.parse_response(file) |
|---|
| 111 | |
|---|
| 112 | class BasicAuthTransport(AuthMixin, xmlrpclib.Transport): |
|---|
| 113 | """basic http authentication transport""" |
|---|
| 114 | |
|---|
| 115 | class BasicAuthSafeTransport(AuthMixin, xmlrpclib.SafeTransport): |
|---|
| 116 | """basic https authentication transport""" |
|---|
| 117 | |
|---|
| 118 | |
|---|
| 119 | def connect(url, user=None, passwd=None, encoding='ISO-8859-1'): |
|---|
| 120 | """return an xml rpc server on <url>, using user / password if specified |
|---|
| 121 | """ |
|---|
| 122 | if user or passwd: |
|---|
| 123 | assert user and passwd is not None |
|---|
| 124 | if url.startswith('https://'): |
|---|
| 125 | transport = BasicAuthSafeTransport(user, passwd, encoding) |
|---|
| 126 | else: |
|---|
| 127 | transport = BasicAuthTransport(user, passwd, encoding) |
|---|
| 128 | else: |
|---|
| 129 | transport = None |
|---|
| 130 | server = xmlrpclib.ServerProxy(url, transport, encoding=encoding) |
|---|
| 131 | return server |
|---|