Add client stream handler
Introduce a new request callback, stream_handler. If set, it replaces all other content-serving mechanisms. The handler is not called in response to HEAD or CONNECT requests, or when following a redirect. Content-related default header fields are not added to the request. In conjunction with a response handler, it provides a minimal interface to implement a WebSocket client.
This commit is contained in:
parent
a4b2c61a65
commit
327d6256ee
31
httplib.h
31
httplib.h
@ -537,6 +537,11 @@ using Progress = std::function<bool(uint64_t current, uint64_t total)>;
|
||||
struct Response;
|
||||
using ResponseHandler = std::function<bool(const Response &response)>;
|
||||
|
||||
class Stream;
|
||||
// Note: do not replace 'std::function<bool(Stream &strm)>' with StreamHandler;
|
||||
// signature is not final
|
||||
using StreamHandler = std::function<bool(Stream &strm)>;
|
||||
|
||||
struct MultipartFormData {
|
||||
std::string name;
|
||||
std::string content;
|
||||
@ -654,6 +659,7 @@ struct Request {
|
||||
|
||||
// for client
|
||||
ResponseHandler response_handler;
|
||||
StreamHandler stream_handler; // EXPERIMENTAL function signature may change
|
||||
ContentReceiverWithProgress content_receiver;
|
||||
Progress progress;
|
||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||
@ -1182,6 +1188,7 @@ enum class Error {
|
||||
Compression,
|
||||
ConnectionTimeout,
|
||||
ProxyConnection,
|
||||
StreamHandler,
|
||||
|
||||
// For internal use only
|
||||
SSLPeerCouldBeClosed_,
|
||||
@ -2272,6 +2279,7 @@ inline std::string to_string(const Error error) {
|
||||
case Error::Compression: return "Compression failed";
|
||||
case Error::ConnectionTimeout: return "Connection timed out";
|
||||
case Error::ProxyConnection: return "Proxy connection failed";
|
||||
case Error::StreamHandler: return "Stream handler failed";
|
||||
case Error::Unknown: return "Unknown";
|
||||
default: break;
|
||||
}
|
||||
@ -7864,10 +7872,12 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
||||
}
|
||||
}
|
||||
|
||||
if (!req.has_header("Accept")) { req.set_header("Accept", "*/*"); }
|
||||
if (!req.stream_handler && !req.has_header("Accept")) {
|
||||
req.set_header("Accept", "*/*");
|
||||
}
|
||||
|
||||
if (!req.content_receiver) {
|
||||
if (!req.has_header("Accept-Encoding")) {
|
||||
if (!req.stream_handler && !req.has_header("Accept-Encoding")) {
|
||||
std::string accept_encoding;
|
||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||
accept_encoding = "br";
|
||||
@ -7885,7 +7895,7 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
||||
req.set_header("User-Agent", agent);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
if (req.body.empty()) {
|
||||
if (req.content_provider_) {
|
||||
@ -8117,13 +8127,26 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
|
||||
res.status != StatusCode::NotModified_304 &&
|
||||
follow_location_;
|
||||
|
||||
if (req.response_handler && !redirect) {
|
||||
if (!redirect) {
|
||||
if (req.response_handler) {
|
||||
if (!req.response_handler(res)) {
|
||||
error = Error::Canceled;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (req.stream_handler) {
|
||||
// Log early
|
||||
if (logger_) { logger_(req, res); }
|
||||
|
||||
if (!req.stream_handler(strm)) {
|
||||
error = Error::StreamHandler;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
auto out =
|
||||
req.content_receiver
|
||||
? static_cast<ContentReceiverWithProgress>(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user