async def test_read_chunk_by_length_doesnt_breaks_reader( self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b"--:", b"Content-Length: 4", b"", b"test", b"--:", b"Content-Length: 6", b"", b"passed", b"--:--", ])), ) body_parts = [] while True: read_part = b"" part = await reader.next() if part is None: break while not part.at_eof(): read_part += await part.read_chunk(3) body_parts.append(read_part) assert body_parts == [b"test", b"passed"]
def test_dispatch_custom_multipart_reader(self, newline: Any) -> None: class CustomReader(aiohttp.MultipartReader): pass reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join( [ b"----:--", b"", b"test", b"----:--", b"", b"passed", b"----:----", b"--:--", ] ) ), ) reader.multipart_reader_cls = CustomReader res = reader._get_part_reader( {CONTENT_TYPE: "multipart/related;boundary=--:--"} ) assert isinstance(res, CustomReader)
async def test_async_for_reader() -> None: data = [{ "test": "passed" }, 42, b'plain text', b'aiohttp\n', b'no epilogue'] reader = aiohttp.MultipartReader( headers={CONTENT_TYPE: 'multipart/mixed; boundary=":"'}, content=Stream(b'\r\n'.join([ b'--:', b'Content-Type: application/json', b'', json.dumps(data[0]).encode(), b'--:', b'Content-Type: application/json', b'', json.dumps(data[1]).encode(), b'--:', b'Content-Type: multipart/related; boundary="::"', b'', b'--::', b'Content-Type: text/plain', b'', data[2], b'--::', b'Content-Disposition: attachment; filename="aiohttp"', b'Content-Type: text/plain', b'Content-Length: 28', b'Content-Encoding: gzip', b'', b'\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03K\xcc\xcc\xcf())' b'\xe0\x02\x00\xd6\x90\xe2O\x08\x00\x00\x00', b'--::', b'Content-Type: multipart/related; boundary=":::"', b'', b'--:::', b'Content-Type: text/plain', b'', data[4], b'--:::--', b'--::--', b'', b'--:--', b'' ]))) idata = iter(data) async def check(reader): async for part in reader: if isinstance(part, aiohttp.BodyPartReader): if part.headers[CONTENT_TYPE] == 'application/json': assert next(idata) == (await part.json()) else: assert next(idata) == await part.read(decode=True) else: await check(part) await check(reader)
async def test_emit_next(self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b"--:%s\r\necho%s--:--" % (newline, newline)), ) res = await reader.next() assert isinstance(res, reader.part_reader_cls)
async def test_invalid_boundary(self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b"---:%s\r\necho%s---:--" % (newline, newline)), ) with pytest.raises(ValueError): await reader.next()
def test_dispatch_bodypart(self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b"--:%s\r\necho%s--:--" % (newline, newline)), ) res = reader._get_part_reader({CONTENT_TYPE: "text/plain"}) assert isinstance(res, reader.part_reader_cls)
async def test_read_chunk_by_length_doesnt_breaks_reader(self, newline) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b'--:', b'Content-Length: 4', b'', b'test', b'--:', b'Content-Length: 6', b'', b'passed', b'--:--', ]))) body_parts = [] while True: read_part = b'' part = await reader.next() if part is None: break while not part.at_eof(): read_part += await part.read_chunk(3) body_parts.append(read_part) assert body_parts == [b'test', b'passed']
async def test_read_mixed_newlines(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/mixed;boundary=":"'}, Stream(b"".join([ b"--:\n", b"Content-Type: multipart/related;boundary=--:--\n", b"\n", b"----:--\r\n", b"\r\n", b"test\r\n", b"----:--\r\n", b"\r\n", b"passed\r\n", b"----:----\r\n", b"\n", b"--:--", ])), ) while True: part = await reader.next() if part is None: break while True: subpart = await part.next() if subpart is None: break
async def test_read_chunk_from_stream_doesnt_breaks_reader( self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b"--:", b"", b"chunk", b"--:", b"", b"two_chunks", b"--:--", ])), ) body_parts = [] while True: read_part = b"" part = await reader.next() if part is None: break while not part.at_eof(): chunk = await part.read_chunk(5) assert chunk read_part += chunk body_parts.append(read_part) assert body_parts == [b"chunk", b"two_chunks"]
async def test_release_next(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'--:\r\n\r\necho\r\n--:--')) await reader.release() assert reader.at_eof() res = await reader.next() assert res is None
async def test_release_release(self, newline) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'--:%s\r\necho%s--:--' % (newline, newline))) await reader.release() assert reader.at_eof() await reader.release() assert reader.at_eof()
async def test_release_next(self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b"--:%s\r\necho%s--:--" % (newline, newline)), ) await reader.release() assert reader.at_eof() res = await reader.next() assert res is None
async def post_create_resource(request, userdata): # pylint: disable=unused-argument db = request.app['db'] storage_client = request.app['storage_client'] checked_csrf = False attachments = {} post = {} reader = aiohttp.MultipartReader(request.headers, request.content) while True: part = await reader.next() # pylint: disable=not-callable if not part: break if part.name == '_csrf': # check csrf token # form fields are delivered in ordrer, the _csrf hidden field should appear first # https://stackoverflow.com/questions/7449861/multipart-upload-form-is-order-guaranteed token1 = request.cookies.get('_csrf') token2 = await part.text() if token1 is None or token2 is None or token1 != token2: log.info('request made with invalid csrf tokens') raise web.HTTPUnauthorized() checked_csrf = True elif part.name == 'file': if not checked_csrf: raise web.HTTPUnauthorized() filename = part.filename if not filename: continue attachment_id = secret_alnum_string() async with await storage_client.insert_object( BUCKET, f'atgu/attachments/{attachment_id}') as f: while True: chunk = await part.read_chunk() if not chunk: break await f.write(chunk) attachments[attachment_id] = filename else: post[part.name] = await part.text() if not checked_csrf: raise web.HTTPUnauthorized() now = time_msecs() id = await db.execute_insertone( ''' INSERT INTO `atgu_resources` (`time_created`, `title`, `description`, `contents`, `tags`, `attachments`, `time_updated`) VALUES (%s, %s, %s, %s, %s, %s, %s); ''', (now, post['title'], post['description'], post['contents'], post['tags'], json.dumps(attachments), now), ) return web.HTTPFound(deploy_config.external_url('atgu', f'/resources/{id}'))
async def test_reading_skips_prelude(self, newline) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b'Multi-part data is not supported.', b'', b'--:', b'', b'test', b'--:', b'', b'passed', b'--:--' ]))) first = await reader.next() assert isinstance(first, aiohttp.BodyPartReader) second = await reader.next() assert first.at_eof() assert not second.at_eof()
def test_dispatch_multipart(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'----:--\r\n' b'\r\n' b'test\r\n' b'----:--\r\n' b'\r\n' b'passed\r\n' b'----:----\r\n' b'--:--')) res = reader._get_part_reader( {CONTENT_TYPE: 'multipart/related;boundary=--:--'}) assert isinstance(res, reader.__class__)
async def test_second_next_releases_previous_object(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'--:\r\n' b'\r\n' b'test\r\n' b'--:\r\n' b'\r\n' b'passed\r\n' b'--:--')) first = await reader.next() assert isinstance(first, aiohttp.BodyPartReader) second = await reader.next() assert first.at_eof() assert not second.at_eof()
def test_dispatch_multipart(self, newline) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b'----:--', b'', b'test', b'----:--', b'', b'passed', b'----:----' b'--:--', ]))) res = reader._get_part_reader( {CONTENT_TYPE: 'multipart/related;boundary=--:--'}) assert isinstance(res, reader.__class__)
async def test_reading_skips_prelude(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'Multi-part data is not supported.\r\n' b'\r\n' b'--:\r\n' b'\r\n' b'test\r\n' b'--:\r\n' b'\r\n' b'passed\r\n' b'--:--')) first = await reader.next() assert isinstance(first, aiohttp.BodyPartReader) second = await reader.next() assert first.at_eof() assert not second.at_eof()
async def test_release_without_read_the_last_object(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'--:\r\n' b'\r\n' b'test\r\n' b'--:\r\n' b'\r\n' b'passed\r\n' b'--:--')) first = await reader.next() second = await reader.next() third = await reader.next() assert first.at_eof() assert second.at_eof() assert second.at_eof() assert third is None
def test_dispatch_custom_multipart_reader(self) -> None: class CustomReader(aiohttp.MultipartReader): pass reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'----:--\r\n' b'\r\n' b'test\r\n' b'----:--\r\n' b'\r\n' b'passed\r\n' b'----:----\r\n' b'--:--')) reader.multipart_reader_cls = CustomReader res = reader._get_part_reader( {CONTENT_TYPE: 'multipart/related;boundary=--:--'}) assert isinstance(res, CustomReader)
async def test_release(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/mixed;boundary=":"'}, Stream(b'--:\r\n' b'Content-Type: multipart/related;boundary=--:--\r\n' b'\r\n' b'----:--\r\n' b'\r\n' b'test\r\n' b'----:--\r\n' b'\r\n' b'passed\r\n' b'----:----\r\n' b'\r\n' b'--:--')) await reader.release() assert reader.at_eof()
async def test_second_next_releases_previous_object(self, newline) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b'--:', b'', b'test', b'--:', b'', b'passed', b'--:--', ]))) first = await reader.next() assert isinstance(first, aiohttp.BodyPartReader) second = await reader.next() assert first.at_eof() assert not second.at_eof()
def test_dispatch_multipart(self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b"----:--", b"", b"test", b"----:--", b"", b"passed", b"----:----" b"--:--", ])), ) res = reader._get_part_reader( {CONTENT_TYPE: "multipart/related;boundary=--:--"}) assert isinstance(res, reader.__class__)
async def test_release_without_read_the_last_object(self, newline) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b'--:', b'', b'test', b'--:', b'', b'passed', b'--:--', ]))) first = await reader.next() second = await reader.next() third = await reader.next() assert first.at_eof() assert second.at_eof() assert second.at_eof() assert third is None
async def test_release(self, newline) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/mixed;boundary=":"'}, Stream( newline.join([ b'--:', b'Content-Type: multipart/related;boundary=--:--', b'', b'----:--', b'', b'test', b'----:--', b'', b'passed', b'----:----', b'', b'--:--', ]))) await reader.release() assert reader.at_eof()
def test_dispatch_custom_multipart_reader(self, newline) -> None: class CustomReader(aiohttp.MultipartReader): pass reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b'----:--', b'', b'test', b'----:--', b'', b'passed', b'----:----', b'--:--', ]))) reader.multipart_reader_cls = CustomReader res = reader._get_part_reader( {CONTENT_TYPE: 'multipart/related;boundary=--:--'}) assert isinstance(res, CustomReader)
async def test_release(self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/mixed;boundary=":"'}, Stream( newline.join([ b"--:", b"Content-Type: multipart/related;boundary=--:--", b"", b"----:--", b"", b"test", b"----:--", b"", b"passed", b"----:----", b"", b"--:--", ])), ) await reader.release() assert reader.at_eof()
async def test_reading_skips_prelude(self, newline: Any) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream( newline.join([ b"Multi-part data is not supported.", b"", b"--:", b"", b"test", b"--:", b"", b"passed", b"--:--", ])), ) first = await reader.next() assert isinstance(first, aiohttp.BodyPartReader) second = await reader.next() assert first.at_eof() assert not second.at_eof()
async def test_read_chunk_from_stream_doesnt_breaks_reader(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'--:\r\n' b'\r\n' b'chunk' b'\r\n--:\r\n' b'\r\n' b'two_chunks' b'\r\n--:--')) body_parts = [] while True: read_part = b'' part = await reader.next() if part is None: break while not part.at_eof(): chunk = await part.read_chunk(5) assert chunk read_part += chunk body_parts.append(read_part) assert body_parts == [b'chunk', b'two_chunks']
async def test_invalid_boundary(self) -> None: reader = aiohttp.MultipartReader( {CONTENT_TYPE: 'multipart/related;boundary=":"'}, Stream(b'---:\r\n\r\necho\r\n---:--')) with pytest.raises(ValueError): await reader.next()