New

Xmlrpclib with cookie aware transport

Using Python made me fall in love with XmlRPC. The python xmlrpclib is great and I'm using this protocol with C# and PHP too.

The problem
Any call to an xmlrpc server is stateless, so that you are forced to send state information back and forth through additional parameters.

The solution
So that i dediced to write a transport object that keeps track of the session id cookies sent by the server.

Here's the code:

import xmlrpclib
class CookieTransport(xmlrpclib.Transport):
	def __init__(self, SESSION_ID_STRING='PHPSESSID'):
		xmlrpclib.Transport.__init__(self)
		self.mycookies=None
		self.mysessid=None
		self.SESSION_ID_STRING = SESSION_ID_STRING
	def parseCookies(self,s):
		if s is None: return {self.SESSION_ID_STRING:None}
		ret = {}
		tmp = s.split(';')
		for t in tmp:
			coppia = t.split('=')
			k = coppia[0].strip()
			v = coppia[1].strip()
			ret[k]=v
		return ret
	def request(self, host, handler, request_body, verbose=0):
		# issue XML-RPC request
		h = self.make_connection(host)
		if verbose:
			h.set_debuglevel(1)
		self.send_request(h, handler, request_body)
		self.send_host(h, host)
		if not self.mysessid is None:
			h.putheader("Cookie", "%s=%s" % (self.SESSION_ID_STRING,self.mysessid) )
		self.send_user_agent(h)
		self.send_content(h, request_body)
		errcode, errmsg, headers = h.getreply()
		if self.mysessid is None:
			self.mycookies = self.parseCookies( headers.getheader('set-cookie') )
			if self.mycookies.has_key(self.SESSION_ID_STRING):
				self.mysessid = self.mycookies[self.SESSION_ID_STRING]
		if errcode != 200:
			raise xmlrpclib.ProtocolError(
				host + handler,
				errcode, errmsg,
				headers
				)
		self.verbose = verbose
		try:
			sock = h._conn.sock
		except AttributeError:
			sock = None
		return self._parse_response(h.getfile(), sock)

As you may have noticed you can specify the name of the session cookie by passing the SESSION_ID_STRING parameter to the constructor.

Now you can create your client in the usual way:

self.server = xmlrpclib.Server(host, transport=CookieTransport())

Any call will send back and forth the session cookie so that you can keep session objects on the server, i.e. username, result list, etc.

If you have any question, please comment this post.

Enjoy,
Rob.