Skip to content

Repeated client request with multipart FormData results in field duplication #4345

Closed
@ulrikjohansson

Description

Long story short

We've run into a problem where a repeated client session request with the same arguments end up not sending the same request data, but duplicted fields.
Reproducible request are important to us because we're using a circuit breaker library with our client requests that do retries on certain errors (like ServerDisconnectedError and TimeoutError)

Expected behaviour

When I repeat a call to ClientSession.request with the exact same arguments I expect to send a copy of the first request

Actual behaviour

When using a FormData object with a field that gets the _is_multipart property set to True, the form fields are duplicated. The machinery inside FormData._gen_form_data just appends the form fields again on each request using it.
`

Steps to reproduce

import asyncio
from aiohttp import ClientSession, FormData
from copy import deepcopy

from aiohttp import __version__ as version
print(f"aiohttp version: {version}")

async def run():
    async with ClientSession() as session:
        url = "http://httpbin.org/anything"
        data = FormData()
        data.add_field("test", "test_value", content_type="application/json")

        for n in range(2):
            await session.post(url, data=data)
            print(f"writer part count: {len(data._writer._parts)} <-- this should stay at 1")

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

Workaround

A workaround for this issue is passing a deepcopy of the FormData object to ClientSession.request

Your environment

aiohttp version: tested with 3.5.4 & 3.6.2
aiohttp component: client
os: linux (ubuntu 19.10)

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions