I'd just like to add that solutions ranging from "create your own product", "use an external method", and "look at allowing things from RestrictedPython" are not solutions. Assume that I (you, whomever) has no access to the Zope backend. The file data needs to somehow be available to a script in Zope, or a way to decode it must be available. Someone on #zope said that binary files weren't handled due to security reasons. I'm curious as to what the implications are by allowing a binary file xmlrpc upload. We are just talking about decoding the file and then creating, say, an Image or File object out of it. Or maybe we'll process it it, but I don't see the problem there either. Assuming that Python itself has no holes in it, and assuming that the decode of the file, and also the mechanisms by which Zope stores the new Image/File object are fine, I don't see the problem. (Sorry for the run-on.) Please enlighten me. -Chris On Mon, 9 Sep 2002 14:32:45 -0500, Kyler Laird spoke forth:
[I'm copying this to the Zope list so that someone there will be sure to correct any gross mistakes I make.]
Transfering binary data through XML-RPC does not seem to be the problem that you described. xmlrpclib handles it fine. Zope receives it fine. It's just unusable once it gets to Zope.
As a test, I created a script that made a Binary object from a simple image foo = xmlrpclib.Binary(img.read()) and then called a test script on my Zope server. result = Zopesvr.test.xmlrpc(foo) This worked o.k. When I printed the string rendition of what the script received, I got <xmlrpclib.Binary instance at 0x98420b4>
Looks good, no? This is much better than we'd thought; there is no need to manually base64 encode it on the client.
However...it turns out that the Binary class in Zope's xmlrpclib product is quite a kludge. # # binary data wrapper (NOTE: this is an extension to Userland's# XML-RPC protocol! only for use with compatible servers!)
class Binary:
def __init__(self, data=None): self.data = data
def decode(self, data): import base64 self.data = base64.decodestring(data)
def encode(self, out): import base64, StringIO out.write("<value><base64>\n") base64.encode(StringIO.StringIO(self.data), out) out.write("</base64></value>\n")
The first thing to notice is that we don't know what type of data is in a Binary object. You just initialize it with some data and then you either encode() or decode() it. If it was initialized with encoded data and you encode() it or it was initialized with decoded data and you decode() it, you'll probably not get what you expected.
The more important deficiency in this class is that even if you do figure out what kind of data is in there, there's no way for you (as a normal user) to get at it. Both decode() and encode() want to stuff their results in a file object. I do not know of any way you can get one in Zope. It does not matter though - you are not allowed to access them anyway.
So...you're screwed. You can't touch the data. (No, you can't just use a Binary object with manage_addFile.)
The quick and dirty solution is to add import AccessControl AccessControl.allow_class(Binary) to xmlrpclib.py. Then you can get straight at the "data" of the Binary object. (I just did this and passed it to manage_addImage(). It worked fine. The data was already decoded.)
Ideally, you'd add some sane public methods to the Binary class. Perhaps "encoded()" and "decoded()" would be a place to start. They could return either strings or StringIO objects.
Sorry I don't have a better solution, but it looks like you're probably going to have to patch Zope if you don't want to give up on XML-RPC and just use HTTP POST. I appreciate and share your desire to use XML-RPC with Zope, but until we get Binary straightened out in Zope and basic authentication added in Python, it just takes too many kludges to recommend.
--kyler
-- -------------------------------------------------------------------- Christopher N. Deckard | Lead Web Systems Developer cnd@ecn.purdue.edu | Engineering Computer Network http://eng.purdue.edu/ECN/ | Purdue University ---- zlib.decompress('x\234K\316Kq((-J)M\325KM)\005\000)"\005w') ---