def multipart_response_iter(self, resp, boundary, body_key, crypto_meta): """ Decrypts a multipart mime doc response body. :param resp: application response :param boundary: multipart boundary string :param body_key: decryption key for the response body :param crypto_meta: crypto_meta for the response body :return: generator for decrypted response body """ with closing_if_possible(resp): parts_iter = multipart_byteranges_to_document_iters( FileLikeIter(resp), boundary) for first_byte, last_byte, length, headers, body in parts_iter: yield "--" + boundary + "\r\n" for header_pair in headers: yield "%s: %s\r\n" % header_pair yield "\r\n" decrypt_ctxt = self.crypto.create_decryption_ctxt( body_key, crypto_meta['iv'], first_byte) for chunk in iter(lambda: body.read(DECRYPT_CHUNK_SIZE), ''): yield decrypt_ctxt.update(chunk) yield "\r\n" yield "--" + boundary + "--"
def multipart_response_iter(self, resp, boundary, body_key, crypto_meta): """ Decrypts a multipart mime doc response body. :param resp: application response :param boundary: multipart boundary string :param body_key: decryption key for the response body :param crypto_meta: crypto_meta for the response body :return: generator for decrypted response body """ with closing_if_possible(resp): parts_iter = multipart_byteranges_to_document_iters( FileLikeIter(resp), boundary) for first_byte, last_byte, length, headers, body in parts_iter: yield b"--" + boundary + b"\r\n" for header, value in headers: yield b"%s: %s\r\n" % (wsgi_to_bytes(header), wsgi_to_bytes(value)) yield b"\r\n" decrypt_ctxt = self.crypto.create_decryption_ctxt( body_key, crypto_meta['iv'], first_byte) for chunk in iter(lambda: body.read(DECRYPT_CHUNK_SIZE), b''): yield decrypt_ctxt.update(chunk) yield b"\r\n" yield b"--" + boundary + b"--"
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 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)