fix: keep body and make encoding process explicit

This commit is contained in:
Flaper Fesp
2013-07-26 11:44:04 +02:00
parent c3143d4f4b
commit 115d316acd
5 changed files with 47 additions and 27 deletions

View File

@@ -123,12 +123,8 @@ class API(object):
#
use_body = not helpers.should_ignore_body(resp.status, req.method)
if use_body:
# get_body must be called before
# set_content_length so that all
# encodings and transformations
# on the body can be applied first.
body = helpers.get_body(resp)
helpers.set_content_length(resp)
body = helpers.get_body(resp)
else:
# Default: return an empty body
body = []

View File

@@ -19,8 +19,6 @@ limitations under the License.
import re
from functools import wraps
import six
from falcon import responders, HTTP_METHODS
import falcon.status_codes as status
@@ -77,10 +75,10 @@ def set_content_length(resp):
content_length = 0
if resp.body is not None:
if resp.body_encoded is not None:
# Since body is assumed to be a byte string (str in Python 2, bytes in
# Python 3), figure out the length using standard functions.
content_length = len(resp.body)
content_length = len(resp.body_encoded)
elif resp.data is not None:
content_length = len(resp.data)
elif resp.stream is not None:
@@ -99,9 +97,6 @@ def set_content_length(resp):
def get_body(resp):
"""Converts resp content into an iterable as required by PEP 333
Post:
If resp.body is set, it'll be encoded.
Args:
resp: Instance of falcon.Response
@@ -114,14 +109,10 @@ def get_body(resp):
"""
body = resp.body
body = resp.body_encoded
if body is not None:
if isinstance(body, six.text_type):
resp.body = body.encode('utf-8')
return [resp.body]
else:
return [body]
return [body]
elif resp.data is not None:
return [resp.data]

View File

@@ -16,6 +16,8 @@ limitations under the License.
"""
import six
from falcon.response_helpers import header_property, format_range
from falcon.util import dt_to_http, percent_escape
@@ -36,7 +38,8 @@ class Response(object):
"""
__slots__ = (
'body', # Stuff
'_body', # Stuff
'_body_encoded', # Stuff
'data',
'_headers',
'status',
@@ -55,11 +58,41 @@ class Response(object):
self.status = '200 OK'
self._headers = {}
self.body = None
self._body = None
self._body_encoded = None
self.data = None
self.stream = None
self.stream_len = None
def _get_body(self):
return self._body
def _set_body(self, value):
self._body = value
self._body_encoded = None
# NOTE(flaper87): Lets use a property
# for the body in case its content was
# encoded and then modified.
body = property(_get_body, _set_body)
@property
def body_encoded(self):
# NOTE(flaper87): Notice this property
# is not thread-safe. If body is modified
# before this property returns, we might
# end up returning None.
body = self._body
if body and not self._body_encoded:
# NOTE(flaper87): Assume it is an
# encoded str, then check and encode
# if it isn't.
self._body_encoded = body
if isinstance(body, six.text_type):
self._body_encoded = body.encode('utf-8')
return self._body_encoded
def set_header(self, name, value):
"""Set a header for this response to a given value.

View File

@@ -85,7 +85,7 @@ class TestHooks(testing.TestBase):
self.api.add_route(self.test_route, zoo_resource)
self.simulate_request(self.test_route)
self.assertEqual(b'fluffy', zoo_resource.resp.body)
self.assertEqual(b'fluffy', zoo_resource.resp.body_encoded)
def test_multiple_global_hook(self):
self.api = falcon.API(after=[fluffiness, cuteness])
@@ -94,17 +94,17 @@ class TestHooks(testing.TestBase):
self.api.add_route(self.test_route, zoo_resource)
self.simulate_request(self.test_route)
self.assertEqual(b'fluffy and cute', zoo_resource.resp.body)
self.assertEqual(b'fluffy and cute', zoo_resource.resp.body_encoded)
def test_output_validator(self):
self.simulate_request(self.test_route)
self.assertEqual(falcon.HTTP_723, self.srmock.status)
self.assertEqual(None, self.resource.resp.body)
self.assertEqual(None, self.resource.resp.body_encoded)
def test_serializer(self):
self.simulate_request(self.test_route, method='PUT')
actual_body = self.resource.resp.body
actual_body = self.resource.resp.body_encoded
self.assertEqual(b'{"animal": "falcon"}', actual_body)
def test_wrapped_resource(self):
@@ -112,7 +112,7 @@ class TestHooks(testing.TestBase):
self.simulate_request('/wrapped')
self.assertEqual(falcon.HTTP_200, self.srmock.status)
self.assertEqual(expected, self.wrapped_resource.resp.body)
self.assertEqual(expected, self.wrapped_resource.resp.body_encoded)
self.simulate_request('/wrapped', method='HEAD')
self.assertEqual(falcon.HTTP_200, self.srmock.status)

View File

@@ -101,7 +101,7 @@ class TestHelloWorld(testing.TestBase):
self.assertEquals(self.srmock.status, self.resource.sample_status)
self.assertEquals(resp.status, self.resource.sample_status)
self.assertEquals(resp.body, self.resource.sample_utf8)
self.assertEquals(resp.body_encoded, self.resource.sample_utf8)
self.assertEquals(body, [self.resource.sample_utf8])
def test_body_bytes(self):
@@ -113,7 +113,7 @@ class TestHelloWorld(testing.TestBase):
self.assertEquals(self.srmock.status, self.resource.sample_status)
self.assertEquals(resp.status, self.resource.sample_status)
self.assertEquals(resp.body, self.resource.sample_utf8)
self.assertEquals(resp.body_encoded, self.resource.sample_utf8)
self.assertEquals(body, [self.resource.sample_utf8])
def test_data(self):