Fix incompatibilities with WebOb 1.7
WebOb 1.7 changed [0] how request bodies are determined to be readable. Prior to version 1.7, the following is how WebOb determined if a request body is readable: #1 Request method is one of POST, PUT or PATCH #2 ``content_length`` length is set #3 Special flag ``webob.is_body_readable`` is set The special flag ``webob.is_body_readable`` was used to signal WebOb to consider a request body readable despite the content length not being set. #1 above is how ``chunked`` Transfer Encoding was supported implicitly in WebOb < 1.7. Now with WebOb 1.7, a request body is considered readable only if ``content_length`` is set and it's non-zero [1]. So, we are only left with #2 and #3 now. This drops implicit support for ``chunked`` Transfer Encoding Glance relied on. Hence, to emulate #1, Glance must set the the special flag upon checking the HTTP methods that may have bodies. This is precisely what this patch attemps to do. [0] https://github.com/Pylons/webob/pull/283 [1] https://github.com/Pylons/webob/pull/283/files#diff-706d71e82f473a3b61d95c2c0d833b60R894 Closes-bug: #1657459 Closes-bug: #1657452 Co-Authored-By: Hemanth Makkapati <hemanth.makkapati@rackspace.com> Change-Id: I19f15165a3d664d5f3a361f29ad7000ba2465a85
This commit is contained in:
parent
9de043acb0
commit
7a843f7e1f
glance
@ -48,7 +48,7 @@ class GzipMiddleware(wsgi.Middleware):
|
||||
# that they can be compressed without reading
|
||||
# the whole content in memory. Notice that using
|
||||
# lazy will set response's content-length to 0.
|
||||
content_type = response.headers["Content-Type"]
|
||||
content_type = response.headers.get("Content-Type", "")
|
||||
lazy = content_type == "application/octet-stream"
|
||||
|
||||
# NOTE(flaper87): Webob takes care of the compression
|
||||
|
@ -275,6 +275,9 @@ class RequestDeserializer(wsgi.JSONRequestDeserializer):
|
||||
except exception.InvalidContentType as e:
|
||||
raise webob.exc.HTTPUnsupportedMediaType(explanation=e.msg)
|
||||
|
||||
if self.is_valid_encoding(request) and self.is_valid_method(request):
|
||||
request.is_body_readable = True
|
||||
|
||||
image_size = request.content_length or None
|
||||
return {'size': image_size, 'data': request.body_file}
|
||||
|
||||
|
@ -982,6 +982,16 @@ class Request(webob.Request):
|
||||
class JSONRequestDeserializer(object):
|
||||
valid_transfer_encoding = frozenset(['chunked', 'compress', 'deflate',
|
||||
'gzip', 'identity'])
|
||||
httpverb_may_have_body = frozenset({'POST', 'PUT', 'PATCH'})
|
||||
|
||||
@classmethod
|
||||
def is_valid_encoding(cls, request):
|
||||
request_encoding = request.headers.get('transfer-encoding', '').lower()
|
||||
return request_encoding in cls.valid_transfer_encoding
|
||||
|
||||
@classmethod
|
||||
def is_valid_method(cls, request):
|
||||
return request.method.upper() in cls.httpverb_may_have_body
|
||||
|
||||
def has_body(self, request):
|
||||
"""
|
||||
@ -989,11 +999,12 @@ class JSONRequestDeserializer(object):
|
||||
|
||||
:param request: Webob.Request object
|
||||
"""
|
||||
request_encoding = request.headers.get('transfer-encoding', '').lower()
|
||||
is_valid_encoding = request_encoding in self.valid_transfer_encoding
|
||||
if is_valid_encoding and request.is_body_readable:
|
||||
|
||||
if self.is_valid_encoding(request) and self.is_valid_method(request):
|
||||
request.is_body_readable = True
|
||||
return True
|
||||
elif request.content_length is not None and request.content_length > 0:
|
||||
|
||||
if request.content_length is not None and request.content_length > 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
@ -506,19 +506,32 @@ class JSONRequestDeserializerTest(test_utils.BaseTestCase):
|
||||
self.assertFalse(self._check_transfer_encoding(
|
||||
transfer_encoding='invalid', content_length=0))
|
||||
|
||||
def test_has_body_invalid_transfer_encoding_no_content_len_and_body(self):
|
||||
self.assertFalse(self._check_transfer_encoding(
|
||||
transfer_encoding='invalid', include_body=False))
|
||||
|
||||
def test_has_body_invalid_transfer_encoding_no_content_len_but_body(self):
|
||||
self.assertTrue(self._check_transfer_encoding(
|
||||
transfer_encoding='invalid', include_body=True))
|
||||
|
||||
def test_has_body_invalid_transfer_encoding_with_content_length(self):
|
||||
self.assertTrue(self._check_transfer_encoding(
|
||||
transfer_encoding='invalid', content_length=5))
|
||||
|
||||
def test_has_body_valid_transfer_encoding_with_content_length(self):
|
||||
self.assertTrue(self._check_transfer_encoding(
|
||||
transfer_encoding='chunked', content_length=0))
|
||||
transfer_encoding='chunked', content_length=1))
|
||||
|
||||
def test_has_body_valid_transfer_encoding_without_content_length(self):
|
||||
self.assertTrue(self._check_transfer_encoding(
|
||||
transfer_encoding='chunked'))
|
||||
|
||||
def _check_transfer_encoding(self, transfer_encoding=None,
|
||||
content_length=None):
|
||||
content_length=None, include_body=True):
|
||||
request = wsgi.Request.blank('/')
|
||||
request.method = 'POST'
|
||||
request.body = b'fake_body'
|
||||
if include_body:
|
||||
request.body = b'fake_body'
|
||||
request.headers['transfer-encoding'] = transfer_encoding
|
||||
if content_length is not None:
|
||||
request.headers['content-length'] = content_length
|
||||
|
Loading…
x
Reference in New Issue
Block a user