Commits

alex.morega  committed b57dde4

JSON input/output tools (#831)

  • Participants
  • Parent commits 52a5671

Comments (0)

Files changed (4)

File cherrypy/_cptools.py

 
 #                              Builtin tools                              #
 
-from cherrypy.lib import cptools, encoding, auth, static, tidy
+from cherrypy.lib import cptools, encoding, auth, static, tidy, jsontools
 from cherrypy.lib import sessions as _sessions, xmlrpc as _xmlrpc
 from cherrypy.lib import caching as _caching, wsgiapp as _wsgiapp
 
 _d.flatten = Tool('before_finalize', cptools.flatten)
 _d.accept = Tool('on_start_resource', cptools.accept)
 _d.redirect = Tool('on_start_resource', cptools.redirect)
+_d.json_in = Tool('before_handler', jsontools.json_in, priority=30)
+_d.json_out = Tool('before_handler', jsontools.json_out, priority=30)
 
 del _d, cptools, encoding, auth, static, tidy

File cherrypy/lib/jsontools.py

+import cherrypy
+
+json_codecs = {}
+
+def json_in(*args, **kwargs):
+    if 'decoder' not in json_codecs:
+        # we don't want to import simplejson until we're sure we need it
+        from simplejson import JSONDecoder
+        json_codecs['decoder'] = JSONDecoder()
+
+    request = cherrypy.request
+    _h = request.headers
+    if ('Content-Type' not in _h
+            or _h.elements('Content-Type')[0].value != 'application/json'):
+        raise cherrypy.HTTPError(415, 'Expected an application/json content type')
+
+    length = int(request.headers['Content-Length'])
+    body = request.body.read(length)
+
+    try:
+        json = json_codecs['decoder'].decode(body)
+    except ValueError:
+        raise cherrypy.HTTPError(400, 'Invalid JSON document')
+
+    request.json = json
+
+def json_out(*args, **kwargs):
+    if 'encoder' not in json_codecs:
+        # we don't want to import simplejson until we're sure we need it
+        from simplejson import JSONEncoder
+        json_codecs['encoder'] = JSONEncoder()
+
+    request = cherrypy.request
+    response = cherrypy.response
+
+    real_handler = request.handler
+    def json_handler(*args, **kwargs):
+        response.headers['Content-Type'] = 'application/json'
+        value = real_handler(*args, **kwargs)
+        return json_codecs['encoder'].iterencode(value)
+    request.handler = json_handler

File cherrypy/test/test.py

         'test_http',
         'test_httpauth',
         'test_httplib',
+        'test_json',
         'test_logging',
         'test_objectmapping',
         'test_dynamicobjectmapping',

File cherrypy/test/test_json.py

+from cherrypy.test import test, helper
+test.prefer_parent_path()
+
+import cherrypy
+
+def setup_server():
+    class Root(object):
+        def plain(self):
+            return 'hello'
+        plain.exposed = True
+
+        def json_string(self):
+            return 'hello'
+        json_string.exposed = True
+        json_string._cp_config = {'tools.json_out.on': True}
+
+        def json_list(self):
+            return ['a', 'b', 42]
+        json_list.exposed = True
+        json_list._cp_config = {'tools.json_out.on': True}
+
+        def json_dict(self):
+            return {'answer': 42}
+        json_dict.exposed = True
+        json_dict._cp_config = {'tools.json_out.on': True}
+
+        def json_post(self):
+            if cherrypy.request.json == [13, 'c']:
+                return 'ok'
+            else:
+                return 'nok'
+        json_post.exposed = True
+        json_post._cp_config = {'tools.json_in.on': True}
+
+    root = Root()
+    cherrypy.tree.mount(root)
+
+class JsonTest(helper.CPWebCase):
+    def test_json_output(self):
+        self.getPage("/plain")
+        self.assertBody("hello")
+
+        self.getPage("/json_string")
+        self.assertBody('"hello"')
+
+        self.getPage("/json_list")
+        self.assertBody('["a", "b", 42]')
+
+        self.getPage("/json_dict")
+        self.assertBody('{"answer": 42}')
+
+    def test_json_input(self):
+        body = '[13, "c"]'
+        headers = [('Content-Type', 'application/json'), ('Content-Length', str(len(body)))]
+        self.getPage("/json_post", method="POST", headers=headers, body=body)
+        self.assertBody('ok')
+
+        self.getPage("/json_post")
+        self.assertStatus(415, 'Expected an application/json content type')
+
+        body = '[13, -]'
+        headers = [('Content-Type', 'application/json'), ('Content-Length', str(len(body)))]
+        self.getPage("/json_post", method="POST", headers=headers, body=body)
+        self.assertStatus(400, 'Invalid JSON document')
+
+if __name__ == '__main__':
+    helper.testmain()
+