You've already forked cpp-httplib
Refactor ETag handling: extract check_if_not_modified and check_if_range methods for improved readability and maintainability
This commit is contained in:
77
httplib.h
77
httplib.h
@@ -1258,6 +1258,10 @@ private:
|
||||
|
||||
bool routing(Request &req, Response &res, Stream &strm);
|
||||
bool handle_file_request(Request &req, Response &res);
|
||||
bool check_if_not_modified(const Request &req, Response &res,
|
||||
const std::string &etag, time_t mtime) const;
|
||||
bool check_if_range(Request &req, const std::string &etag,
|
||||
time_t mtime) const;
|
||||
bool dispatch_request(Request &req, Response &res,
|
||||
const Handlers &handlers) const;
|
||||
bool dispatch_request_for_content_reader(
|
||||
@@ -8357,7 +8361,6 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
|
||||
res.set_header(kv.first, kv.second);
|
||||
}
|
||||
|
||||
// Compute and set weak ETag based on mtime+size.
|
||||
auto etag = detail::compute_etag(stat);
|
||||
if (!etag.empty()) { res.set_header("ETag", etag); }
|
||||
|
||||
@@ -8368,6 +8371,42 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
|
||||
res.set_header("Last-Modified", last_modified);
|
||||
}
|
||||
|
||||
if (check_if_not_modified(req, res, etag, mtime)) { return true; }
|
||||
|
||||
check_if_range(req, etag, mtime);
|
||||
|
||||
auto mm = std::make_shared<detail::mmap>(path.c_str());
|
||||
if (!mm->is_open()) {
|
||||
output_error_log(Error::OpenFile, &req);
|
||||
return false;
|
||||
}
|
||||
|
||||
res.set_content_provider(
|
||||
mm->size(),
|
||||
detail::find_content_type(path, file_extension_and_mimetype_map_,
|
||||
default_file_mimetype_),
|
||||
[mm](size_t offset, size_t length, DataSink &sink) -> bool {
|
||||
sink.write(mm->data() + offset, length);
|
||||
return true;
|
||||
});
|
||||
|
||||
if (req.method != "HEAD" && file_request_handler_) {
|
||||
file_request_handler_(req, res);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
output_error_log(Error::OpenFile, &req);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Server::check_if_not_modified(const Request &req, Response &res,
|
||||
const std::string &etag,
|
||||
time_t mtime) const {
|
||||
// Handle conditional GET:
|
||||
// 1. If-None-Match takes precedence (RFC 9110 Section 13.1.2)
|
||||
// 2. If-Modified-Since is checked only when If-None-Match is absent
|
||||
@@ -8404,7 +8443,11 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Server::check_if_range(Request &req, const std::string &etag,
|
||||
time_t mtime) const {
|
||||
// Handle If-Range for partial content requests (RFC 9110
|
||||
// Section 13.1.5). If-Range is only evaluated when Range header is
|
||||
// present. If the validator matches, serve partial content; otherwise
|
||||
@@ -8423,43 +8466,17 @@ inline bool Server::handle_file_request(Request &req, Response &res) {
|
||||
} else {
|
||||
// HTTP-date comparison
|
||||
auto if_range_time = detail::parse_http_date(val);
|
||||
valid = (if_range_time != static_cast<time_t>(-1) &&
|
||||
mtime <= if_range_time);
|
||||
valid =
|
||||
(if_range_time != static_cast<time_t>(-1) && mtime <= if_range_time);
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
// Validator doesn't match: ignore Range and serve full content
|
||||
req.ranges.clear();
|
||||
}
|
||||
}
|
||||
|
||||
auto mm = std::make_shared<detail::mmap>(path.c_str());
|
||||
if (!mm->is_open()) {
|
||||
output_error_log(Error::OpenFile, &req);
|
||||
return false;
|
||||
}
|
||||
|
||||
res.set_content_provider(
|
||||
mm->size(),
|
||||
detail::find_content_type(path, file_extension_and_mimetype_map_,
|
||||
default_file_mimetype_),
|
||||
[mm](size_t offset, size_t length, DataSink &sink) -> bool {
|
||||
sink.write(mm->data() + offset, length);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (req.method != "HEAD" && file_request_handler_) {
|
||||
file_request_handler_(req, res);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
output_error_log(Error::OpenFile, &req);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline socket_t
|
||||
|
||||
Reference in New Issue
Block a user