diff --git a/glanceclient/common/http.py b/glanceclient/common/http.py index d963be67..cc62c417 100644 --- a/glanceclient/common/http.py +++ b/glanceclient/common/http.py @@ -5,6 +5,7 @@ OpenStack Client interface. Handles the REST calls and responses. import copy import logging import os +import StringIO import urlparse import httplib2 @@ -25,6 +26,7 @@ from glanceclient import exc logger = logging.getLogger(__name__) USER_AGENT = 'python-glanceclient' +CHUNKSIZE = 1024 * 64 # 64kB class HTTPClient(httplib2.Http): @@ -88,7 +90,12 @@ class HTTPClient(httplib2.Http): # Redirected. Reissue the request to the new location. return self._http_request(resp['location'], method, **kwargs) - return resp, body + #NOTE(bcwaldon): body has been loaded to a string at this point, + # but we want to move to a world where it can be read from a + # socket-level cache. This is here until we can do that. + body_iter = ResponseBodyIterator(StringIO.StringIO(body)) + + return resp, body_iter def json_request(self, method, url, **kwargs): kwargs.setdefault('headers', {}) @@ -97,7 +104,8 @@ class HTTPClient(httplib2.Http): if 'body' in kwargs: kwargs['body'] = json.dumps(kwargs['body']) - resp, body = self._http_request(url, method, **kwargs) + resp, body_iter = self._http_request(url, method, **kwargs) + body = ''.join([chunk for chunk in body_iter]) if body: try: @@ -115,3 +123,21 @@ class HTTPClient(httplib2.Http): kwargs['headers'].setdefault('Content-Type', 'application/octet-stream') return self._http_request(url, method, **kwargs) + + +class ResponseBodyIterator(object): + """A class that acts as an iterator over an HTTP response.""" + + def __init__(self, resp): + self.resp = resp + + def __iter__(self): + while True: + yield self.next() + + def next(self): + chunk = self.resp.read(CHUNKSIZE) + if chunk: + return chunk + else: + raise StopIteration() diff --git a/glanceclient/v1/images.py b/glanceclient/v1/images.py index 5bee3597..4263bafd 100644 --- a/glanceclient/v1/images.py +++ b/glanceclient/v1/images.py @@ -159,8 +159,9 @@ class ImageManager(base.Manager): if copy_from is not None: hdrs['x-glance-api-copy-from'] = copy_from - resp, body = self.api.raw_request( + resp, body_iter = self.api.raw_request( 'POST', '/v1/images', headers=hdrs, body=image_data) + body = ''.join([c for c in body_iter]) return Image(self, json.loads(body)['image']) def update(self, image, **kwargs): @@ -199,6 +200,7 @@ class ImageManager(base.Manager): hdrs['x-glance-api-copy-from'] = copy_from url = '/v1/images/%s' % base.getid(image) - resp, body = self.api.raw_request( + resp, body_iter = self.api.raw_request( 'PUT', url, headers=hdrs, body=image_data) + body = ''.join([c for c in body_iter]) return Image(self, json.loads(body)['image']) diff --git a/tests/v1/test_images.py b/tests/v1/test_images.py index b3fe1281..dc2f2c17 100644 --- a/tests/v1/test_images.py +++ b/tests/v1/test_images.py @@ -131,7 +131,7 @@ class ImageManagerTest(unittest.TestCase): self.assertEqual(image.name, 'image-1') def test_data(self): - data = self.mgr.data('1') + data = ''.join([b for b in self.mgr.data('1')]) expect = [('GET', '/v1/images/1', {}, None)] self.assertEqual(self.api.calls, expect) self.assertEqual(data, 'XXX') @@ -256,7 +256,7 @@ class ImageTest(unittest.TestCase): def test_data(self): image = self.mgr.get('1') - data = image.data() + data = ''.join([b for b in image.data()]) expect = [ ('HEAD', '/v1/images/1', {}, None), ('GET', '/v1/images/1', {}, None),