Skip to content

Commit

Permalink
Add client stream handler
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
falbrechtskirchinger committed Feb 20, 2025
1 parent a4b2c61 commit 327d625
Showing 1 changed file with 30 additions and 7 deletions.
37 changes: 30 additions & 7 deletions httplib.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -1182,6 +1188,7 @@ enum class Error {
Compression,
ConnectionTimeout,
ProxyConnection,
StreamHandler,

// For internal use only
SSLPeerCouldBeClosed_,
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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";
Expand All @@ -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_) {
Expand Down Expand Up @@ -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;
}
}

Expand Down

0 comments on commit 327d625

Please sign in to comment.