yhirose/cpp-httplib

Server::set_payload_max_length cannot increase the payload size beyond 8 KiB

Gondlar opened this issue · 4 comments

httplib currently has two mechanisms for checking the payload size and returning HTTP status code 413:

First, it checks the Content-Length header and compares it to payload_max_length, which is set using Server::set_payload_max_length.

cpp-httplib/httplib.h

Lines 3916 to 3923 in e426a38

auto len = get_header_value_u64(x.headers, "Content-Length", 0, 0);
if (len > payload_max_length) {
exceed_payload_max_length = true;
skip_content_with_length(strm, len);
ret = false;
} else if (len > 0) {
ret = read_content_with_length(strm, len, std::move(progress), out);
}

Secondly, for POST data, it compares the actual size of the payload to the precompiler constant CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH, which defaults to 8 KiB.

cpp-httplib/httplib.h

Lines 6008 to 6014 in e426a38

if (!content_type.find("application/x-www-form-urlencoded")) {
if (req.body.size() > CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH) {
res.status = 413; // NOTE: should be 414?
return false;
}
detail::parse_query_text(req.body, req.params);
}

Since both checks are made, the lower value always wins. The behavior has been noticed in the past, e.g., in #144, but not addressed. Note that the test mentioned when closing that bug report does not actually apply to the issue at hand: It sets Server::set_payload_max_length to 8, which is lower than 8KiB and hence works as expected.

In my opinion, the contention between these two ways to configure this behavior is a problem. Is there a reason why there are two configuration parameters for this? If not, I think the second case should be adapted to use the value set by Server::set_payload_max_length as well. Otherwise, the README should clearly document this behavior and not cite Server::set_payload_max_length as the sole place to configure this.

@Gondlar thanks for the detailed information. The problem that you mentioned only happens with a request which has the 'application/x-www-form-urlencoded' content type. CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH is made to protect a cpp-http server from attacks with huge 'www-form-urlencoded' data which may make detail::parse_query_text unresponsive. (detail::parse_query_text is a slow function and will keep all the key-value pairs in memory...)

Could you give me any suggestion where in REAME I can put such information that will help users? Thanks for your help.

I'd suggest the part that deals with "Set maximum payload length for reading a request body", that's where people who need to know this are most likely to look.

cpp-httplib/README.md

Lines 414 to 419 in e426a38

### Set maximum payload length for reading a request body
```c++
svr.set_payload_max_length(1024 * 1024 * 512); // 512MB
```

Does it sound good to you?

### Set maximum payload length for reading a request body

```c++
svr.set_payload_max_length(1024 * 1024 * 512); // 512MB

NOTE: When the request body content type is 'www-form-urlencoded', the actual payload length shouldn't exceed CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH.

Sounds fine, thanks!