quick search:
 

XMLRPC File into ZOPE

Submitted by: runyaga
Last Edited: 2005-02-12

Category: Python(External Method)

Average rating is: 5.0 out of 5 (1 ratings)

Description:
Demonstrates how automagically ZOPE does XMLRPC. Unlike most systems where XMLRPC is a special call. All ZOPE methods are xmlrpc aware. Its quite magical. Here are 3 easy steps to getting a binary file to be XMLRPC'ed from a client to ZOPE Server and storing the result on the filesystem. (look at previous recipes to find out how to create a file object in the ZODB)

1. the xmlrpc Client which determines what file wants to be uploaded

2. the file xmlrpc.py in $ZOPE/Extensions, which takes the file and puts it on the localfilesystem (you could easily change this to store it in the Object Database)

3. the 'external method' proxy in the ZODB ;)

*thanks to kapil who showed me the obvious, base64 encode it (I was trying to work
with the binary type)


Source (Text):
""" The XMLRPC client """
import string, xmlrpclib, httplib
from base64 import encodestring

class BasicAuthTransport(xmlrpclib.Transport):
    """ taken from http://www.zope.org/Members/Amos/XML-RPC """
    def __init__(self, username=None, password=None, verbose=0):
        self.username=username
        self.password=password
        self.verbose=verbose

    def request(self, host, handler, request_body, verbose=0):
        h = httplib.HTTP(host)
        h.putrequest("POST", handler)
        h.putheader("Host", host)
        h.putheader("User-Agent", self.user_agent)
        h.putheader("Content-Type", "text/xml")
        h.putheader("Content-Length", str(len(request_body)))

        # basic auth
        if self.username is not None and self.password is not None:
            h.putheader("AUTHORIZATION", "Basic %s" % string.replace(
                    encodestring("%s:%s" % (self.username, self.password)),
                    "\012", ""))
        h.endheaders()

        if request_body:
            h.send(request_body)

        errcode, errmsg, headers = h.getreply()

        if errcode != 200:
            raise xmlrpclib.ProtocolError(
                host + handler,
                errcode, errmsg,
                headers
                )

        return self.parse_response(h.getfile())

if __name__=='__main__':
    d=xmlrpclib.Server('http://pynchon.runyaga.com:8080/',
                       BasicAuthTransport('runyaga','%&#password($@') )
    from StringIO import StringIO
    str_obj = None
    try:
        f = open('c:\\tmp\\dreamweaver.exe', 'rb')
        str_obj = encodestring( f.read() )
        f.close()
        del f
        #in my example the 'putFileOnfilesystem' External Method was in the root of the ZODB
        #if yours in a a folder called test you would call d.test.putFileOnFilesytem(...
        d.putFileOnFilesystem('dreamweaver.exe', str_obj)
    finally:
        del str_obj
    del d

""" on the server create a file in $ZOPE/Extensions called xmlrpc.py """
from base64 import decodestring
from StringIO import StringIO

def put_fileOnFilesystem(file_id, file_obj):
    """ puts the file on the file system """
    file = StringIO()
    data = decodestring(file_obj)
    fd = open('/tmp/'+file_id, 'wb')

    file.write(data)
    file.seek(0)
    fd.write( file.read() )
    fd.close()

    del file
    del data

""" in the ZODB create a External Method: """
ID = putFileOnFilesystem
module = xmlrpc (name of the $ZOPE/Extnesions file w/o the .py)
function = put_fileOnFilesystem

Explanation:
The main thing to notice is XMLRPC doesnt have a file type. so its kinda lame
but you end up having to base64 encode a file object (does *not* work for really large
files) and then pass it into the parameter as if it were a string.

This is certainly less than desirable (client has to know how to marshall the file object
in XMLRPC land) but it works!


Comments:

No Comments