babelouest / ulfius

Web Framework to build REST APIs, Webservices or any HTTP endpoint in C language. Can stream large amount of data, integrate JSON data with Jansson, and create websocket services
https://babelouest.github.io/ulfius
GNU Lesser General Public License v2.1
1.07k stars 183 forks source link

Issue faced in file_upload_callback in Ulfius TLS mode [HTTPS] #271

Open gayathriaccount opened 5 months ago

gayathriaccount commented 5 months ago

Hi, We have a usecase in processing a multipart request using ulfius file upload callback function. When this usecase is tested in Non-TLS mode [ http ], it seems to work fine without any issue. But if the same case is tested in TLS mode [ https ], we are facing some issue.

SCENARIO: Consider the below Non-TLS request:

/usr/bin/curl -X POST -H "Content-Type:multipart/form-data" -F restcacertspem=@hello.txt http://localhost:port/endpointName

hello.txt file content: abcdefghijklmnopqrstuvwxyz

Result: The file upload callback is invoked once with complete data as expected. Values fetched inside the callback is as below: key === restcacertspem filename === hello.txt content_type === text/plain transfer_encoding === (null) data === abcdefghijklmnopqrstuvwxyz size === 26


The same scenario is not working with the below TLS request /usr/bin/curl -X POST -H "Content-Type:multipart/form-data" -F restcacertspem=@hello.txt https://localhost:port/endpointName --insecure

Result: In this case, the file upload callback is invoked twice with incomplete data key === restcacertspem filename === hello.txt content_type === text/plain transfer_encoding === (null) data === abcdefghijklmnopqrstuvwxyz

a; name="restcacertspem"; filename="hello.txt" size === 22 -------------------> The size is also not correct here. The data has 26 characters but it is giving 22.

key === restcacertspem filename === hello.txt content_type === text/plain transfer_encoding === (null) data === wxyz size === 4

Please help us to overcome this issue.

Thanks and regards Gayathri

babelouest commented 5 months ago

Hello @gayathriaccount ,

The file upload callback function is intended to be executed multiple times, as mentionned in the documentation:

 * The callback function file_upload_callback will be called
 * multiple times, with the uploaded file in striped in parts

Also, remember to use the size_t size parameter because, as in your example, the const char * data is longer than 22 in the first call, but the second will continue starting at offset 22, so if you concat data into another variable, the result may be different than what's expected.

This functionality was designed to avoid large uploads to be included in the const struct _u_request * request in the callback function, because the parameters included in it are malloc'd. This solution provides a process that will let you deal with possibly large data the way you want it.

gayathriaccount commented 5 months ago

Hi, Thank you for the detailed description. But may I get little more clarification on why this behavior is like this only for TLS mode. And also why doesn't the size match with the size of the data in the first call of the file_upload_callback.

Thanks and regards Gayathri

babelouest commented 5 months ago

The difference between TLS and non TLS mode may be because underneath libmocrohttpd handles its buffer differently, but if you try with a larger file, both modes will have multiple calls to the callback function.

The size parameter is also handled by libmocrohttpd so I'm not sure how they manage it with the data parameter, but I suppose the data parameter can be a FIFO. However, don't expect data to be complete, always use size and offset for your file upload management.