support sse

This commit is contained in:
yangzhao 2024-07-31 19:33:14 +08:00
parent 6a848b1a16
commit ea98d12a31

138
httplib.h
View File

@ -559,6 +559,8 @@ struct Request {
const SSL *ssl = nullptr;
#endif
socket_t sock_fd;
bool has_header(const std::string &key) const;
std::string get_header_value(const std::string &key, size_t id = 0) const;
uint64_t get_header_value_u64(const std::string &key, size_t id = 0) const;
@ -728,7 +730,7 @@ private:
}
#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
OPENSSL_thread_stop ();
OPENSSL_thread_stop();
#endif
}
@ -757,7 +759,6 @@ const char *status_message(int status);
std::string get_bearer_token_auth(const Request &req);
namespace detail {
class MatcherBase {
public:
virtual ~MatcherBase() = default;
@ -1824,9 +1825,9 @@ public:
bool is_valid() const override;
SSL_CTX *ssl_context() const;
void update_certs (X509 *cert, EVP_PKEY *private_key,
X509_STORE *client_ca_cert_store = nullptr);
void update_certs(X509 *cert, EVP_PKEY *private_key,
X509_STORE *client_ca_cert_store = nullptr);
private:
bool process_and_close_socket(socket_t sock) override;
@ -2824,7 +2825,9 @@ inline bool mmap::open(const char *path) {
wpath += path[i];
}
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | \
WINAPI_PARTITION_GAMES) && \
(_WIN32_WINNT >= _WIN32_WINNT_WIN8)
hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
OPEN_EXISTING, NULL);
#else
@ -2834,7 +2837,8 @@ inline bool mmap::open(const char *path) {
if (hFile_ == INVALID_HANDLE_VALUE) { return false; }
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | \
WINAPI_PARTITION_GAMES)
LARGE_INTEGER size{};
if (!::GetFileSizeEx(hFile_, &size)) { return false; }
size_ = static_cast<size_t>(size.QuadPart);
@ -2846,13 +2850,13 @@ inline bool mmap::open(const char *path) {
size_ = (static_cast<size_t>(sizeHigh) << (sizeof(DWORD) * 8)) | sizeLow;
#endif
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && \
(_WIN32_WINNT >= _WIN32_WINNT_WIN8)
hMapping_ =
::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL);
#else
hMapping_ =
::CreateFileMappingW(hFile_, NULL, PAGE_READONLY, size.HighPart,
size.LowPart, NULL);
hMapping_ = ::CreateFileMappingW(hFile_, NULL, PAGE_READONLY, size.HighPart,
size.LowPart, NULL);
#endif
if (hMapping_ == NULL) {
@ -2860,7 +2864,8 @@ inline bool mmap::open(const char *path) {
return false;
}
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8)
#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && \
(_WIN32_WINNT >= _WIN32_WINNT_WIN8)
addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0);
#else
addr_ = ::MapViewOfFile(hMapping_, FILE_MAP_READ, 0, 0, 0);
@ -5371,6 +5376,43 @@ private:
ContentProviderWithoutLength content_provider_;
};
class SseEmitter {
private:
socket_t sockFd;
public:
long id;
string event = "message";
string data;
long retry = 3000;
SseEmitter(socket_t sockFd = 0);
socket_t getSockFD();
int send();
~SseEmitter();
};
SseEmitter::SseEmitter(socket_t sockFd) { this->sockFd = sockFd; }
socket_t SseEmitter::getSockFD() { return sockFd; }
int SseEmitter::send() {
string sendData = "id: " + std::to_string(id) + "\nevent: " + event +
"\ndata: " + data + "\nretry: " + std::to_string(retry) +
"\n\n\n";
const char *ptr = sendData.c_str();
if (!is_socket_alive(sockFd)) { return -1; }
return send_socket(sockFd, ptr, strlen(ptr), CPPHTTPLIB_SEND_FLAGS);
}
SseEmitter::~SseEmitter() {}
} // namespace detail
inline std::string hosted_at(const std::string &hostname) {
@ -6205,6 +6247,16 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
res.set_header("Accept-Ranges", "bytes");
}
if (res.has_header("Content-Type")) {
string type = res.get_header_value("Content-Type");
if (type.find("text/event-stream") != std::string::npos) {
res.headers.erase("Content-Length");
res.headers.erase("Keep-Alive");
res.set_header("Connection", "keep-alive");
res.set_header("Cache-Control", "no-cache");
}
}
if (post_routing_handler_) { post_routing_handler_(req, res); }
// Response line and headers
@ -6242,6 +6294,11 @@ inline bool Server::write_response_core(Stream &strm, bool close_connection,
// Log
if (logger_) { logger_(req, res); }
if (res.has_header("Content-Type")) {
string type = res.get_header_value("Content-Type");
if (type.find("text/event-stream") != std::string::npos) { return false; }
}
return ret;
}
@ -6787,6 +6844,7 @@ Server::process_request(Stream &strm, bool close_connection,
if (!line_reader.getline()) { return false; }
Request req;
req.sock_fd = strm.socket();
Response res;
res.version = "HTTP/1.1";
@ -6933,8 +6991,11 @@ inline bool Server::process_and_close_socket(socket_t sock) {
nullptr);
});
detail::shutdown_socket(sock);
detail::close_socket(sock);
if (ret) {
detail::shutdown_socket(sock);
detail::close_socket(sock);
}
return ret;
}
@ -8185,7 +8246,8 @@ inline Result ClientImpl::Patch(const std::string &path,
inline Result ClientImpl::Patch(const std::string &path,
const std::string &body,
const std::string &content_type, Progress progress) {
const std::string &content_type,
Progress progress) {
return Patch(path, Headers(), body, content_type, progress);
}
@ -8784,17 +8846,17 @@ inline bool SSLServer::is_valid() const { return ctx_; }
inline SSL_CTX *SSLServer::ssl_context() const { return ctx_; }
inline void SSLServer::update_certs (X509 *cert, EVP_PKEY *private_key,
X509_STORE *client_ca_cert_store) {
inline void SSLServer::update_certs(X509 *cert, EVP_PKEY *private_key,
X509_STORE *client_ca_cert_store) {
std::lock_guard<std::mutex> guard(ctx_mutex_);
std::lock_guard<std::mutex> guard(ctx_mutex_);
SSL_CTX_use_certificate (ctx_, cert);
SSL_CTX_use_PrivateKey (ctx_, private_key);
SSL_CTX_use_certificate(ctx_, cert);
SSL_CTX_use_PrivateKey(ctx_, private_key);
if (client_ca_cert_store != nullptr) {
SSL_CTX_set_cert_store (ctx_, client_ca_cert_store);
}
if (client_ca_cert_store != nullptr) {
SSL_CTX_set_cert_store(ctx_, client_ca_cert_store);
}
}
inline bool SSLServer::process_and_close_socket(socket_t sock) {
@ -9579,7 +9641,8 @@ inline Result Client::Patch(const std::string &path, const char *body,
}
inline Result Client::Patch(const std::string &path, const char *body,
size_t content_length,
const std::string &content_type, Progress progress) {
const std::string &content_type,
Progress progress) {
return cli_->Patch(path, body, content_length, content_type, progress);
}
inline Result Client::Patch(const std::string &path, const Headers &headers,
@ -9589,15 +9652,18 @@ inline Result Client::Patch(const std::string &path, const Headers &headers,
}
inline Result Client::Patch(const std::string &path, const Headers &headers,
const char *body, size_t content_length,
const std::string &content_type, Progress progress) {
return cli_->Patch(path, headers, body, content_length, content_type, progress);
const std::string &content_type,
Progress progress) {
return cli_->Patch(path, headers, body, content_length, content_type,
progress);
}
inline Result Client::Patch(const std::string &path, const std::string &body,
const std::string &content_type) {
return cli_->Patch(path, body, content_type);
}
inline Result Client::Patch(const std::string &path, const std::string &body,
const std::string &content_type, Progress progress) {
const std::string &content_type,
Progress progress) {
return cli_->Patch(path, body, content_type, progress);
}
inline Result Client::Patch(const std::string &path, const Headers &headers,
@ -9607,7 +9673,8 @@ inline Result Client::Patch(const std::string &path, const Headers &headers,
}
inline Result Client::Patch(const std::string &path, const Headers &headers,
const std::string &body,
const std::string &content_type, Progress progress) {
const std::string &content_type,
Progress progress) {
return cli_->Patch(path, headers, body, content_type, progress);
}
inline Result Client::Patch(const std::string &path, size_t content_length,
@ -9646,7 +9713,8 @@ inline Result Client::Delete(const std::string &path, const char *body,
}
inline Result Client::Delete(const std::string &path, const char *body,
size_t content_length,
const std::string &content_type, Progress progress) {
const std::string &content_type,
Progress progress) {
return cli_->Delete(path, body, content_length, content_type, progress);
}
inline Result Client::Delete(const std::string &path, const Headers &headers,
@ -9656,15 +9724,18 @@ inline Result Client::Delete(const std::string &path, const Headers &headers,
}
inline Result Client::Delete(const std::string &path, const Headers &headers,
const char *body, size_t content_length,
const std::string &content_type, Progress progress) {
return cli_->Delete(path, headers, body, content_length, content_type, progress);
const std::string &content_type,
Progress progress) {
return cli_->Delete(path, headers, body, content_length, content_type,
progress);
}
inline Result Client::Delete(const std::string &path, const std::string &body,
const std::string &content_type) {
return cli_->Delete(path, body, content_type);
}
inline Result Client::Delete(const std::string &path, const std::string &body,
const std::string &content_type, Progress progress) {
const std::string &content_type,
Progress progress) {
return cli_->Delete(path, body, content_type, progress);
}
inline Result Client::Delete(const std::string &path, const Headers &headers,
@ -9674,7 +9745,8 @@ inline Result Client::Delete(const std::string &path, const Headers &headers,
}
inline Result Client::Delete(const std::string &path, const Headers &headers,
const std::string &body,
const std::string &content_type, Progress progress) {
const std::string &content_type,
Progress progress) {
return cli_->Delete(path, headers, body, content_type, progress);
}
inline Result Client::Options(const std::string &path) {