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
37
httplib.h
37
httplib.h
@ -537,6 +537,11 @@ using Progress = std::function<bool(uint64_t current, uint64_t total)>;
|
|||||||
struct Response;
|
struct Response;
|
||||||
using ResponseHandler = std::function<bool(const Response &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 {
|
struct MultipartFormData {
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string content;
|
std::string content;
|
||||||
@ -654,6 +659,7 @@ struct Request {
|
|||||||
|
|
||||||
// for client
|
// for client
|
||||||
ResponseHandler response_handler;
|
ResponseHandler response_handler;
|
||||||
|
StreamHandler stream_handler; // EXPERIMENTAL function signature may change
|
||||||
ContentReceiverWithProgress content_receiver;
|
ContentReceiverWithProgress content_receiver;
|
||||||
Progress progress;
|
Progress progress;
|
||||||
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
|
||||||
@ -1182,6 +1188,7 @@ enum class Error {
|
|||||||
Compression,
|
Compression,
|
||||||
ConnectionTimeout,
|
ConnectionTimeout,
|
||||||
ProxyConnection,
|
ProxyConnection,
|
||||||
|
StreamHandler,
|
||||||
|
|
||||||
// For internal use only
|
// For internal use only
|
||||||
SSLPeerCouldBeClosed_,
|
SSLPeerCouldBeClosed_,
|
||||||
@ -2272,6 +2279,7 @@ inline std::string to_string(const Error error) {
|
|||||||
case Error::Compression: return "Compression failed";
|
case Error::Compression: return "Compression failed";
|
||||||
case Error::ConnectionTimeout: return "Connection timed out";
|
case Error::ConnectionTimeout: return "Connection timed out";
|
||||||
case Error::ProxyConnection: return "Proxy connection failed";
|
case Error::ProxyConnection: return "Proxy connection failed";
|
||||||
|
case Error::StreamHandler: return "Stream handler failed";
|
||||||
case Error::Unknown: return "Unknown";
|
case Error::Unknown: return "Unknown";
|
||||||
default: break;
|
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.content_receiver) {
|
||||||
if (!req.has_header("Accept-Encoding")) {
|
if (!req.stream_handler && !req.has_header("Accept-Encoding")) {
|
||||||
std::string accept_encoding;
|
std::string accept_encoding;
|
||||||
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
#ifdef CPPHTTPLIB_BROTLI_SUPPORT
|
||||||
accept_encoding = "br";
|
accept_encoding = "br";
|
||||||
@ -7885,7 +7895,7 @@ inline bool ClientImpl::write_request(Stream &strm, Request &req,
|
|||||||
req.set_header("User-Agent", agent);
|
req.set_header("User-Agent", agent);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
};
|
}
|
||||||
|
|
||||||
if (req.body.empty()) {
|
if (req.body.empty()) {
|
||||||
if (req.content_provider_) {
|
if (req.content_provider_) {
|
||||||
@ -8117,10 +8127,23 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req,
|
|||||||
res.status != StatusCode::NotModified_304 &&
|
res.status != StatusCode::NotModified_304 &&
|
||||||
follow_location_;
|
follow_location_;
|
||||||
|
|
||||||
if (req.response_handler && !redirect) {
|
if (!redirect) {
|
||||||
if (!req.response_handler(res)) {
|
if (req.response_handler) {
|
||||||
error = Error::Canceled;
|
if (!req.response_handler(res)) {
|
||||||
return false;
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user