1 from xml.dom import minidom
2 from xml.sax import handler, make_parser, saxutils
3 from osrf.json import to_object
4 from osrf.net_obj import NetworkObject, new_object_from_hint
6 import urllib, urllib2, sys, re
11 def __init__(self, service, method, params=[]):
12 self.service = service
16 self.bytes_read = 0 # for now this, this is really characters read
18 def setPath(self, path):
22 params = self.buildPOSTParams()
23 request = urllib2.Request(self.buildURL(), data=params)
26 response =urllib2.urlopen(request)
27 except urllib2.HTTPError, e:
29 sys.stderr.write('%s => %s?%s\n' % (unicode(e), self.buildURL(), params))
32 return self.handleResponse(response)
34 def buildPOSTParams(self):
36 params = urllib.urlencode({
37 'service': self.service,
38 'method': self.method,
39 'format': self.getFormat(),
40 'input_format': self.getInputFormat()
44 params += '¶m=%s' % urllib.quote(self.encodeParam(p), "'/")
47 def setDefaultHost(host):
50 setDefaultHost = staticmethod(setDefaultHost)
54 Builds the URL for the OpenSRF gateway based on the host and path
56 Previous versions of the code assumed that the host would be a bare
57 hostname or IP address, and prepended the http:// protocol. However,
58 to enable more secure communications, now we check for the existence
59 of the HTTP or HTTPS prefix and use that if it has been supplied.
62 if defaultHost.lower().startswith(('http://', 'https://')):
63 return '%s/%s' % (defaultHost, self.path)
65 return 'http://%s/%s' % (defaultHost, self.path)
67 class JSONGatewayRequest(GatewayRequest):
68 def __init__(self, service, method, *params):
69 GatewayRequest.__init__(self, service, method, list(params))
74 def getInputFormat(self):
75 return self.getFormat()
77 def handleResponse(self, response):
79 data = response.read()
80 self.bytes_read = len(str(response.headers)) + len(data)
83 if obj['status'] != 200:
84 sys.stderr.write('JSON gateway returned status %d:\n' % (obj['status']))
87 # the gateway wraps responses in an array to handle streaming data
88 # if there is only one item in the array, it (probably) wasn't a streaming request
90 if len(p) > 1: return p
91 if len(p): return p[0]
94 def encodeParam(self, param):
95 return osrf.json.to_json(param)
97 class XMLGatewayRequest(GatewayRequest):
99 def __init__(self, service, method, *params):
100 GatewayRequest.__init__(self, service, method, list(params))
105 def getInputFormat(self):
106 return self.getFormat()
108 def handleResponse(self, response):
109 handler = XMLGatewayParser()
110 parser = make_parser()
111 parser.setContentHandler(handler)
113 parser.parse(response)
115 osrf.log.log_error('Error parsing gateway XML: %s' % unicode(e))
118 return handler.getResult()
120 def encodeParam(self, param):
121 return osrf.net_obj.to_xml(param);
123 class XMLGatewayParser(handler.ContentHandler):
129 self.posStack = [] # for tracking array-based hinted object indices
131 # true if we are parsing an element that may have character data
132 self.charsPending = 0
137 def __getAttr(self, attrs, name):
138 for (k, v) in attrs.items():
143 def startElement(self, name, attrs):
145 if self.charsPending:
146 # we just read a 'string' or 'number' element that resulted
147 # in no text data. Appaned a None object
148 self.appendChild(None)
151 self.appendChild(None)
154 if name == 'string' or name == 'number':
155 self.charsPending = True
158 if name == 'element': # this is an object item wrapper
159 self.keyStack.append(self.__getAttr(attrs, 'key'))
162 hint = self.__getAttr(attrs, 'class_hint')
164 obj = new_object_from_hint(hint)
165 self.appendChild(obj)
166 self.objStack.append(obj)
168 self.posStack.append(0)
173 self.appendChild(obj)
174 self.objStack.append(obj)
179 self.appendChild(obj)
180 self.objStack.append(obj)
183 if name == 'boolean':
184 self.appendChild((self.__getAttr(attrs, 'value') == 'true'))
188 def appendChild(self, child):
190 if self.result == None:
193 if not self.objStack: return;
195 parent = self.objStack[len(self.objStack)-1]
197 if isinstance(parent, list):
200 if isinstance(parent, dict):
201 parent[self.keyStack.pop()] = child
203 if isinstance(parent, NetworkObject):
205 if parent.get_registry().protocol == 'array':
206 keys = parent.get_registry().keys
207 i = self.posStack.pop()
210 self.posStack.append(i+1)
212 key = self.keyStack.pop()
214 parent.set_field(key, child)
216 def endElement(self, name):
217 if name == 'array' or name == 'object':
220 def characters(self, chars):
221 self.charsPending = False
222 self.appendChild(urllib.unquote_plus(chars))