feat(Request): Also accept query params from POSTed forms
This patch adds support for merging the body of an 'application/x-www-form-urlencoded' request into the params collection so they can be queried via get_param & Co. Credit goes to sorenh for the originaly idea and POC. Thanks Soren! Partially implements issue #180
This commit is contained in:
@@ -123,13 +123,14 @@ class Request(object):
|
||||
'_cached_headers',
|
||||
'_cached_uri',
|
||||
'_cached_relative_uri',
|
||||
'content_type',
|
||||
'env',
|
||||
'method',
|
||||
'_params',
|
||||
'path',
|
||||
'query_string',
|
||||
'stream',
|
||||
'_wsgierrors'
|
||||
'_wsgierrors',
|
||||
)
|
||||
|
||||
def __init__(self, env):
|
||||
@@ -179,6 +180,8 @@ class Request(object):
|
||||
self._cached_uri = None
|
||||
self._cached_relative_uri = None
|
||||
|
||||
self.content_type = self._get_header_by_wsgi_name('HTTP_CONTENT_TYPE')
|
||||
|
||||
# NOTE(kgriffs): Wrap wsgi.input if needed to make read() more robust,
|
||||
# normalizing semantics between, e.g., gunicorn and wsgiref.
|
||||
if isinstance(self.stream, NativeStream): # pragma: nocover
|
||||
@@ -186,6 +189,26 @@ class Request(object):
|
||||
# covered since the test that does so uses multiprocessing.
|
||||
self.stream = helpers.Body(self.stream, self.content_length)
|
||||
|
||||
# PERF(kgriffs): Technically, we should spend a few more
|
||||
# cycles and parse the content type for real, but
|
||||
# this heuristic will work virtually all the time.
|
||||
if (self.content_type and
|
||||
'application/x-www-form-urlencoded' in self.content_type):
|
||||
|
||||
# NOTE(kgriffs): This assumes self.stream has been patched
|
||||
# above in the case of wsgiref, so that self.content_length
|
||||
# is not needed. Normally we just avoid accessing
|
||||
# self.content_length, because it is a little expensive
|
||||
# to call. We could cache self.content_length, but the
|
||||
# overhead to do that won't usually be helpful, since
|
||||
# content length will only ever be read once per
|
||||
# request in most cases.
|
||||
body = self.stream.read()
|
||||
body = body.decode('ascii')
|
||||
|
||||
extra_params = uri.parse_query_string(uri.decode(body))
|
||||
self._params.update(extra_params)
|
||||
|
||||
# ------------------------------------------------------------------------
|
||||
# Properties
|
||||
# ------------------------------------------------------------------------
|
||||
@@ -233,10 +256,6 @@ class Request(object):
|
||||
|
||||
return None
|
||||
|
||||
@property
|
||||
def content_type(self):
|
||||
return self._get_header_by_wsgi_name('HTTP_CONTENT_TYPE')
|
||||
|
||||
@property
|
||||
def date(self):
|
||||
http_date = self._get_header_by_wsgi_name('HTTP_DATE')
|
||||
|
||||
@@ -2,7 +2,7 @@ import falcon
|
||||
import falcon.testing as testing
|
||||
|
||||
|
||||
class TestQueryParams(testing.TestBase):
|
||||
class _TestQueryParams(testing.TestBase):
|
||||
|
||||
def before(self):
|
||||
self.resource = testing.TestResource()
|
||||
@@ -242,3 +242,16 @@ class TestQueryParams(testing.TestBase):
|
||||
|
||||
self.assertRaises(falcon.HTTPBadRequest,
|
||||
req.get_param_as_list, 'coord', transform=int)
|
||||
|
||||
|
||||
class PostQueryParams(_TestQueryParams):
|
||||
def simulate_request(self, path, query_string):
|
||||
headers = {"Content-Type": "application/x-www-form-urlencoded"}
|
||||
super(PostQueryParams, self).simulate_request(path, body=query_string,
|
||||
headers=headers)
|
||||
|
||||
|
||||
class GetQueryParams(_TestQueryParams):
|
||||
def simulate_request(self, path, query_string):
|
||||
super(GetQueryParams, self).simulate_request(
|
||||
path, query_string=query_string)
|
||||
|
||||
Reference in New Issue
Block a user