Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Counting bytes in a forwarded stream #3598

Closed
drtpotter opened this issue Feb 7, 2019 · 5 comments
Closed

Counting bytes in a forwarded stream #3598

drtpotter opened this issue Feb 7, 2019 · 5 comments
Labels

Comments

@drtpotter
Copy link

drtpotter commented Feb 7, 2019

Hi there,

In the documentation I see that I can open a connection from one source and pass the content to another stream as follows:

resp = await session.get('http://python.org')
await session.post('http://httpbin.org/post', data=resp.content)

In my implementation of this I will be forwarding streams of potentially very large files with unknown length. I need to be able to count the bytes that is transferred in resp.content without dumping resp.content to a local file. How can I do this?

Thankyou in advance!

@aio-libs-bot
Copy link

GitMate.io thinks the contributor most likely able to help you is @asvetlov.

Possibly related issues are #3440 (Streams reorganization), #1101 (Streaming to FormData), #2555 (Simplify stream classes), #3260 (Deprecate stream.unread_data), and #2680 (Request ignore X-Forwarded-Proto).

@asvetlov
Copy link
Member

resp.content supports async iterator protocol.
You can wrap it into a custom class with counter:

class Wrapper:
    def __init__(self, content):
        self._content = content
        self._counter = 0
        self._iter = None

    def __aiter__(self):
         self._iter = self._content.__aiter__()
         return self._iter

    async def __anext__(self):
         chunk = await self._iter.__anext__()
         self._counter += len(chunk)
         return chunk

resp = await session.get('http://python.org')
wrapper = Wrapper(resp.content)
await session.post('http://httpbin.org/post', data=wrapper)
print(wrapper._counter)

@drtpotter
Copy link
Author

drtpotter commented Feb 15, 2019

Hi there,

Thanks for that, here is the full example but I can't seem to get anything other than zero out of wrapper._counter. Is wrapper deep-copied during session.post?

import aiohttp
import asyncio

class Wrapper:
    def __init__(self, content):
        self._content = content
        self._counter = 0
        self._iter = None

    def __aiter__(self):
         self._iter = self._content.__aiter__()
         return self  # return self, not self._iter

    async def __anext__(self):
         chunk = await self._iter.__anext__()
         self._counter += len(chunk)
         return chunk

async def main():
    session=aiohttp.ClientSession()
    resp = await session.get('http://python.org')
    wrapper = Wrapper(resp.content)
    await session.post('http://httpbin.org/post', data=wrapper)
    print(wrapper._counter)

loop = asyncio.get_event_loop()
loop.run_until_complete(main())

@asvetlov
Copy link
Member

Sorry, I've made a mistake in __aiter__.
Updated your previous full example to make it work

@drtpotter
Copy link
Author

Thanks for your help on this, much appreciated!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants