fix swob HEAD handling for leak tracking
We added a "safety net" in swob that won't let HEAD responses return a body. It seems like we don't currently have many unittests that both enforce leak tracking and ALSO make HEAD requests. The way swob works currently it's not possible for even a "well behaved client" to get a clean assert with FakeSwift's leak tracking because the leak tracking iterator isn't returned to the client to close and swob doesn't do anything to close down and consume the HEAD response iterator it's throwing away. RelatedChange: I168e147aae7c1728e7e3fdabb7fba6f2d747d937 Change-Id: I079315ebeb772eaad1bf190fefd132b4087b4897
This commit is contained in:
@@ -55,7 +55,7 @@ from six.moves import urllib
|
||||
|
||||
from swift.common.header_key_dict import HeaderKeyDict
|
||||
from swift.common.utils import UTC, reiterate, split_path, Timestamp, pairs, \
|
||||
close_if_possible, closing_if_possible, config_true_value
|
||||
close_if_possible, closing_if_possible, config_true_value, drain_and_close
|
||||
from swift.common.exceptions import InvalidTimestamp
|
||||
|
||||
|
||||
@@ -1400,6 +1400,7 @@ class Response(object):
|
||||
|
||||
if self.request and self.request.method == 'HEAD':
|
||||
# We explicitly do NOT want to set self.content_length to 0 here
|
||||
drain_and_close(app_iter) # be friendly to our app_iter
|
||||
return [b'']
|
||||
|
||||
if self.conditional_response and self.request and \
|
||||
|
@@ -552,6 +552,20 @@ class ObjectVersioningTestCase(ObjectVersioningBaseTestCase):
|
||||
self.assertIn(
|
||||
('X-Symlink-Target', 'c/o?version-id=0000001234.00000'),
|
||||
headers)
|
||||
self.assertEqual(body, b'')
|
||||
# N.B. HEAD req already works with existing registered GET response
|
||||
req = Request.blank(
|
||||
'/v1/a/c/o?symlink=get', method='HEAD',
|
||||
environ={'swift.cache': self.cache_version_on})
|
||||
status, headers, body = self.call_ov(req)
|
||||
self.assertEqual(status, '200 OK')
|
||||
self.assertEqual(len(self.authorized), 1)
|
||||
self.assertRequestEqual(req, self.authorized[0])
|
||||
self.assertIn(('X-Object-Version-Id', '0000001234.00000'), headers)
|
||||
self.assertIn(
|
||||
('X-Symlink-Target', 'c/o?version-id=0000001234.00000'),
|
||||
headers)
|
||||
self.assertEqual(body, b'')
|
||||
|
||||
def test_put_object_no_versioning(self):
|
||||
self.app.register(
|
||||
|
@@ -28,6 +28,8 @@ from six.moves.urllib.parse import quote
|
||||
import swift.common.swob as swob
|
||||
from swift.common import utils, exceptions
|
||||
|
||||
from test.unit.common.middleware.helpers import LeakTrackingIter
|
||||
|
||||
|
||||
class TestHeaderEnvironProxy(unittest.TestCase):
|
||||
def test_proxy(self):
|
||||
@@ -1232,16 +1234,34 @@ class TestResponse(unittest.TestCase):
|
||||
The Response object's __call__ method should be able to reify a
|
||||
Request object from the env it gets passed.
|
||||
"""
|
||||
tracking = {
|
||||
'closed': 0,
|
||||
'read': 0,
|
||||
}
|
||||
|
||||
def mark_closed(*args):
|
||||
tracking['closed'] += 1
|
||||
|
||||
def mark_read(*args):
|
||||
tracking['read'] += 1
|
||||
|
||||
def test_app(environ, start_response):
|
||||
start_response('200 OK', [])
|
||||
return [b'hi']
|
||||
body = [b'hi']
|
||||
return LeakTrackingIter(body, mark_closed, mark_read, None)
|
||||
req = swob.Request.blank('/')
|
||||
req.method = 'HEAD'
|
||||
status, headers, app_iter = req.call_application(test_app)
|
||||
resp = swob.Response(status=status, headers=dict(headers),
|
||||
app_iter=app_iter)
|
||||
output_iter = resp(req.environ, lambda *_: None)
|
||||
self.assertEqual(list(output_iter), [b''])
|
||||
with utils.closing_if_possible(output_iter):
|
||||
body = b''.join(output_iter)
|
||||
self.assertEqual(body, b'')
|
||||
self.assertEqual(tracking, {
|
||||
'closed': 1,
|
||||
'read': 1,
|
||||
})
|
||||
|
||||
def test_call_preserves_closeability(self):
|
||||
def test_app(environ, start_response):
|
||||
|
Reference in New Issue
Block a user