def http_response_to_document_iters(response, read_chunk_size=4096): """ Takes a successful object-GET HTTP response and turns it into an iterator of (first-byte, last-byte, length, headers, body-file) 5-tuples. The response must either be a 200 or a 206; if you feed in a 204 or something similar, this probably won't work. :param response: HTTP response, like from bufferedhttp.http_connect(), not a swob.Response. """ chunked = is_chunked(dict(response.getheaders())) if response.status == 200: if chunked: # Single "range" that's the whole object with an unknown length return iter([(0, None, None, response.getheaders(), response)]) # Single "range" that's the whole object content_length = int(response.getheader("Content-Length")) return iter([(0, content_length - 1, content_length, response.getheaders(), response)]) content_type, params_list = parse_content_type(response.getheader("Content-Type")) if content_type != "multipart/byteranges": # Single range; no MIME framing, just the bytes. The start and end # byte indices are in the Content-Range header. start, end, length = parse_content_range(response.getheader("Content-Range")) return iter([(start, end, length, response.getheaders(), response)]) else: # Multiple ranges; the response body is a multipart/byteranges MIME # document, and we have to parse it using the MIME boundary # extracted from the Content-Type header. params = dict(params_list) return multipart_byteranges_to_document_iters(response, params["boundary"], read_chunk_size)
def handle(self, req, start_response): app_resp = self._app_call(req.environ) try: put_crypto_meta = self._read_crypto_meta( 'X-Object-Sysmeta-Crypto-Body-Meta', True) put_keys = self.get_decryption_keys(req, put_crypto_meta) post_crypto_meta = self._read_crypto_meta( 'X-Object-Transient-Sysmeta-Crypto-Meta', False) post_keys = self.get_decryption_keys(req, post_crypto_meta) except EncryptionException as err: self.logger.error( "Error decrypting object: %s", err) raise HTTPInternalServerError( body='Error decrypting object', content_type='text/plain') if put_keys is None and post_keys is None: # skip decryption start_response(self._response_status, self._response_headers, self._response_exc_info) return app_resp mod_resp_headers = self.decrypt_resp_headers(put_keys, post_keys) if put_crypto_meta and req.method == 'GET' and \ is_success(self._get_status_int()): # 2xx response and encrypted body body_key = self.get_unwrapped_key( put_crypto_meta, put_keys['object']) content_type, content_type_attrs = parse_content_type( self._response_header_value('Content-Type')) if (self._get_status_int() == 206 and content_type == 'multipart/byteranges'): boundary = wsgi_to_bytes(dict(content_type_attrs)["boundary"]) resp_iter = self.multipart_response_iter( app_resp, boundary, body_key, put_crypto_meta) else: offset = 0 content_range = self._response_header_value('Content-Range') if content_range: # Determine offset within the whole object if ranged GET offset, end, total = parse_content_range(content_range) resp_iter = self.response_iter( app_resp, body_key, put_crypto_meta, offset) else: # don't decrypt body of unencrypted or non-2xx responses resp_iter = app_resp mod_resp_headers = purge_crypto_sysmeta_headers(mod_resp_headers) start_response(self._response_status, mod_resp_headers, self._response_exc_info) return resp_iter
def handle_get(self, req, start_response): app_resp = self._app_call(req.environ) keys = self.get_decryption_keys(req) if keys is None: # skip decryption start_response(self._response_status, self._response_headers, self._response_exc_info) return app_resp mod_resp_headers = self.decrypt_resp_headers(keys) crypto_meta = None if is_success(self._get_status_int()): try: crypto_meta = self.get_crypto_meta( 'X-Object-Sysmeta-Crypto-Body-Meta') except EncryptionException as err: msg = 'Error decrypting object' self.logger.error( _('%(msg)s: %(err)s') % { 'msg': msg, 'err': err }) raise HTTPInternalServerError(body=msg, content_type='text/plain') if crypto_meta: # 2xx response and encrypted body body_key = self.get_unwrapped_key(crypto_meta, keys['object']) content_type, content_type_attrs = parse_content_type( self._response_header_value('Content-Type')) if (self._get_status_int() == 206 and content_type == 'multipart/byteranges'): boundary = dict(content_type_attrs)["boundary"] resp_iter = self.multipart_response_iter( app_resp, boundary, body_key, crypto_meta) else: offset = 0 content_range = self._response_header_value('Content-Range') if content_range: # Determine offset within the whole object if ranged GET offset, end, total = parse_content_range(content_range) resp_iter = self.response_iter(app_resp, body_key, crypto_meta, offset) else: # don't decrypt body of unencrypted or non-2xx responses resp_iter = app_resp mod_resp_headers = purge_crypto_sysmeta_headers(mod_resp_headers) start_response(self._response_status, mod_resp_headers, self._response_exc_info) return resp_iter
def handle_get(self, req, start_response): app_resp = self._app_call(req.environ) keys = self.get_decryption_keys(req) if keys is None: # skip decryption start_response(self._response_status, self._response_headers, self._response_exc_info) return app_resp mod_resp_headers = self.decrypt_resp_headers(keys) crypto_meta = None if is_success(self._get_status_int()): try: crypto_meta = self.get_crypto_meta( 'X-Object-Sysmeta-Crypto-Body-Meta') except EncryptionException as err: msg = 'Error decrypting object' self.logger.error(_('%(msg)s: %(err)s') % {'msg': msg, 'err': err}) raise HTTPInternalServerError( body=msg, content_type='text/plain') if crypto_meta: # 2xx response and encrypted body body_key = self.get_unwrapped_key(crypto_meta, keys['object']) content_type, content_type_attrs = parse_content_type( self._response_header_value('Content-Type')) if (self._get_status_int() == 206 and content_type == 'multipart/byteranges'): boundary = dict(content_type_attrs)["boundary"] resp_iter = self.multipart_response_iter( app_resp, boundary, body_key, crypto_meta) else: offset = 0 content_range = self._response_header_value('Content-Range') if content_range: # Determine offset within the whole object if ranged GET offset, end, total = parse_content_range(content_range) resp_iter = self.response_iter( app_resp, body_key, crypto_meta, offset) else: # don't decrypt body of unencrypted or non-2xx responses resp_iter = app_resp mod_resp_headers = purge_crypto_sysmeta_headers(mod_resp_headers) start_response(self._response_status, mod_resp_headers, self._response_exc_info) return resp_iter
def handle_get(self, req, start_response): app_resp = self._app_call(req.environ) put_crypto_meta = self._read_crypto_meta( 'X-Object-Sysmeta-Crypto-Body-Meta', True) put_keys = self.get_decryption_keys(req, put_crypto_meta) post_crypto_meta = self._read_crypto_meta( 'X-Object-Transient-Sysmeta-Crypto-Meta', False) post_keys = self.get_decryption_keys(req, post_crypto_meta) if put_keys is None and post_keys is None: # skip decryption start_response(self._response_status, self._response_headers, self._response_exc_info) return app_resp mod_resp_headers = self.decrypt_resp_headers(put_keys, post_keys) if put_crypto_meta and is_success(self._get_status_int()): # 2xx response and encrypted body body_key = self.get_unwrapped_key(put_crypto_meta, put_keys['object']) content_type, content_type_attrs = parse_content_type( self._response_header_value('Content-Type')) if (self._get_status_int() == 206 and content_type == 'multipart/byteranges'): boundary = dict(content_type_attrs)["boundary"] resp_iter = self.multipart_response_iter( app_resp, boundary, body_key, put_crypto_meta) else: offset = 0 content_range = self._response_header_value('Content-Range') if content_range: # Determine offset within the whole object if ranged GET offset, end, total = parse_content_range(content_range) resp_iter = self.response_iter(app_resp, body_key, put_crypto_meta, offset) else: # don't decrypt body of unencrypted or non-2xx responses resp_iter = app_resp mod_resp_headers = purge_crypto_sysmeta_headers(mod_resp_headers) start_response(self._response_status, mod_resp_headers, self._response_exc_info) return resp_iter
def http_response_to_document_iters(response, read_chunk_size=4096): """ Takes a successful object-GET HTTP response and turns it into an iterator of (first-byte, last-byte, length, headers, body-file) 5-tuples. The response must either be a 200 or a 206; if you feed in a 204 or something similar, this probably won't work. :param response: HTTP response, like from bufferedhttp.http_connect(), not a swob.Response. """ chunked = is_chunked(dict(response.getheaders())) if response.status == 200: if chunked: # Single "range" that's the whole object with an unknown length return iter([(0, None, None, response.getheaders(), response)]) # Single "range" that's the whole object print 'Content-Length : ' + response.getheader('Content-Length') content_length = int(response.getheader('Content-Length')) return iter([(0, content_length - 1, content_length, response.getheaders(), response)]) content_type, params_list = parse_content_type( response.getheader('Content-Type')) if content_type != 'multipart/byteranges': # Single range; no MIME framing, just the bytes. The start and end # byte indices are in the Content-Range header. start, end, length = parse_content_range( response.getheader('Content-Range')) return iter([(start, end, length, response.getheaders(), response)]) else: # Multiple ranges; the response body is a multipart/byteranges MIME # document, and we have to parse it using the MIME boundary # extracted from the Content-Type header. params = dict(params_list) return multipart_byteranges_to_document_iters(response, params['boundary'], read_chunk_size)