~nova-coresec/nova/ppa-lucid

« back to all changes in this revision

Viewing changes to nova/wsgi.py

  • Committer: Soren Hansen
  • Date: 2010-10-14 21:26:14 UTC
  • mfrom: (195.1.85 ubuntu-packaging)
  • Revision ID: soren.hansen@rackspace.com-20101014212614-ioz32fe7oleepk4j
Merge ubuntu packaging branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
Utility methods for working with WSGI servers
22
22
"""
23
23
 
 
24
import json
24
25
import logging
25
26
import sys
 
27
from xml.dom import minidom
26
28
 
27
29
import eventlet
28
30
import eventlet.wsgi
29
31
eventlet.patcher.monkey_patch(all=False, socket=True)
30
32
import routes
31
33
import routes.middleware
 
34
import webob
32
35
import webob.dec
33
36
import webob.exc
34
37
 
227
230
        serializer = Serializer(request.environ, _metadata)
228
231
        return serializer.to_content_type(data)
229
232
 
 
233
    def _deserialize(self, data, request):
 
234
        """
 
235
        Deserialize the request body to the response type requested in request.
 
236
        Uses self._serialization_metadata if it exists, which is a dict mapping
 
237
        MIME types to information needed to serialize to that type.
 
238
        """
 
239
        _metadata = getattr(type(self), "_serialization_metadata", {})
 
240
        serializer = Serializer(request.environ, _metadata)
 
241
        return serializer.deserialize(data)
230
242
 
231
243
class Serializer(object):
232
244
    """
233
 
    Serializes a dictionary to a Content Type specified by a WSGI environment.
 
245
    Serializes and deserializes dictionaries to certain MIME types.
234
246
    """
235
247
 
236
248
    def __init__(self, environ, metadata=None):
239
251
        'metadata' is an optional dict mapping MIME types to information
240
252
        needed to serialize a dictionary to that type.
241
253
        """
242
 
        self.environ = environ
243
254
        self.metadata = metadata or {}
244
 
        self._methods = {
245
 
            'application/json': self._to_json,
246
 
            'application/xml': self._to_xml}
 
255
        req = webob.Request(environ)
 
256
        suffix = req.path_info.split('.')[-1].lower()
 
257
        if suffix == 'json':
 
258
            self.handler = self._to_json
 
259
        elif suffix == 'xml':
 
260
            self.handler = self._to_xml
 
261
        elif 'application/json' in req.accept:
 
262
            self.handler = self._to_json
 
263
        elif 'application/xml' in req.accept:
 
264
            self.handler = self._to_xml
 
265
        else:
 
266
            self.handler = self._to_json # default
247
267
 
248
268
    def to_content_type(self, data):
249
269
        """
250
 
        Serialize a dictionary into a string.  The format of the string
251
 
        will be decided based on the Content Type requested in self.environ:
252
 
        by Accept: header, or by URL suffix.
253
 
        """
254
 
        mimetype = 'application/xml'
255
 
        # TODO(gundlach): determine mimetype from request
256
 
        return self._methods.get(mimetype, repr)(data)
 
270
        Serialize a dictionary into a string.
 
271
        
 
272
        The format of the string will be decided based on the Content Type
 
273
        requested in self.environ: by Accept: header, or by URL suffix.
 
274
        """
 
275
        return self.handler(data)
 
276
 
 
277
    def deserialize(self, datastring):
 
278
        """
 
279
        Deserialize a string to a dictionary.
 
280
        
 
281
        The string must be in the format of a supported MIME type.
 
282
        """
 
283
        datastring = datastring.strip()
 
284
        try:
 
285
            is_xml = (datastring[0] == '<')
 
286
            if not is_xml:
 
287
                return json.loads(datastring)
 
288
            return self._from_xml(datastring)
 
289
        except:
 
290
            return None
 
291
 
 
292
    def _from_xml(self, datastring):
 
293
        xmldata = self.metadata.get('application/xml', {})
 
294
        plurals = set(xmldata.get('plurals', {}))
 
295
        node = minidom.parseString(datastring).childNodes[0]
 
296
        return {node.nodeName: self._from_xml_node(node, plurals)}
 
297
 
 
298
    def _from_xml_node(self, node, listnames):
 
299
        """
 
300
        Convert a minidom node to a simple Python type.
 
301
        
 
302
        listnames is a collection of names of XML nodes whose subnodes should
 
303
        be considered list items.
 
304
        """
 
305
        if len(node.childNodes) == 1 and node.childNodes[0].nodeType == 3:
 
306
            return node.childNodes[0].nodeValue
 
307
        elif node.nodeName in listnames:
 
308
            return [self._from_xml_node(n, listnames) for n in node.childNodes]
 
309
        else:
 
310
            result = dict()
 
311
            for attr in node.attributes.keys():
 
312
                result[attr] = node.attributes[attr].nodeValue
 
313
            for child in node.childNodes:
 
314
                if child.nodeType != node.TEXT_NODE:
 
315
                    result[child.nodeName] = self._from_xml_node(child, listnames)
 
316
            return result
257
317
 
258
318
    def _to_json(self, data):
259
 
        import json
260
319
        return json.dumps(data)
261
320
 
262
321
    def _to_xml(self, data):
263
322
        metadata = self.metadata.get('application/xml', {})
264
323
        # We expect data to contain a single key which is the XML root.
265
324
        root_key = data.keys()[0]
266
 
        from xml.dom import minidom
267
325
        doc = minidom.Document()
268
326
        node = self._to_xml_node(doc, metadata, root_key, data[root_key])
269
327
        return node.toprettyxml(indent='    ')