Convert limiting_iter to LimitingReader.
Glance commit 3c69df5aa7
added a new
limiting_iter function in utils which we use to limit reads to
image data being uploaded. This simple generator doesn't work
with image backends like the Swift store which require a 'read'
method.
This patch swaps out the simple limiting_iter function for a
LimitingReader class which supports both 'read' and __iter__
functions.
Fixes LP Bug #1039212 which cause the exception below when used
with the previous code:
AttributeError: 'CooperativeReader' object has no attribute 'read'
Change-Id: I87d9a30f7afe0207386d621050312374ced161d5
This commit is contained in:
parent
3c69df5aa7
commit
a6de4de65b
@ -834,7 +834,7 @@ class ImageDeserializer(wsgi.JSONRequestDeserializer):
|
||||
data = request.body_file if self.has_body(request) else None
|
||||
|
||||
if image_size is None and data is not None:
|
||||
data = utils.limiting_iter(data, CONF.image_size_cap)
|
||||
data = utils.LimitingReader(data, CONF.image_size_cap)
|
||||
|
||||
#NOTE(bcwaldon): this is a hack to make sure the downstream code
|
||||
# gets the correct image data
|
||||
|
@ -125,18 +125,34 @@ class CooperativeReader(object):
|
||||
return cooperative_iter(self.fd.__iter__())
|
||||
|
||||
|
||||
def limiting_iter(iter, limit):
|
||||
class LimitingReader(object):
|
||||
"""
|
||||
Iterator designed to fail when reading image data past the configured
|
||||
Reader designed to fail when reading image data past the configured
|
||||
allowable amount.
|
||||
"""
|
||||
bytes_read = 0
|
||||
for chunk in iter:
|
||||
bytes_read += len(chunk)
|
||||
if bytes_read > limit:
|
||||
def __init__(self, data, limit):
|
||||
"""
|
||||
:param data: Underlying image data object
|
||||
:param limit: maximum number of bytes the reader should allow
|
||||
"""
|
||||
self.data = data
|
||||
self.limit = limit
|
||||
self.bytes_read = 0
|
||||
|
||||
def __iter__(self):
|
||||
for chunk in self.data:
|
||||
self.bytes_read += len(chunk)
|
||||
if self.bytes_read > self.limit:
|
||||
raise exception.ImageSizeLimitExceeded()
|
||||
else:
|
||||
yield chunk
|
||||
|
||||
def read(self, i):
|
||||
result = self.data.read(i)
|
||||
self.bytes_read += len(result)
|
||||
if self.bytes_read > self.limit:
|
||||
raise exception.ImageSizeLimitExceeded()
|
||||
else:
|
||||
yield chunk
|
||||
return result
|
||||
|
||||
|
||||
def image_meta_to_http_headers(image_meta):
|
||||
|
@ -15,6 +15,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import StringIO
|
||||
import tempfile
|
||||
|
||||
from glance.common import exception
|
||||
@ -72,18 +73,45 @@ class TestUtils(test_utils.BaseTestCase):
|
||||
|
||||
self.assertEquals(bytes_read, BYTES)
|
||||
|
||||
def test_limited_iter_reads_succeed(self):
|
||||
fap = 'abcdefghij'
|
||||
fap = utils.limiting_iter(fap, 10)
|
||||
def test_limiting_reader(self):
|
||||
"""Ensure limiting reader class accesses all bytes of file"""
|
||||
BYTES = 1024
|
||||
bytes_read = 0
|
||||
for chunk in fap:
|
||||
data = StringIO.StringIO("*" * BYTES)
|
||||
for chunk in utils.LimitingReader(data, BYTES):
|
||||
bytes_read += len(chunk)
|
||||
self.assertEqual(10, bytes_read)
|
||||
|
||||
def test_limited_iter_reads_fail(self):
|
||||
fap = 'abcdefghij'
|
||||
fap = utils.limiting_iter(fap, 9)
|
||||
for i, chunk in enumerate(fap):
|
||||
if i == 8:
|
||||
break
|
||||
self.assertRaises(exception.ImageSizeLimitExceeded, fap.next)
|
||||
self.assertEquals(bytes_read, BYTES)
|
||||
|
||||
bytes_read = 0
|
||||
data = StringIO.StringIO("*" * BYTES)
|
||||
reader = utils.LimitingReader(data, BYTES)
|
||||
byte = reader.read(1)
|
||||
while len(byte) != 0:
|
||||
bytes_read += 1
|
||||
byte = reader.read(1)
|
||||
|
||||
self.assertEquals(bytes_read, BYTES)
|
||||
|
||||
def test_limiting_reader_fails(self):
|
||||
"""Ensure limiting reader class throws exceptions if limit exceeded"""
|
||||
BYTES = 1024
|
||||
|
||||
def _consume_all_iter():
|
||||
bytes_read = 0
|
||||
data = StringIO.StringIO("*" * BYTES)
|
||||
for chunk in utils.LimitingReader(data, BYTES - 1):
|
||||
bytes_read += len(chunk)
|
||||
|
||||
self.assertRaises(exception.ImageSizeLimitExceeded, _consume_all_iter)
|
||||
|
||||
def _consume_all_read():
|
||||
bytes_read = 0
|
||||
data = StringIO.StringIO("*" * BYTES)
|
||||
reader = utils.LimitingReader(data, BYTES - 1)
|
||||
byte = reader.read(1)
|
||||
while len(byte) != 0:
|
||||
bytes_read += 1
|
||||
byte = reader.read(1)
|
||||
|
||||
self.assertRaises(exception.ImageSizeLimitExceeded, _consume_all_read)
|
||||
|
Loading…
Reference in New Issue
Block a user