]> review.fuel-infra Code Review - openstack-build/heat-build.git/commitdiff
Impose a size limit on JSON request body
authorLiang Chen <cbjchen@cn.ibm.com>
Sat, 31 Aug 2013 06:53:43 +0000 (14:53 +0800)
committerLiang Chen <cbjchen@cn.ibm.com>
Wed, 11 Sep 2013 02:51:47 +0000 (10:51 +0800)
The size limit on JSON request body is to ensure the server not being
overwhelmed by extremly large JSON request body.

Fixes bug #1215501

Change-Id: Ia58f6690e994d34212953c44821f7a4cc4c435fe

etc/heat/heat.conf.sample
heat/common/exception.py
heat/common/wsgi.py
heat/tests/test_wsgi.py

index d8f238fd9b92a4b88900bf16069bc4d6a19abbe0..50867b806c9956647b3cacda7158e81a422ff4f0 100644 (file)
 #auth_encryption_key=notgood but just long enough i think
 
 
+#
+# Options defined in heat.common.wsgi
+#
+
+# Maximum raw byte size of JSON request body. Should be larger
+# than max_template_size. (integer value)
+#max_json_body_size=1048576
+
+
 #
 # Options defined in heat.db.api
 #
index fcaff0a995778943fd574fc93fe67308037d367c..bc175e8096478021b4bef60c40e9081ffdc838b9 100644 (file)
@@ -330,3 +330,7 @@ class StackRecursionLimitReached(HeatException):
     def __init__(self, recursion_depth):
         self.message = self.message % recursion_depth
         super(StackRecursionLimitReached, self).__init__()
+
+
+class RequestLimitExceeded(HeatException):
+    message = _('Request limit exceeded: %(message)s')
index f50c521d83aec310d77cd442bb7b0c856fba3821..08386ed6235cbd658f984efd8b6acb9fc4eb4ccf 100644 (file)
@@ -137,6 +137,12 @@ cfg.CONF.register_group(api_cw_group)
 cfg.CONF.register_opts(api_cw_opts,
                        group=api_cw_group)
 
+json_size_opt = cfg.IntOpt('max_json_body_size',
+                           default=1048576,
+                           help='Maximum raw byte size of JSON request body.'
+                                ' Should be larger than max_template_size.')
+cfg.CONF.register_opt(json_size_opt)
+
 
 class WritableLogger(object):
     """A thin wrapper that responds to `write` and logs."""
@@ -524,6 +530,12 @@ class JSONRequestDeserializer(object):
 
     def from_json(self, datastring):
         try:
+            if len(datastring) > cfg.CONF.max_json_body_size:
+                msg = _('JSON body size (%(len)s bytes) exceeds maximum '
+                        'allowed size (%(limit)s bytes).') % \
+                    {'len': len(datastring),
+                     'limit': cfg.CONF.max_json_body_size}
+                raise exception.RequestLimitExceeded(message=msg)
             return json.loads(datastring)
         except ValueError as ex:
             raise webob.exc.HTTPBadRequest(str(ex))
@@ -638,11 +650,10 @@ class Resource(object):
         # ContentType=JSON results in a JSON serialized response...
         content_type = request.params.get("ContentType")
 
-        deserialized_request = self.dispatch(self.deserializer,
-                                             action, request)
-        action_args.update(deserialized_request)
-
         try:
+            deserialized_request = self.dispatch(self.deserializer,
+                                                 action, request)
+            action_args.update(deserialized_request)
             action_result = self.dispatch(self.controller, action,
                                           request, **action_args)
         except TypeError as err:
index 01d947725e8b23121730189399b800d4e863ac4f..52783d98264543e680705b8c0f9d33d2747f9366 100644 (file)
@@ -17,6 +17,8 @@
 
 
 import datetime
+import json
+from oslo.config import cfg
 import stubout
 import webob
 
@@ -380,3 +382,15 @@ class JSONRequestDeserializerTest(HeatTestCase):
         actual = wsgi.JSONRequestDeserializer().default(request)
         expected = {"body": {"key": "value"}}
         self.assertEqual(actual, expected)
+
+    def test_from_json_exceeds_max_json_mb(self):
+        cfg.CONF.set_override('max_json_body_size', 10)
+        body = json.dumps(['a'] * cfg.CONF.max_json_body_size)
+        self.assertTrue(len(body) > cfg.CONF.max_json_body_size)
+        error = self.assertRaises(exception.RequestLimitExceeded,
+                                  wsgi.JSONRequestDeserializer().from_json,
+                                  body)
+        msg = 'Request limit exceeded: JSON body size ' + \
+              '(%s bytes) exceeds maximum allowed size (%s bytes).' % \
+              (len(body), cfg.CONF.max_json_body_size)
+        self.assertEqual(msg, str(error))