mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-17 10:59:39 +00:00
Reject CR/LF in the request target and fail the request cleanly (#2501)
* reject crlf in request target in write_request_line * declare write_request_line in test.cc for split builds split.py strips `inline` and moves the definition into httplib.cc, so detail::write_request_line is not visible from the split httplib.h and test_split failed to compile. Re-declare it in test.cc, matching what the base64_encode and getaddrinfo_with_timeout tests already do. * Fail the request when write_request_line rejects the target The CR/LF guard in write_request_line returns -1, but ClientImpl::write_request ignored that return value. A rejected target therefore produced a request-line- less request (headers only) that the client silently reported as a successful send. This is the primary path reachable via a decoded redirect Location under set_path_encode(false), and it also carries the CONNECT target. Check the return value like ClientImpl::open_stream already does and fail with Error::Write. Add an end-to-end test asserting the client refuses a CR/LF target instead of putting it on the wire. --------- Co-authored-by: Sayed Kaif <metsw24@gmail.com>
This commit is contained in:
1 parent
75938f08c7
commit
255c075b82
2 files changed
+89
-1
No files matched your search
@@ -7542,6 +7542,13 @@ bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status,
|
||||
|
||||
inline ssize_t write_request_line(Stream &strm, const std::string &method,
|
||||
const std::string &path) {
|
||||
// A request target must not carry CR/LF (or other control octets); otherwise
|
||||
// a value smuggled into it splits the request line and injects headers or a
|
||||
// whole request. The same field-value check already guards header values in
|
||||
// check_and_write_headers and the request target in
|
||||
// perform_websocket_handshake; apply it here too.
|
||||
if (!fields::is_field_value(path)) { return -1; }
|
||||
|
||||
std::string s = method;
|
||||
s += ' ';
|
||||
s += path;
|
||||
@@ -13849,7 +13856,14 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
||||
}
|
||||
|
||||
// Write request line and headers
|
||||
detail::write_request_line(bstrm, req.method, path_with_query);
|
||||
if (detail::write_request_line(bstrm, req.method, path_with_query) < 0) {
|
||||
// A rejected target (e.g. CR/LF smuggled in via a decoded redirect
|
||||
// Location under set_path_encode(false)) must fail the request cleanly
|
||||
// instead of emitting a request-line-less, header-injecting request.
|
||||
error = Error::Write;
|
||||
output_error_log(error, &req);
|
||||
return false;
|
||||
}
|
||||
if (!detail::check_and_write_headers(bstrm, req.headers, header_writer_,
|
||||
error)) {
|
||||
output_error_log(error, &req);
|
||||
|
||||
Reference in new issue
Block a user