falconry / falcon

The no-magic web data plane API and microservices framework for Python developers, with a focus on reliability, correctness, and performance at scale.
https://falcon.readthedocs.io/en/stable/
Apache License 2.0
9.51k stars 937 forks source link

req.params is empty when incoming HTTP POST data has a field longer than 256 bytes. #2136

Closed justinvirtualitics closed 1 year ago

justinvirtualitics commented 1 year ago

Setup a simple API, as follows with Falcon 3.1.1:

class MyApi(object):
    def on_post(self, req, resp):
        form = req.params
        # do stuff with the form data...

app = falcon.App()
app.req_options.auto_parse_form_urlencoded = True
app.add_route('/myapi', MyApi())

Call the API from a C# app using BestHTTP/2.

HTTPRequest request = new HTTPRequest(new Uri(MyApiUri), HTTPMethods.Post, MyApiResponseCallback);
string a1= "somevalue";
string a2 = "someothervalue";
string a3 = "somethirdvalue";
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddField("a1", a1);
request.AddField("a2", a2);
request.AddField("a3", a3);
request.ConnectTimeout = new TimeSpan(0, 0, 10);
request.Timeout = new TimeSpan(0, 0, 10);
request.Send();

The above works perfectly as long as the strings aren't too large. A simple test case:

I have not found any information about a limit the 100s of bytes for a given field in a POST request like this, and I have reason to believe that this issue is on the Falcon side. I have been able to extract the values (not keys) from req.media and confirmed that the data in question has arrived at the server, but fails to be read through the request params method wrapper.

Any help would be greatly appreciated.

justinvirtualitics commented 1 year ago

A possible fix on the C#/BestHTTP side:

request.FormUsage = BestHTTP.Forms.HTTPFormUsage.UrlEncoded;

It seems that the 256 byte threshold was triggering the default "Automatic" Form Usage setting, which apparently switched it to Multipart instead of UrlEncoded as the server was expecting.

CaselIT commented 1 year ago

Hi,

I don't think there is any kind of limit on the falcon side regarding the size of the form body. Can you confirm in the on_post that the content type is x-www-form-urlencoded in all cases, even when params is empty?

Maybe you can switch to multipart in all cases and use the falcon api to handle that: https://falcon.readthedocs.io/en/stable/api/multipart.html

justinvirtualitics commented 1 year ago

Thanks for the response @CaselIT .

Upon closer investigation, the content type on the falcon side was appearing as changed (to multipart) in that case, I just hadn't noticed it before. So overall it does appear that the issue was on the C#/BestHTTP side specific to my usage, and not a problem with Falcon.

Switching the api to multipart in all cases on the Falcon side is something I may try later, but for now, I have this working as intended.

Thanks again, closing this issue now.

CaselIT commented 1 year ago

Great, thanks for reporting back

vytas7 commented 1 year ago

Just adding to @CaselIT's answer, as of Falcon 3+, it is recommended to use req.media to handle even URL-encoded forms, i.e. form = req.params becomes form = req.get_media() (auto_parse_form_urlencoded is now deprecated).