summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRyan Petrello <lists@ryanpetrello.com>2015-01-07 17:34:21 -0500
committerRyan Petrello <lists@ryanpetrello.com>2015-01-08 14:58:21 -0500
commitf491076a0f1b9f080c139a8062c9481e8024d8cb (patch)
tree408427508ad981aa61803d060bc503677d0f78d0
parentfe19eb67a83c4ec1e239586b2d7a6141a5d56418 (diff)
downloadpecan-f491076a0f1b9f080c139a8062c9481e8024d8cb.tar.gz
Change pecan to more gracefully handle a few odd request encoding edge cases.
Webob raises UnicodeDecodeErrors during request argument parsing in two situations: * HTTP POST requests composed of non-Unicode data (only affects Webob in Python2) * URL paths that contain invalid percent-encoded characters, e.g., /some/path/%AA Pecan should detect these types of decoding failures when `webob.Request` attributes are accessed, log the original exception, and coerce the HTTP 500 into a more accurate HTTP 400. Fixes bug: 1408102 Fixes bug: 1407749 Change-Id: I734efd36230b6742805bcfd801dc0de2489ef92b
-rw-r--r--pecan/core.py8
-rw-r--r--pecan/tests/test_base.py17
-rw-r--r--pecan/tests/test_rest.py26
3 files changed, 48 insertions, 3 deletions
diff --git a/pecan/core.py b/pecan/core.py
index 173210b..e74a8b1 100644
--- a/pecan/core.py
+++ b/pecan/core.py
@@ -48,7 +48,13 @@ class RoutingState(object):
class Request(WebObRequest):
- pass
+
+ def __getattribute__(self, name):
+ try:
+ return WebObRequest.__getattribute__(self, name)
+ except UnicodeDecodeError as e:
+ logger.exception(e)
+ abort(400)
class Response(WebObResponse):
diff --git a/pecan/tests/test_base.py b/pecan/tests/test_base.py
index cca494c..1369837 100644
--- a/pecan/tests/test_base.py
+++ b/pecan/tests/test_base.py
@@ -146,6 +146,23 @@ class TestAppIterFile(PecanTestCase):
assert len(r.body) == 0
+class TestInvalidURLEncoding(PecanTestCase):
+
+ @property
+ def app_(self):
+ class RootController(object):
+
+ @expose()
+ def _route(self, args, request):
+ assert request.path
+
+ return TestApp(Pecan(RootController()))
+
+ def test_rest_with_non_utf_8_body(self):
+ r = self.app_.get('/%aa/', expect_errors=True)
+ assert r.status_int == 400
+
+
class TestIndexRouting(PecanTestCase):
@property
diff --git a/pecan/tests/test_rest.py b/pecan/tests/test_rest.py
index d839084..391b7d0 100644
--- a/pecan/tests/test_rest.py
+++ b/pecan/tests/test_rest.py
@@ -1,11 +1,12 @@
-from webtest import TestApp
+import struct
import warnings
try:
from simplejson import dumps, loads
except:
from json import dumps, loads # noqa
-from six import b as b_
+from six import b as b_, PY3
+from webtest import TestApp
from pecan import abort, expose, make_app, response, redirect
from pecan.rest import RestController
@@ -1359,6 +1360,27 @@ class TestRestController(PecanTestCase):
assert r.status_int == 200
assert r.body == b_("DEFAULT missing")
+ def test_rest_with_non_utf_8_body(self):
+ if PY3:
+ # webob+PY3 doesn't suffer from this bug; the POST parsing in PY3
+ # seems to more gracefully detect the bytestring
+ return
+
+ class FooController(RestController):
+
+ @expose()
+ def post(self):
+ return "POST"
+
+ class RootController(RestController):
+ foo = FooController()
+
+ app = TestApp(make_app(RootController()))
+
+ data = struct.pack('255h', *range(0, 255))
+ r = app.post('/foo/', data, expect_errors=True)
+ assert r.status_int == 400
+
def test_dynamic_rest_lookup(self):
class BarController(RestController):
@expose()