File upload with httpx from utf-8 str content (not encoded) leads to h11._util.LocalProtocolError: Too much data for declared Content-Length #7052
-
First check
ExampleServerimport uvicorn
from fastapi import FastAPI, File
app = FastAPI()
@app.put("/upload")
async def upload(file: bytes = File(...)):
...
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=20000, log_level='trace')Clientimport asyncio
import httpx
async def main():
cli: httpx.AsyncClient
async with httpx.AsyncClient(base_url='http://127.0.0.1:20000') as cli:
# await cli.put('/upload', files=[('file', ('sample.txt', 'Q'))]) # ok
# await cli.put('/upload', files=[('file', ('sample.txt', 'Й'.encode()))]) # ok
await cli.put('/upload', files=[('file', ('sample.txt', 'Й'))]) # exception, see below
if __name__ == "__main__":
asyncio.run(main())DescriptionNot sure it's about FastAPI or httpx, but suppose it should be useful here anyway. Environment
|
Beta Was this translation helpful? Give feedback.
Replies: 8 comments
-
|
Probably about uvicorn.run(app, host="0.0.0.0", port=20000, log_level='trace', http="httptools") |
Beta Was this translation helpful? Give feedback.
-
|
Does not help. I forget to mention exception is on client side. |
Beta Was this translation helpful? Give feedback.
-
|
Can you try setting a content-type? await cli.put('/upload', files=[('file', ('sample.txt', 'Й', 'text/plain'))]If it doesn't work, please check the content-length of the outgoing request and incoming request using a debugger. |
Beta Was this translation helpful? Give feedback.
-
It doesn't work.
Sorry, I don't get how to do it, instead i captured outgoing packets from client using Wireshark, here them are. Good, sending 'Q'. Bad, sending 'Й'. |
Beta Was this translation helpful? Give feedback.
-
|
This seams to be a problem with how HTTPx calculates the content-length. @AntonOvsyannikov Try using the Requests module instead and see if you can replicate the Problem. It happens with 'HTTPx' but not when I use 'requests': import requests
def main():
base_url='http://127.0.0.1:20000'
# requests.put(f'{base_url}/upload', files=[('file', ('sample.txt', 'Q'))]) # ok
# requests.put(f'{base_url}/upload', files=[('file', ('sample.txt', 'Й'.encode()))]) # ok
requests.put(f'{base_url}/upload', files=[('file', ('sample.txt', 'Й'))]) # ok
if __name__ == "__main__":
main() |
Beta Was this translation helpful? Give feedback.
-
|
I suspect this was changed recently, the content part has to be bytes now it seems.
|
Beta Was this translation helpful? Give feedback.
-
|
Assuming the original need was handled, this will be automatically closed now. But feel free to add more comments or create new issues or PRs. |
Beta Was this translation helpful? Give feedback.
-
|
This was solved some time ago. |
Beta Was this translation helpful? Give feedback.
This was solved some time ago.