Add server stream handler
Similarly to client stream handlers, setting a handler on the response replaces all other content-serving mechanisms. No connection-, content-, or ranges-related headers are added. This provides a minimal interface to implement a WebSocket server.
This commit is contained in:
parent
e5422a469b
commit
c8425a60fc
80
httplib.h
80
httplib.h
@ -707,6 +707,8 @@ struct Response {
|
||||
const std::string &content_type);
|
||||
void set_file_content(const std::string &path);
|
||||
|
||||
void set_stream_handler(StreamHandler stream_handler);
|
||||
|
||||
Response() = default;
|
||||
Response(const Response &) = default;
|
||||
Response &operator=(const Response &) = default;
|
||||
@ -726,6 +728,7 @@ struct Response {
|
||||
bool content_provider_success_ = false;
|
||||
std::string file_content_path_;
|
||||
std::string file_content_content_type_;
|
||||
StreamHandler stream_handler_;
|
||||
};
|
||||
|
||||
class Stream {
|
||||
@ -6002,6 +6005,10 @@ inline void Response::set_file_content(const std::string &path) {
|
||||
file_content_path_ = path;
|
||||
}
|
||||
|
||||
inline void Response::set_stream_handler(StreamHandler stream_handler) {
|
||||
stream_handler_ = std::move(stream_handler);
|
||||
}
|
||||
|
||||
// Result implementation
|
||||
inline bool Result::has_request_header(const std::string &key) const {
|
||||
return request_headers_.find(key) != request_headers_.end();
|
||||
@ -6600,31 +6607,34 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
|
||||
|
||||
std::string content_type;
|
||||
std::string boundary;
|
||||
if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); }
|
||||
if (!res.stream_handler_) {
|
||||
if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); }
|
||||
|
||||
// Prepare additional headers
|
||||
if (close_connection || req.get_header_value("Connection") == "close") {
|
||||
res.set_header("Connection", "close");
|
||||
} else {
|
||||
std::string s = "timeout=";
|
||||
s += std::to_string(keep_alive_timeout_sec_);
|
||||
s += ", max=";
|
||||
s += std::to_string(keep_alive_max_count_);
|
||||
res.set_header("Keep-Alive", s);
|
||||
}
|
||||
// Prepare additional headers
|
||||
if (close_connection || req.get_header_value("Connection") == "close") {
|
||||
res.set_header("Connection", "close");
|
||||
} else {
|
||||
std::string s = "timeout=";
|
||||
s += std::to_string(keep_alive_timeout_sec_);
|
||||
s += ", max=";
|
||||
s += std::to_string(keep_alive_max_count_);
|
||||
res.set_header("Keep-Alive", s);
|
||||
}
|
||||
|
||||
if ((!res.body.empty() || res.content_length_ > 0 || res.content_provider_) &&
|
||||
!res.has_header("Content-Type")) {
|
||||
res.set_header("Content-Type", "text/plain");
|
||||
}
|
||||
if ((!res.body.empty() || res.content_length_ > 0 ||
|
||||
res.content_provider_) &&
|
||||
!res.has_header("Content-Type")) {
|
||||
res.set_header("Content-Type", "text/plain");
|
||||
}
|
||||
|
||||
if (res.body.empty() && !res.content_length_ && !res.content_provider_ &&
|
||||
!res.has_header("Content-Length")) {
|
||||
res.set_header("Content-Length", "0");
|
||||
}
|
||||
if (res.body.empty() && !res.content_length_ && !res.content_provider_ &&
|
||||
!res.has_header("Content-Length")) {
|
||||
res.set_header("Content-Length", "0");
|
||||
}
|
||||
|
||||
if (req.method == "HEAD" && !res.has_header("Accept-Ranges")) {
|
||||
res.set_header("Accept-Ranges", "bytes");
|
||||
if (req.method == "HEAD" && !res.has_header("Accept-Ranges")) {
|
||||
res.set_header("Accept-Ranges", "bytes");
|
||||
}
|
||||
}
|
||||
|
||||
if (post_routing_handler_) { post_routing_handler_(req, res); }
|
||||
@ -6642,16 +6652,24 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
|
||||
|
||||
// Body
|
||||
auto ret = true;
|
||||
if (req.method != "HEAD") {
|
||||
if (!res.body.empty()) {
|
||||
if (!detail::write_data(strm, res.body.data(), res.body.size())) {
|
||||
ret = false;
|
||||
}
|
||||
} else if (res.content_provider_) {
|
||||
if (write_content_with_provider(strm, req, res, boundary, content_type)) {
|
||||
res.content_provider_success_ = true;
|
||||
} else {
|
||||
ret = false;
|
||||
if (res.stream_handler_) {
|
||||
// Log
|
||||
if (logger_) { logger_(req, res); }
|
||||
|
||||
return res.stream_handler_(strm);
|
||||
} else {
|
||||
if (req.method != "HEAD") {
|
||||
if (!res.body.empty()) {
|
||||
if (!detail::write_data(strm, res.body.data(), res.body.size())) {
|
||||
ret = false;
|
||||
}
|
||||
} else if (res.content_provider_) {
|
||||
if (write_content_with_provider(strm, req, res, boundary,
|
||||
content_type)) {
|
||||
res.content_provider_success_ = true;
|
||||
} else {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user