httpx icon indicating copy to clipboard operation
httpx copied to clipboard

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

Open wesley800 opened this issue 3 years ago • 0 comments
trafficstars

This problem is basically an extension of https://github.com/encode/httpx/discussions/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.

wesley800 avatar Sep 22 '22 10:09 wesley800