diff --git a/httplib.h b/httplib.h index b833e18b97..31d0899142 100644 --- a/httplib.h +++ b/httplib.h @@ -537,6 +537,11 @@ using Progress = std::function; struct Response; using ResponseHandler = std::function; +class Stream; +// Note: do not replace 'std::function' with StreamHandler; +// signature is not final +using StreamHandler = std::function; + 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,10 +8127,23 @@ inline bool ClientImpl::process_request(Stream &strm, Request &req, res.status != StatusCode::NotModified_304 && follow_location_; - if (req.response_handler && !redirect) { - if (!req.response_handler(res)) { - error = Error::Canceled; - return false; + 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; } }