google-auth-library-python icon indicating copy to clipboard operation
google-auth-library-python copied to clipboard

_aiohttp_requests.AuthorizedSession is not decompressing Google Drive API response

Open tstodden opened this issue 3 years ago • 1 comments

Environment details

  • OS: Arch Linux
  • Python version: 3.10.0
  • pip version: 21.2.4
  • google-auth version: 2.3.3

Steps to reproduce

  1. Create a service account and generate a JSON key for it
  2. Create a google.oauth2._service_account_async.Credentials instance with the scope https://www.googleapis.com/auth/drive.metadata.readonly
  3. Create a google.auth.transport._aiohttp_requests.AuthorizedSession instance using the credentials
  4. Make a GET request similar to session.request("GET", "https://www.googleapis.com/drive/v3/files/{fileId}") replacing fileId with the file identifier of a file (Google Sheet, Google Doc, etc.) that you shared with the service account
  5. The request you get back will be an aiohttp.ClientResponse instance and the body will still be compressed using gzip. Therefore, if you attempt to use response.json() it will fail when attempting to decode it

I was able to temporarily overcome this by wrapping the aiohttp.ClientResponse in _aiohttp_requests._CombinedResponse and using the content() method which has logic to decompress the payload.

Let me know if perhaps I'm using the interface wrong or if it would be helpful for me to give additional context, thanks!

tstodden avatar Nov 07 '21 02:11 tstodden

Hi @tstodden,

That looks like a reasonable approach given the current code - I get similar results with the following code snippet constructed from your reproduction steps:

import asyncio

from google.auth.transport import _aiohttp_requests
from google.oauth2 import _service_account_async


credentials = _service_account_async.Credentials.from_service_account_file(
    "/path/to/service_account.json",
    scopes=["https://www.googleapis.com/auth/drive.metadata.readonly"],
)

file_id = "my-file-id"

async def main():

    async with _aiohttp_requests.AuthorizedSession(
        credentials=credentials
    ) as authed_session:
        response = await authed_session.request(
            "GET", f"https://www.googleapis.com/drive/v3/files/{file_id}"
        )

        response = _aiohttp_requests._CombinedResponse(response)
        content = await response.content()
        print(content)


asyncio.run(main())

I'm not sure if the intent was that the additional manual wrapping would be required. I'll take a closer look at the history of the aiohttp transport and get back to you.

busunkim96 avatar Nov 10 '21 00:11 busunkim96