Skip to content

encode_content prevents requests with content=encode_multipart_data(...) from sending by AsyncClient #2377

@wesley800

Description

@wesley800

This problem is basically an extension of #2341 . Suppose one wants to send a POST request with multipart-encoded form data (but NOT uploading files), without any cookie sessions. One way to do that is to build something like:

ac = httpx.AsyncClient()
formdata = {"user":"John","pwd":"secret!"}
header, content = httpx._content.encode_multipart_data(formdata, {}, b'----WebkitRandomBoundary')
req = httpx.Request("POST", 'https://example.org/login', content=content, headers=header)
res = await ac.send(req, auth=None, follow_redirects=False)

ac.send() would definitely check if req.stream implements AsyncByteStream (actually it's checked in ac._send_single_request()), which surprisingly fail. But it goes flawlessly when using httpx.Client() to send the request.

Although content is of type httpx._multipart.MultipartStream, and does implement AsyncByteStream. But in encode_content called by the constructure of httpx.Request, content is wrapped again into IteratorByteStream, which drops the impl to AsyncByteStream. For now it can be hacked by directly assign stream=content and manually call the "private" method req._prepare(header), which seems to not be a good practice at least to me.

I guess there's two solutions. One is to add a AsyncRequest type, as well as the corresponding encode_async_request. The other is to build a new interface SyncAndAsyncIteratorByteStream and change encode_content to check first if the data origin supports both Iterable and AsyncIterable first.

Metadata

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