8#ifndef CPPHTTPLIB_HTTPLIB_H
9#define CPPHTTPLIB_HTTPLIB_H
11#define CPPHTTPLIB_VERSION "0.39.0"
12#define CPPHTTPLIB_VERSION_NUM "0x002700"
15#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A00
17 "cpp-httplib doesn't support Windows 8 or lower. Please use Windows 10 or later."
25#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
26#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 5
29#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND
30#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND 10000
33#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT
34#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 100
37#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
38#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 300
41#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
42#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 0
45#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND
46#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND 5
49#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND
50#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND 0
53#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND
54#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND 5
57#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND
58#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND 0
61#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND
62#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND 300
65#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND
66#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND 0
69#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND
70#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND 5
73#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND
74#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND 0
77#ifndef CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND
78#define CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND 0
81#ifndef CPPHTTPLIB_EXPECT_100_THRESHOLD
82#define CPPHTTPLIB_EXPECT_100_THRESHOLD 1024
85#ifndef CPPHTTPLIB_EXPECT_100_TIMEOUT_MSECOND
86#define CPPHTTPLIB_EXPECT_100_TIMEOUT_MSECOND 1000
89#ifndef CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_THRESHOLD
90#define CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_THRESHOLD (1024 * 1024)
93#ifndef CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_TIMEOUT_MSECOND
94#define CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_TIMEOUT_MSECOND 50
97#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND
98#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 0
101#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND
103#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 1000
105#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0
109#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
110#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192
113#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH
114#define CPPHTTPLIB_HEADER_MAX_LENGTH 8192
117#ifndef CPPHTTPLIB_HEADER_MAX_COUNT
118#define CPPHTTPLIB_HEADER_MAX_COUNT 100
121#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT
122#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20
125#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
126#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024
129#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH
130#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (100 * 1024 * 1024)
133#ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
134#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192
137#ifndef CPPHTTPLIB_RANGE_MAX_COUNT
138#define CPPHTTPLIB_RANGE_MAX_COUNT 1024
141#ifndef CPPHTTPLIB_TCP_NODELAY
142#define CPPHTTPLIB_TCP_NODELAY false
145#ifndef CPPHTTPLIB_IPV6_V6ONLY
146#define CPPHTTPLIB_IPV6_V6ONLY false
149#ifndef CPPHTTPLIB_RECV_BUFSIZ
150#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)
153#ifndef CPPHTTPLIB_SEND_BUFSIZ
154#define CPPHTTPLIB_SEND_BUFSIZ size_t(16384u)
157#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ
158#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)
161#ifndef CPPHTTPLIB_THREAD_POOL_COUNT
162#define CPPHTTPLIB_THREAD_POOL_COUNT \
163 ((std::max)(8u, std::thread::hardware_concurrency() > 0 \
164 ? std::thread::hardware_concurrency() - 1 \
168#ifndef CPPHTTPLIB_THREAD_POOL_MAX_COUNT
169#define CPPHTTPLIB_THREAD_POOL_MAX_COUNT (CPPHTTPLIB_THREAD_POOL_COUNT * 4)
172#ifndef CPPHTTPLIB_THREAD_POOL_IDLE_TIMEOUT
173#define CPPHTTPLIB_THREAD_POOL_IDLE_TIMEOUT 3
176#ifndef CPPHTTPLIB_RECV_FLAGS
177#define CPPHTTPLIB_RECV_FLAGS 0
180#ifndef CPPHTTPLIB_SEND_FLAGS
181#define CPPHTTPLIB_SEND_FLAGS 0
184#ifndef CPPHTTPLIB_LISTEN_BACKLOG
185#define CPPHTTPLIB_LISTEN_BACKLOG 5
188#ifndef CPPHTTPLIB_MAX_LINE_LENGTH
189#define CPPHTTPLIB_MAX_LINE_LENGTH 32768
192#ifndef CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH
193#define CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH 16777216
196#ifndef CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND
197#define CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND 300
200#ifndef CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND
201#define CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND 5
204#ifndef CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND
205#define CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND 30
213#ifndef _CRT_SECURE_NO_WARNINGS
214#define _CRT_SECURE_NO_WARNINGS
217#ifndef _CRT_NONSTDC_NO_DEPRECATE
218#define _CRT_NONSTDC_NO_DEPRECATE
223#error Sorry, Visual Studio versions prior to 2015 are not supported
226#pragma comment(lib, "ws2_32.lib")
228#ifndef _SSIZE_T_DEFINED
229using ssize_t = __int64;
230#define _SSIZE_T_DEFINED
235#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)
239#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)
250#if defined(__has_include)
251#if __has_include(<afunix.h>)
254#define CPPHTTPLIB_HAVE_AFUNIX_H 1
258#ifndef WSA_FLAG_NO_HANDLE_INHERIT
259#define WSA_FLAG_NO_HANDLE_INHERIT 0x80
262using nfds_t =
unsigned long;
264using socklen_t = int;
268#include <arpa/inet.h>
269#if !defined(_AIX) && !defined(__MVS__)
275#define NI_MAXHOST 1025
280#include <netinet/in.h>
286#include <netinet/tcp.h>
290#include <sys/socket.h>
295#ifndef INVALID_SOCKET
296#define INVALID_SOCKET (-1)
300#if defined(__APPLE__)
301#include <TargetConditionals.h>
311#include <condition_variable>
331#include <system_error>
333#include <unordered_map>
334#include <unordered_set>
336#if __cplusplus >= 201703L
342#if defined(__APPLE__) && \
343 !defined(CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES) && \
344 (defined(CPPHTTPLIB_OPENSSL_SUPPORT) || \
345 defined(CPPHTTPLIB_MBEDTLS_SUPPORT) || \
346 defined(CPPHTTPLIB_WOLFSSL_SUPPORT))
347#ifndef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
348#define CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
354#if defined(_WIN32) && \
355 !defined(CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)
356#define CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
359#if defined(CPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO) || \
360 defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN)
362#include <CFNetwork/CFHost.h>
363#include <CoreFoundation/CoreFoundation.h>
367#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
375#undef X509_EXTENSIONS
376#undef PKCS7_SIGNER_INFO
379#pragma comment(lib, "crypt32.lib")
383#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
385#include <Security/Security.h>
389#include <openssl/err.h>
390#include <openssl/evp.h>
391#include <openssl/ssl.h>
392#include <openssl/x509v3.h>
394#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)
395#include <openssl/applink.c>
401#if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER)
402#if OPENSSL_VERSION_NUMBER < 0x1010107f
403#error Please use OpenSSL or a current version of BoringSSL
405#define SSL_get1_peer_certificate SSL_get_peer_certificate
406#elif OPENSSL_VERSION_NUMBER < 0x30000000L
407#error Sorry, OpenSSL versions prior to 3.0.0 are not supported
412#ifdef CPPHTTPLIB_MBEDTLS_SUPPORT
413#include <mbedtls/ctr_drbg.h>
414#include <mbedtls/entropy.h>
415#include <mbedtls/error.h>
416#include <mbedtls/md5.h>
417#include <mbedtls/net_sockets.h>
418#include <mbedtls/oid.h>
419#include <mbedtls/pk.h>
420#include <mbedtls/sha1.h>
421#include <mbedtls/sha256.h>
422#include <mbedtls/sha512.h>
423#include <mbedtls/ssl.h>
424#include <mbedtls/x509_crt.h>
428#pragma comment(lib, "crypt32.lib")
431#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
433#include <Security/Security.h>
438#if MBEDTLS_VERSION_MAJOR >= 3
439#define CPPHTTPLIB_MBEDTLS_V3
444#ifdef CPPHTTPLIB_WOLFSSL_SUPPORT
445#include <wolfssl/options.h>
447#include <wolfssl/openssl/x509v3.h>
450#ifndef WOLFSSL_GEN_EMAIL
451#define WOLFSSL_GEN_EMAIL 1
453#ifndef WOLFSSL_GEN_DNS
454#define WOLFSSL_GEN_DNS 2
456#ifndef WOLFSSL_GEN_URI
457#define WOLFSSL_GEN_URI 6
459#ifndef WOLFSSL_GEN_IPADD
460#define WOLFSSL_GEN_IPADD 7
463#include <wolfssl/ssl.h>
464#include <wolfssl/wolfcrypt/hash.h>
465#include <wolfssl/wolfcrypt/md5.h>
466#include <wolfssl/wolfcrypt/sha256.h>
467#include <wolfssl/wolfcrypt/sha512.h>
471#pragma comment(lib, "crypt32.lib")
474#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
476#include <Security/Security.h>
482#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) || \
483 defined(CPPHTTPLIB_MBEDTLS_SUPPORT) || defined(CPPHTTPLIB_WOLFSSL_SUPPORT)
484#define CPPHTTPLIB_SSL_ENABLED
487#ifdef CPPHTTPLIB_ZLIB_SUPPORT
491#ifdef CPPHTTPLIB_BROTLI_SUPPORT
492#include <brotli/decode.h>
493#include <brotli/encode.h>
496#ifdef CPPHTTPLIB_ZSTD_SUPPORT
519template <
class T,
class... Args>
520typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type
522 return std::unique_ptr<T>(
new T(std::forward<Args>(args)...));
526typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type
528 typedef typename std::remove_extent<T>::type RT;
529 return std::unique_ptr<T>(
new RT[n]);
535 const static unsigned char table[256] = {
536 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
537 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
538 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
539 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
540 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
541 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,
542 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
543 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
544 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
545 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
546 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
547 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
548 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 224, 225, 226,
549 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,
550 242, 243, 244, 245, 246, 215, 248, 249, 250, 251, 252, 253, 254, 223, 224,
551 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
552 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,
555 return table[(
unsigned char)(
char)c];
559 std::string result = s;
561 result.begin(), result.end(), result.begin(),
562 [](
unsigned char c) { return static_cast<char>(to_lower(c)); });
566inline bool equal(
const std::string &a,
const std::string &b) {
567 return a.size() == b.size() &&
568 std::equal(a.begin(), a.end(), b.begin(), [](
char ca,
char cb) {
569 return to_lower(ca) == to_lower(cb);
574 bool operator()(
const std::string &a,
const std::string &b)
const {
581 return hash_core(key.data(), key.size(), 0);
584 size_t hash_core(
const char *s,
size_t l,
size_t h)
const {
589 (((std::numeric_limits<size_t>::max)() >> 6) &
591 static_cast<unsigned char>(
to_lower(*s)));
606 : exit_function(std::move(f)), execute_on_destruction{true} {}
609 : exit_function(std::move(rhs.exit_function)),
610 execute_on_destruction{rhs.execute_on_destruction} {
615 if (execute_on_destruction) { this->exit_function(); }
618 void release() { this->execute_on_destruction =
false; }
625 std::function<void(
void)> exit_function;
626 bool execute_on_destruction;
638 T &value,
int base = 10) {
640 const char *p = first;
641 bool negative =
false;
643 if (p != last && *p ==
'-') {
647 if (p == last) {
return {first, std::errc::invalid_argument}; }
650 for (; p != last; ++p) {
653 if (
'0' <= c && c <=
'9') {
655 }
else if (
'a' <= c && c <=
'z') {
656 digit = c -
'a' + 10;
657 }
else if (
'A' <= c && c <=
'Z') {
658 digit = c -
'A' + 10;
663 if (digit < 0 || digit >= base) {
break; }
664 if (result > ((std::numeric_limits<T>::max)() - digit) / base) {
665 return {p, std::errc::result_out_of_range};
667 result = result * base + digit;
670 if (p == first || (negative && p == first + 1)) {
671 return {first, std::errc::invalid_argument};
674 value = negative ? -result : result;
675 return {p, std::errc{}};
681 std::string s(first, last);
682 char *endptr =
nullptr;
684 value = std::strtod(s.c_str(), &endptr);
685 if (endptr == s.c_str()) {
return {first, std::errc::invalid_argument}; }
686 if (errno == ERANGE) {
687 return {first + (endptr - s.c_str()), std::errc::result_out_of_range};
689 return {first + (endptr - s.c_str()), std::errc{}};
692inline bool parse_port(
const char *s,
size_t len,
int &port) {
695 if (r.ec != std::errc{} || val < 1 || val > 65535) {
return false; }
794using Params = std::multimap<std::string, std::string>;
805#if __cplusplus >= 201703L
810template <
typename T> T
any_cast(
const any &a) {
return std::any_cast<T>(a); }
811template <
typename T> T
any_cast(any &a) {
return std::any_cast<T>(a); }
813 return std::any_cast<T>(std::move(a));
815template <
typename T>
const T *
any_cast(
const any *a)
noexcept {
816 return std::any_cast<T>(a);
818template <
typename T> T *
any_cast(
any *a)
noexcept {
819 return std::any_cast<T>(a);
826 const char *
what() const noexcept
override {
return "bad any_cast"; }
837 static const char id = 0;
843 virtual std::unique_ptr<any_storage>
clone()
const = 0;
850 std::unique_ptr<any_storage>
clone()
const override {
859 std::unique_ptr<detail::any_storage> storage_;
863 any(const
any &o) : storage_(o.storage_ ? o.storage_->clone() :
nullptr) {}
866 storage_ = o.storage_ ? o.storage_->clone() :
nullptr;
872 typename T, typename D = typename std::decay<T>::type,
873 typename std::enable_if<!std::is_same<D,
any>::value,
int>::type = 0>
874 any(T &&v) : storage_(new
detail::any_value<D>(std::forward<T>(v))) {}
877 typename T,
typename D =
typename std::decay<T>::type,
878 typename std::enable_if<!std::is_same<D, any>::value,
int>::type = 0>
884 bool has_value() const noexcept {
return storage_ !=
nullptr; }
885 void reset() noexcept { storage_.reset(); }
887 template <
typename T>
friend T *
any_cast(
any *a)
noexcept;
888 template <
typename T>
friend const T *
any_cast(
const any *a)
noexcept;
892 if (!a || !a->storage_) {
return nullptr; }
898 if (!a || !a->storage_) {
return nullptr; }
905 typename std::remove_cv<typename std::remove_reference<T>::type>::type;
907#ifndef CPPHTTPLIB_NO_EXCEPTIONS
910 if (!p) { std::abort(); }
912 return static_cast<T
>(*p);
917 typename std::remove_cv<typename std::remove_reference<T>::type>::type;
919#ifndef CPPHTTPLIB_NO_EXCEPTIONS
922 if (!p) { std::abort(); }
924 return static_cast<T
>(*p);
929 typename std::remove_cv<typename std::remove_reference<T>::type>::type;
931#ifndef CPPHTTPLIB_NO_EXCEPTIONS
934 if (!p) { std::abort(); }
936 return static_cast<T
>(std::move(*p));
966 std::string
get_field(
const std::string &key,
size_t id = 0)
const;
967 std::vector<std::string>
get_fields(
const std::string &key)
const;
968 bool has_field(
const std::string &key)
const;
973 std::vector<FormData>
get_files(
const std::string &key)
const;
974 bool has_file(
const std::string &key)
const;
995 std::function<bool(
const char *data,
size_t data_len)>
write;
1002 class data_sink_streambuf final :
public std::streambuf {
1004 explicit data_sink_streambuf(
DataSink &sink) : sink_(sink) {}
1007 std::streamsize xsputn(
const char *s, std::streamsize n)
override {
1008 if (sink_.write(s,
static_cast<size_t>(n))) {
return n; }
1016 data_sink_streambuf sb_;
1020 std::function<bool(
size_t offset,
size_t length,
DataSink &sink)>;
1023 std::function<bool(
size_t offset,
DataSink &sink)>;
1037 const std::string &filename = std::string(),
1038 const std::string &content_type = std::string()) {
1041 fdp.
filename = filename.empty() ? filepath : filename;
1044 std::ifstream f(filepath, std::ios::binary);
1045 if (!f) {
return false; }
1047 f.seekg(
static_cast<std::streamoff
>(offset));
1054 f.read(buf,
sizeof(buf));
1055 auto n =
static_cast<size_t>(f.gcount());
1056 if (n > 0) {
return sink.write(buf, n); }
1063inline std::pair<size_t, ContentProvider>
1067 std::ifstream f(filepath, std::ios::binary | std::ios::ate);
1069 size =
static_cast<size_t>(f.tellg());
1074 std::ifstream f(filepath, std::ios::binary);
1075 if (!f) {
return false; }
1076 f.seekg(
static_cast<std::streamoff
>(offset));
1077 if (!f.good()) {
return false; }
1079 while (length > 0) {
1080 auto to_read = (std::min)(
sizeof(buf), length);
1081 f.read(buf,
static_cast<std::streamsize
>(to_read));
1082 auto n =
static_cast<size_t>(f.gcount());
1083 if (n == 0) {
break; }
1084 if (!sink.write(buf, n)) {
return false; }
1089 return {size, std::move(provider)};
1093 const char *data,
size_t data_length,
size_t offset,
size_t total_length)>;
1096 std::function<bool(
const char *data,
size_t data_length)>;
1115 return reader_(std::move(receiver));
1122using Range = std::pair<ssize_t, ssize_t>;
1125#ifdef CPPHTTPLIB_SSL_ENABLED
1130using ctx_t =
void *;
1131using session_t =
void *;
1132using const_session_t =
const void *;
1133using cert_t =
void *;
1134using ca_store_t =
void *;
1143enum class SanType { DNS, IP, EMAIL, URI, OTHER };
1152struct VerifyContext {
1158 const char *error_string;
1161 std::string subject_cn()
const;
1162 std::string issuer_name()
const;
1163 bool check_hostname(
const char *hostname)
const;
1164 std::vector<SanEntry> sans()
const;
1165 bool validity(time_t ¬_before, time_t ¬_after)
const;
1166 std::string serial()
const;
1169using VerifyCallback = std::function<bool(
const VerifyContext &ctx)>;
1172enum class ErrorCode :
int {
1185 ErrorCode code = ErrorCode::Fatal;
1186 uint64_t backend_code = 0;
1190 static std::string verify_error_to_string(
long error_code);
1197 PeerCert(PeerCert &&other)
noexcept;
1198 PeerCert &operator=(PeerCert &&other)
noexcept;
1201 PeerCert(
const PeerCert &) =
delete;
1202 PeerCert &operator=(
const PeerCert &) =
delete;
1204 explicit operator bool()
const;
1205 std::string subject_cn()
const;
1206 std::string issuer_name()
const;
1207 bool check_hostname(
const char *hostname)
const;
1208 std::vector<SanEntry> sans()
const;
1209 bool validity(time_t ¬_before, time_t ¬_after)
const;
1210 std::string serial()
const;
1213 explicit PeerCert(cert_t cert);
1214 cert_t cert_ =
nullptr;
1215 friend PeerCert get_peer_cert_from_session(const_session_t session);
1219using ContextSetupCallback = std::function<bool(ctx_t ctx)>;
1254 bool has_header(
const std::string &key)
const;
1256 size_t id = 0)
const;
1258 size_t id = 0)
const;
1260 void set_header(
const std::string &key,
const std::string &val);
1266 bool has_param(
const std::string &key)
const;
1267 std::string
get_param_value(
const std::string &key,
size_t id = 0)
const;
1279 (std::chrono::steady_clock::time_point::min)();
1281#ifdef CPPHTTPLIB_SSL_ENABLED
1282 tls::const_session_t ssl =
nullptr;
1283 tls::PeerCert peer_cert()
const;
1284 std::string sni()
const;
1301 bool has_header(
const std::string &key)
const;
1303 size_t id = 0)
const;
1305 size_t id = 0)
const;
1307 void set_header(
const std::string &key,
const std::string &val);
1314 void set_content(
const char *s,
size_t n,
const std::string &content_type);
1315 void set_content(
const std::string &s,
const std::string &content_type);
1316 void set_content(std::string &&s,
const std::string &content_type);
1319 size_t length,
const std::string &content_type,
ContentProvider provider,
1331 const std::string &content_type);
1408 virtual ssize_t
read(
char *ptr,
size_t size) = 0;
1409 virtual ssize_t
write(
const char *ptr,
size_t size) = 0;
1421 ssize_t write(
const char *ptr);
1422 ssize_t write(
const std::string &s);
1435 virtual bool enqueue(std::function<
void()> fn) = 0;
1443 explicit ThreadPool(
size_t n,
size_t max_n = 0,
size_t mqr = 0);
1447 bool enqueue(std::function<
void()> fn)
override;
1451 void worker(
bool is_dynamic);
1452 void move_to_finished(std::thread::id
id);
1453 void cleanup_finished_threads();
1455 size_t base_thread_count_;
1456 size_t max_thread_count_;
1457 size_t max_queued_requests_;
1458 size_t idle_thread_count_;
1462 std::list<std::function<void()>> jobs_;
1463 std::vector<std::thread> threads_;
1464 std::list<std::thread> dynamic_threads_;
1465 std::vector<std::thread>
1468 std::condition_variable cond_;
1497 const std::string &
pattern()
const {
return pattern_; }
1503 std::string pattern_;
1534 static constexpr char separator =
'/';
1539 std::vector<std::string> static_fragments_;
1542 std::vector<std::string> param_names_;
1558 bool match(
Request &request)
const override;
1568bool set_socket_opt_time(
socket_t sock,
int level,
int optname, time_t sec,
1578 std::function<void(
const Request &,
Response &, std::exception_ptr ep)>;
1596 std::function<std::string(
const std::vector<std::string> &protocols)>;
1620 const std::string &mount_point = std::string());
1621 bool set_mount_point(
const std::string &mount_point,
const std::string &dir,
1625 const std::string &mime);
1629 template <
class ErrorHandlerFunc>
1631 return set_error_handler_core(
1632 std::forward<ErrorHandlerFunc>(handler),
1633 std::is_convertible<ErrorHandlerFunc, HandlerWithResponse>{});
1636 Server &set_exception_handler(ExceptionHandler handler);
1638 Server &set_pre_routing_handler(HandlerWithResponse handler);
1639 Server &set_post_routing_handler(Handler handler);
1641 Server &set_pre_request_handler(HandlerWithResponse handler);
1643 Server &set_expect_100_continue_handler(Expect100ContinueHandler handler);
1648 Server &set_address_family(
int family);
1649 Server &set_tcp_nodelay(
bool on);
1650 Server &set_ipv6_v6only(
bool on);
1655 set_header_writer(std::function<ssize_t(
Stream &,
Headers &)>
const &writer);
1657 Server &set_trusted_proxies(
const std::vector<std::string> &proxies);
1659 Server &set_keep_alive_max_count(
size_t count);
1660 Server &set_keep_alive_timeout(time_t sec);
1662 Server &set_read_timeout(time_t sec, time_t usec = 0);
1663 template <
class Rep,
class Period>
1664 Server &set_read_timeout(
const std::chrono::duration<Rep, Period> &duration);
1666 Server &set_write_timeout(time_t sec, time_t usec = 0);
1667 template <
class Rep,
class Period>
1668 Server &set_write_timeout(
const std::chrono::duration<Rep, Period> &duration);
1670 Server &set_idle_interval(time_t sec, time_t usec = 0);
1671 template <
class Rep,
class Period>
1672 Server &set_idle_interval(
const std::chrono::duration<Rep, Period> &duration);
1674 Server &set_payload_max_length(
size_t length);
1676 Server &set_websocket_ping_interval(time_t sec);
1677 template <
class Rep,
class Period>
1678 Server &set_websocket_ping_interval(
1679 const std::chrono::duration<Rep, Period> &duration);
1681 bool bind_to_port(
const std::string &host,
int port,
int socket_flags = 0);
1682 int bind_to_any_port(
const std::string &host,
int socket_flags = 0);
1683 bool listen_after_bind();
1685 bool listen(
const std::string &host,
int port,
int socket_flags = 0);
1687 bool is_running()
const;
1688 void wait_until_ready()
const;
1690 void decommission();
1696 int remote_port,
const std::string &local_addr,
1697 int local_port,
bool close_connection,
1698 bool &connection_closed,
1699 const std::function<
void(
Request &)> &setup_request,
1700 bool *websocket_upgraded =
nullptr);
1720 std::vector<std::pair<std::unique_ptr<detail::MatcherBase>,
Handler>>;
1721 using HandlersForContentReader =
1722 std::vector<std::pair<std::unique_ptr<detail::MatcherBase>,
1725 static std::unique_ptr<detail::MatcherBase>
1726 make_matcher(
const std::string &pattern);
1729 Server &set_error_handler_core(
Handler handler, std::false_type);
1731 socket_t create_server_socket(
const std::string &host,
int port,
1734 int bind_internal(
const std::string &host,
int port,
int socket_flags);
1735 bool listen_internal();
1740 const std::string &etag, time_t mtime)
const;
1741 bool check_if_range(
Request &req,
const std::string &etag,
1742 time_t mtime)
const;
1744 const Handlers &handlers)
const;
1745 bool dispatch_request_for_content_reader(
1747 const HandlersForContentReader &handlers)
const;
1749 bool parse_request_line(
const char *s,
Request &req)
const;
1751 std::string &content_type, std::string &boundary)
const;
1752 bool write_response(
Stream &strm,
bool close_connection,
Request &req,
1754 bool write_response_with_content(
Stream &strm,
bool close_connection,
1756 bool write_response_core(
Stream &strm,
bool close_connection,
1758 bool need_apply_ranges);
1759 bool write_content_with_provider(
Stream &strm,
const Request &req,
1760 Response &res,
const std::string &boundary,
1761 const std::string &content_type);
1763 bool read_content_with_content_receiver(
Stream &strm,
Request &req,
1773 virtual bool process_and_close_socket(
socket_t sock);
1776 void output_pre_compression_log(
const Request &req,
1778 void output_error_log(
const Error &err,
const Request *req)
const;
1780 std::atomic<bool> is_running_{
false};
1781 std::atomic<bool> is_decommissioned{
false};
1783 struct MountPointEntry {
1784 std::string mount_point;
1785 std::string base_dir;
1786 std::string resolved_base_dir;
1789 std::vector<MountPointEntry> base_dirs_;
1790 std::map<std::string, std::string> file_extension_and_mimetype_map_;
1791 std::string default_file_mimetype_ =
"application/octet-stream";
1792 Handler file_request_handler_;
1794 Handlers get_handlers_;
1795 Handlers post_handlers_;
1796 HandlersForContentReader post_handlers_for_content_reader_;
1797 Handlers put_handlers_;
1798 HandlersForContentReader put_handlers_for_content_reader_;
1799 Handlers patch_handlers_;
1800 HandlersForContentReader patch_handlers_for_content_reader_;
1801 Handlers delete_handlers_;
1802 HandlersForContentReader delete_handlers_for_content_reader_;
1803 Handlers options_handlers_;
1805 struct WebSocketHandlerEntry {
1806 std::unique_ptr<detail::MatcherBase> matcher;
1807 WebSocketHandler handler;
1808 SubProtocolSelector sub_protocol_selector;
1810 using WebSocketHandlers = std::vector<WebSocketHandlerEntry>;
1811 WebSocketHandlers websocket_handlers_;
1813 HandlerWithResponse error_handler_;
1814 ExceptionHandler exception_handler_;
1815 HandlerWithResponse pre_routing_handler_;
1816 Handler post_routing_handler_;
1817 HandlerWithResponse pre_request_handler_;
1818 Expect100ContinueHandler expect_100_continue_handler_;
1820 mutable std::mutex logger_mutex_;
1822 Logger pre_compression_logger_;
1825 int address_family_ = AF_UNSPEC;
1831 std::function<ssize_t(Stream &, Headers &)> header_writer_ =
1832 detail::write_headers;
1840 : res_(std::move(res)), err_(err),
1841 request_headers_(std::move(request_headers)) {}
1843 operator bool()
const {
return res_ !=
nullptr; }
1844 bool operator==(std::nullptr_t)
const {
return res_ ==
nullptr; }
1845 bool operator!=(std::nullptr_t)
const {
return res_ !=
nullptr; }
1857 bool has_request_header(
const std::string &key)
const;
1858 std::string get_request_header_value(
const std::string &key,
1859 const char *def =
"",
1860 size_t id = 0)
const;
1861 size_t get_request_header_value_u64(
const std::string &key,
size_t def = 0,
1862 size_t id = 0)
const;
1863 size_t get_request_header_value_count(
const std::string &key)
const;
1866 std::unique_ptr<Response> res_;
1870#ifdef CPPHTTPLIB_SSL_ENABLED
1874 : res_(std::move(res)), err_(err),
1875 request_headers_(std::move(request_headers)), ssl_error_(ssl_error) {}
1876 Result(std::unique_ptr<Response> &&res, Error err, Headers &&request_headers,
1877 int ssl_error, uint64_t ssl_backend_error)
1878 : res_(std::move(res)), err_(err),
1879 request_headers_(std::move(request_headers)), ssl_error_(ssl_error),
1880 ssl_backend_error_(ssl_backend_error) {}
1882 int ssl_error()
const {
return ssl_error_; }
1883 uint64_t ssl_backend_error()
const {
return ssl_backend_error_; }
1887 uint64_t ssl_backend_error_ = 0;
1890#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
1892 [[deprecated(
"Use ssl_backend_error() instead. "
1893 "This function will be removed by v1.0.0.")]]
1894 uint64_t ssl_openssl_error()
const {
1895 return ssl_backend_error_;
1914#ifdef CPPHTTPLIB_SSL_ENABLED
1916 session(other.session)
1920#ifdef CPPHTTPLIB_SSL_ENABLED
1921 other.session =
nullptr;
1926 if (
this != &other) {
1929#ifdef CPPHTTPLIB_SSL_ENABLED
1930 session = other.session;
1931 other.session =
nullptr;
1937#ifdef CPPHTTPLIB_SSL_ENABLED
1938 tls::session_t session =
nullptr;
1944struct ChunkedDecoder;
1957 ssize_t
read(
char *buf,
size_t len);
1964 return br.
read(buf, len);
1978 const std::string &client_cert_path,
1979 const std::string &client_key_path);
2000 ssize_t read(
char *buf,
size_t len);
2001 void parse_trailers_if_needed();
2010 ssize_t read_with_decompression(
char *buf,
size_t len);
2012 std::unique_ptr<ClientConnection> connection_;
2013 std::unique_ptr<Stream> socket_stream_;
2014 Stream *stream_ =
nullptr;
2017 std::unique_ptr<detail::decompressor> decompressor_;
2018 std::string decompress_buffer_;
2019 size_t decompress_offset_ = 0;
2020 size_t decompressed_bytes_read_ = 0;
2038 Result Post(
const std::string &path,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2039 Result Post(
const std::string &path,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2047 Result Post(
const std::string &path,
const Headers &headers,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2048 Result Post(
const std::string &path,
const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2060 Result Put(
const std::string &path,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2061 Result Put(
const std::string &path,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2069 Result Put(
const std::string &path,
const Headers &headers,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2070 Result Put(
const std::string &path,
const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2082 Result Patch(
const std::string &path,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2083 Result Patch(
const std::string &path,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2091 Result Patch(
const std::string &path,
const Headers &headers,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2092 Result Patch(
const std::string &path,
const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2104 Result Delete(
const std::string &path,
const char *body,
size_t content_length,
const std::string &content_type,
DownloadProgress progress =
nullptr);
2108 Result Delete(
const std::string &path,
const Headers &headers,
const char *body,
size_t content_length,
const std::string &content_type,
DownloadProgress progress =
nullptr);
2120 const Params ¶ms = {},
2122 const std::string &body = {},
2123 const std::string &content_type = {});
2125 bool send(Request &req, Response &res, Error &error);
2126 Result send(
const Request &req);
2130 std::string host()
const;
2133 size_t is_socket_open()
const;
2136 void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
2138 void set_default_headers(Headers headers);
2141 set_header_writer(std::function<ssize_t(Stream &, Headers &)>
const &writer);
2143 void set_address_family(
int family);
2144 void set_tcp_nodelay(
bool on);
2145 void set_ipv6_v6only(
bool on);
2146 void set_socket_options(SocketOptions socket_options);
2148 void set_connection_timeout(time_t sec, time_t usec = 0);
2149 template <
class Rep,
class Period>
2151 set_connection_timeout(
const std::chrono::duration<Rep, Period> &duration);
2153 void set_read_timeout(time_t sec, time_t usec = 0);
2154 template <
class Rep,
class Period>
2155 void set_read_timeout(
const std::chrono::duration<Rep, Period> &duration);
2157 void set_write_timeout(time_t sec, time_t usec = 0);
2158 template <
class Rep,
class Period>
2159 void set_write_timeout(
const std::chrono::duration<Rep, Period> &duration);
2161 void set_max_timeout(time_t msec);
2162 template <
class Rep,
class Period>
2163 void set_max_timeout(
const std::chrono::duration<Rep, Period> &duration);
2165 void set_basic_auth(
const std::string &username,
const std::string &password);
2166 void set_bearer_token_auth(
const std::string &token);
2168 void set_keep_alive(
bool on);
2169 void set_follow_location(
bool on);
2171 void set_path_encode(
bool on);
2173 void set_compress(
bool on);
2175 void set_decompress(
bool on);
2177 void set_payload_max_length(
size_t length);
2179 void set_interface(
const std::string &intf);
2181 void set_proxy(
const std::string &host,
int port);
2182 void set_proxy_basic_auth(
const std::string &username,
2183 const std::string &password);
2184 void set_proxy_bearer_token_auth(
const std::string &token);
2186 void set_logger(Logger logger);
2187 void set_error_logger(ErrorLogger error_logger);
2198#ifdef CPPHTTPLIB_SSL_ENABLED
2199 tls::session_t ssl =
nullptr;
2203 virtual bool create_and_connect_socket(Socket &socket,
Error &error);
2204 virtual bool ensure_socket_connection(Socket &socket,
Error &error);
2205 virtual bool setup_proxy_connection(
2207 std::chrono::time_point<std::chrono::steady_clock> start_time,
2217 virtual void shutdown_ssl(Socket &socket,
bool shutdown_gracefully);
2218 void shutdown_socket(Socket &socket)
const;
2219 void close_socket(Socket &socket);
2222 bool close_connection,
Error &error);
2224 bool write_content_with_provider(
Stream &strm,
const Request &req,
2225 Error &error)
const;
2230 void output_error_log(
const Error &err,
const Request *req)
const;
2307 bool skip_100_continue =
true)
const;
2308 bool write_request(
Stream &strm,
Request &req,
bool close_connection,
2309 Error &error,
bool skip_body =
false);
2311 void prepare_default_headers(
Request &r,
bool for_stream,
2312 const std::string &ct);
2314 bool create_redirect_client(
const std::string &scheme,
2316 Response &res,
const std::string &path,
2317 const std::string &location,
Error &error);
2318 template <
typename ClientType>
void setup_redirect_client(ClientType &client);
2320 bool close_connection,
Error &error);
2321 std::unique_ptr<Response> send_with_content_provider_and_receiver(
2322 Request &req,
const char *body,
size_t content_length,
2327 Result send_with_content_provider_and_receiver(
2328 const std::string &method,
const std::string &path,
2329 const Headers &headers,
const char *body,
size_t content_length,
2340 std::chrono::time_point<std::chrono::steady_clock> start_time,
2341 std::function<
bool(
Stream &strm)> callback);
2342 virtual bool is_ssl()
const;
2344 void transfer_socket_ownership_to_handle(
StreamHandle &handle);
2346#ifdef CPPHTTPLIB_SSL_ENABLED
2348 void set_digest_auth(
const std::string &username,
2349 const std::string &password);
2350 void set_proxy_digest_auth(
const std::string &username,
2351 const std::string &password);
2352 void set_ca_cert_path(
const std::string &ca_cert_file_path,
2353 const std::string &ca_cert_dir_path = std::string());
2354 void enable_server_certificate_verification(
bool enabled);
2355 void enable_server_hostname_verification(
bool enabled);
2358 std::string digest_auth_username_;
2359 std::string digest_auth_password_;
2360 std::string proxy_digest_auth_username_;
2361 std::string proxy_digest_auth_password_;
2362 std::string ca_cert_file_path_;
2363 std::string ca_cert_dir_path_;
2364 bool server_certificate_verification_ =
true;
2365 bool server_hostname_verification_ =
true;
2366 std::string ca_cert_pem_;
2367 int last_ssl_error_ = 0;
2368 uint64_t last_backend_error_ = 0;
2371#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
2373 [[deprecated(
"Use load_ca_cert_store() instead. "
2374 "This function will be removed by v1.0.0.")]]
2375 void set_ca_cert_store(X509_STORE *ca_cert_store);
2377 [[deprecated(
"Use tls::create_ca_store() instead. "
2378 "This function will be removed by v1.0.0.")]]
2379 X509_STORE *create_ca_cert_store(
const char *ca_cert, std::size_t size)
const;
2381 [[deprecated(
"Use set_server_certificate_verifier(VerifyCallback) instead. "
2382 "This function will be removed by v1.0.0.")]]
2383 virtual void set_server_certificate_verifier(
2391 explicit Client(
const std::string &scheme_host_port);
2393 explicit Client(
const std::string &scheme_host_port,
2394 const std::string &client_cert_path,
2395 const std::string &client_key_path);
2401 const std::string &client_cert_path,
2402 const std::string &client_key_path);
2426 Result Post(
const std::string &path,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2427 Result Post(
const std::string &path,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2435 Result Post(
const std::string &path,
const Headers &headers,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2436 Result Post(
const std::string &path,
const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2448 Result Put(
const std::string &path,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2449 Result Put(
const std::string &path,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2457 Result Put(
const std::string &path,
const Headers &headers,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2458 Result Put(
const std::string &path,
const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2470 Result Patch(
const std::string &path,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2471 Result Patch(
const std::string &path,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2479 Result Patch(
const std::string &path,
const Headers &headers,
const char *body,
size_t content_length,
const std::string &content_type,
UploadProgress progress =
nullptr);
2480 Result Patch(
const std::string &path,
const Headers &headers,
const std::string &body,
const std::string &content_type,
UploadProgress progress =
nullptr);
2492 Result Delete(
const std::string &path,
const char *body,
size_t content_length,
const std::string &content_type,
DownloadProgress progress =
nullptr);
2496 Result Delete(
const std::string &path,
const Headers &headers,
const char *body,
size_t content_length,
const std::string &content_type,
DownloadProgress progress =
nullptr);
2508 const std::string &path,
2509 const Params ¶ms = {},
2511 const std::string &body = {},
2512 const std::string &content_type = {});
2514 bool send(Request &req, Response &res, Error &error);
2515 Result send(
const Request &req);
2519 std::string host()
const;
2522 size_t is_socket_open()
const;
2525 void set_hostname_addr_map(std::map<std::string, std::string> addr_map);
2527 void set_default_headers(Headers headers);
2530 set_header_writer(std::function<ssize_t(Stream &, Headers &)>
const &writer);
2532 void set_address_family(
int family);
2533 void set_tcp_nodelay(
bool on);
2534 void set_socket_options(SocketOptions socket_options);
2536 void set_connection_timeout(time_t sec, time_t usec = 0);
2537 template <
class Rep,
class Period>
2539 set_connection_timeout(
const std::chrono::duration<Rep, Period> &duration);
2541 void set_read_timeout(time_t sec, time_t usec = 0);
2542 template <
class Rep,
class Period>
2543 void set_read_timeout(
const std::chrono::duration<Rep, Period> &duration);
2545 void set_write_timeout(time_t sec, time_t usec = 0);
2546 template <
class Rep,
class Period>
2547 void set_write_timeout(
const std::chrono::duration<Rep, Period> &duration);
2549 void set_max_timeout(time_t msec);
2550 template <
class Rep,
class Period>
2551 void set_max_timeout(
const std::chrono::duration<Rep, Period> &duration);
2553 void set_basic_auth(
const std::string &username,
const std::string &password);
2554 void set_bearer_token_auth(
const std::string &token);
2556 void set_keep_alive(
bool on);
2557 void set_follow_location(
bool on);
2559 void set_path_encode(
bool on);
2560 void set_url_encode(
bool on);
2562 void set_compress(
bool on);
2564 void set_decompress(
bool on);
2566 void set_payload_max_length(
size_t length);
2568 void set_interface(
const std::string &intf);
2570 void set_proxy(
const std::string &host,
int port);
2571 void set_proxy_basic_auth(
const std::string &username,
2572 const std::string &password);
2573 void set_proxy_bearer_token_auth(
const std::string &token);
2574 void set_logger(Logger logger);
2575 void set_error_logger(ErrorLogger error_logger);
2578 std::unique_ptr<ClientImpl> cli_;
2580#ifdef CPPHTTPLIB_SSL_ENABLED
2582 void set_digest_auth(
const std::string &username,
2583 const std::string &password);
2584 void set_proxy_digest_auth(
const std::string &username,
2585 const std::string &password);
2586 void enable_server_certificate_verification(
bool enabled);
2587 void enable_server_hostname_verification(
bool enabled);
2588 void set_ca_cert_path(
const std::string &ca_cert_file_path,
2589 const std::string &ca_cert_dir_path = std::string());
2591 void set_ca_cert_store(tls::ca_store_t ca_cert_store);
2592 void load_ca_cert_store(
const char *ca_cert, std::size_t size);
2594 void set_server_certificate_verifier(tls::VerifyCallback verifier);
2596 void set_session_verifier(
2599 tls::ctx_t tls_context()
const;
2601#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
2602 void enable_windows_certificate_verification(
bool enabled);
2606 bool is_ssl_ =
false;
2609#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
2611 [[deprecated(
"Use tls_context() instead. "
2612 "This function will be removed by v1.0.0.")]]
2613 SSL_CTX *ssl_context()
const;
2615 [[deprecated(
"Use set_session_verifier(session_t) instead. "
2616 "This function will be removed by v1.0.0.")]]
2617 void set_server_certificate_verifier(
2620 [[deprecated(
"Use Result::ssl_backend_error() instead. "
2621 "This function will be removed by v1.0.0.")]]
2622 long get_verify_result()
const;
2626#ifdef CPPHTTPLIB_SSL_ENABLED
2627class SSLServer :
public Server {
2629 SSLServer(
const char *cert_path,
const char *private_key_path,
2630 const char *client_ca_cert_file_path =
nullptr,
2631 const char *client_ca_cert_dir_path =
nullptr,
2632 const char *private_key_password =
nullptr);
2635 const char *cert_pem;
2636 size_t cert_pem_len;
2637 const char *key_pem;
2639 const char *client_ca_pem;
2640 size_t client_ca_pem_len;
2641 const char *private_key_password;
2643 explicit SSLServer(
const PemMemory &pem);
2648 explicit SSLServer(
const tls::ContextSetupCallback &setup_callback);
2650 ~SSLServer()
override;
2652 bool is_valid()
const override;
2654 bool update_certs_pem(
const char *cert_pem,
const char *key_pem,
2655 const char *client_ca_pem =
nullptr,
2656 const char *password =
nullptr);
2658 tls::ctx_t tls_context()
const {
return ctx_; }
2660 int ssl_last_error()
const {
return last_ssl_error_; }
2663 bool process_and_close_socket(
socket_t sock)
override;
2665 tls::ctx_t ctx_ =
nullptr;
2666 std::mutex ctx_mutex_;
2668 int last_ssl_error_ = 0;
2670#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
2672 [[deprecated(
"Use SSLServer(PemMemory) or "
2673 "SSLServer(ContextSetupCallback) instead. "
2674 "This constructor will be removed by v1.0.0.")]]
2675 SSLServer(X509 *cert, EVP_PKEY *private_key,
2676 X509_STORE *client_ca_cert_store =
nullptr);
2678 [[deprecated(
"Use SSLServer(ContextSetupCallback) instead. "
2679 "This constructor will be removed by v1.0.0.")]]
2681 const std::function<
bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback);
2683 [[deprecated(
"Use tls_context() instead. "
2684 "This function will be removed by v1.0.0.")]]
2685 SSL_CTX *ssl_context()
const;
2687 [[deprecated(
"Use update_certs_pem() instead. "
2688 "This function will be removed by v1.0.0.")]]
2689 void update_certs(X509 *cert, EVP_PKEY *private_key,
2690 X509_STORE *client_ca_cert_store =
nullptr);
2694class SSLClient final :
public ClientImpl {
2696 explicit SSLClient(
const std::string &host);
2698 explicit SSLClient(
const std::string &host,
int port);
2700 explicit SSLClient(
const std::string &host,
int port,
2701 const std::string &client_cert_path,
2702 const std::string &client_key_path,
2703 const std::string &private_key_password = std::string());
2706 const char *cert_pem;
2707 size_t cert_pem_len;
2708 const char *key_pem;
2710 const char *private_key_password;
2712 explicit SSLClient(
const std::string &host,
int port,
const PemMemory &pem);
2714 ~SSLClient()
override;
2716 bool is_valid()
const override;
2718 void set_ca_cert_store(tls::ca_store_t ca_cert_store);
2719 void load_ca_cert_store(
const char *ca_cert, std::size_t size);
2721 void set_server_certificate_verifier(tls::VerifyCallback verifier);
2724 void set_session_verifier(
2727 tls::ctx_t tls_context()
const {
return ctx_; }
2729#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
2730 void enable_windows_certificate_verification(
bool enabled);
2734 bool create_and_connect_socket(Socket &socket, Error &error)
override;
2735 bool ensure_socket_connection(Socket &socket, Error &error)
override;
2736 void shutdown_ssl(Socket &socket,
bool shutdown_gracefully)
override;
2737 void shutdown_ssl_impl(Socket &socket,
bool shutdown_gracefully);
2740 process_socket(
const Socket &socket,
2741 std::chrono::time_point<std::chrono::steady_clock> start_time,
2742 std::function<
bool(Stream &strm)> callback)
override;
2743 bool is_ssl()
const override;
2745 bool setup_proxy_connection(
2747 std::chrono::time_point<std::chrono::steady_clock> start_time,
2748 Response &res,
bool &success, Error &error)
override;
2749 bool connect_with_proxy(
2751 std::chrono::time_point<std::chrono::steady_clock> start_time,
2752 Response &res,
bool &success, Error &error);
2753 bool initialize_ssl(Socket &socket, Error &error);
2757 tls::ctx_t ctx_ =
nullptr;
2758 std::mutex ctx_mutex_;
2759 std::once_flag initialize_cert_;
2761 long verify_result_ = 0;
2765#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
2766 bool enable_windows_cert_verification_ =
true;
2769 friend class ClientImpl;
2771#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
2773 [[deprecated(
"Use SSLClient(host, port, PemMemory) instead. "
2774 "This constructor will be removed by v1.0.0.")]]
2775 explicit SSLClient(
const std::string &host,
int port, X509 *client_cert,
2776 EVP_PKEY *client_key,
2777 const std::string &private_key_password = std::string());
2779 [[deprecated(
"Use Result::ssl_backend_error() instead. "
2780 "This function will be removed by v1.0.0.")]]
2781 long get_verify_result()
const;
2783 [[deprecated(
"Use tls_context() instead. "
2784 "This function will be removed by v1.0.0.")]]
2785 SSL_CTX *ssl_context()
const;
2787 [[deprecated(
"Use set_session_verifier(session_t) instead. "
2788 "This function will be removed by v1.0.0.")]]
2789 void set_server_certificate_verifier(
2793 bool verify_host(X509 *server_cert)
const;
2794 bool verify_host_with_subject_alt_name(X509 *server_cert)
const;
2795 bool verify_host_with_common_name(X509 *server_cert)
const;
2802template <
typename T,
typename U>
2804 auto sec = std::chrono::duration_cast<std::chrono::seconds>(duration).count();
2805 auto usec = std::chrono::duration_cast<std::chrono::microseconds>(
2806 duration - std::chrono::seconds(sec))
2808 callback(
static_cast<time_t
>(sec),
static_cast<time_t
>(usec));
2811template <
size_t N>
inline constexpr size_t str_len(
const char (&)[N]) {
2816 return !str.empty() &&
2817 std::all_of(str.cbegin(), str.cend(),
2818 [](
unsigned char c) { return std::isdigit(c); });
2822 const std::string &key,
size_t def,
2823 size_t id,
bool &is_invalid_value) {
2824 is_invalid_value =
false;
2825 auto rng = headers.equal_range(key);
2826 auto it = rng.first;
2827 std::advance(it,
static_cast<ssize_t
>(
id));
2828 if (it != rng.second) {
2830 return static_cast<size_t>(std::strtoull(it->second.data(),
nullptr, 10));
2832 is_invalid_value =
true;
2839 const std::string &key,
size_t def,
2847template <
class Rep,
class Period>
2855template <
class Rep,
class Period>
2863template <
class Rep,
class Period>
2871template <
class Rep,
class Period>
2873 const std::chrono::duration<Rep, Period> &duration) {
2879template <
class Rep,
class Period>
2881 const std::chrono::duration<Rep, Period> &duration) {
2886template <
class Rep,
class Period>
2888 const std::chrono::duration<Rep, Period> &duration) {
2893template <
class Rep,
class Period>
2895 const std::chrono::duration<Rep, Period> &duration) {
2897 std::chrono::duration_cast<std::chrono::milliseconds>(duration).count();
2901template <
class Rep,
class Period>
2903 const std::chrono::duration<Rep, Period> &duration) {
2904 cli_->set_connection_timeout(duration);
2907template <
class Rep,
class Period>
2910 cli_->set_read_timeout(duration);
2913template <
class Rep,
class Period>
2916 cli_->set_write_timeout(duration);
2920 cli_->set_max_timeout(msec);
2923template <
class Rep,
class Period>
2926 cli_->set_max_timeout(duration);
2934std::string
hosted_at(
const std::string &hostname);
2936void hosted_at(
const std::string &hostname, std::vector<std::string> &addrs);
2940std::string
encode_uri(
const std::string &value);
2942std::string
decode_uri(
const std::string &value);
2948 bool space_as_plus =
true);
2950 bool plus_as_space =
true);
2958std::pair<std::string, std::string>
2960 const std::string &password,
2961 bool is_proxy =
false);
2966inline std::wstring u8string_to_wstring(
const char *s) {
2967 if (!s) {
return std::wstring(); }
2969 auto len =
static_cast<int>(strlen(s));
2970 if (!len) {
return std::wstring(); }
2972 auto wlen = ::MultiByteToWideChar(CP_UTF8, 0, s, len,
nullptr, 0);
2973 if (!wlen) {
return std::wstring(); }
2977 wlen = ::MultiByteToWideChar(
2979 const_cast<LPWSTR
>(
reinterpret_cast<LPCWSTR
>(ws.data())), wlen);
2980 if (wlen !=
static_cast<int>(ws.size())) { ws.clear(); }
2989 time_t
mtime()
const;
2990 size_t size()
const;
3004std::string
trim_copy(
const std::string &s);
3007 const char *data, std::size_t size,
char d,
3008 std::function<
void(
const char *, std::size_t,
const char *, std::size_t)>
3012 const std::string &str,
char d,
3013 std::function<
void(
const char *, std::size_t,
const char *, std::size_t)>
3016void split(
const char *b,
const char *e,
char d,
3017 std::function<
void(
const char *,
const char *)> fn);
3019void split(
const char *b,
const char *e,
char d,
size_t m,
3020 std::function<
void(
const char *,
const char *)> fn);
3023 socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
3024 time_t write_timeout_sec, time_t write_timeout_usec,
3025 time_t max_timeout_msec,
3026 std::chrono::time_point<std::chrono::steady_clock> start_time,
3027 std::function<
bool(
Stream &)> callback);
3030 int port,
int address_family,
bool tcp_nodelay,
3032 time_t connection_timeout_sec,
3033 time_t connection_timeout_usec,
3034 time_t read_timeout_sec, time_t read_timeout_usec,
3035 time_t write_timeout_sec,
3036 time_t write_timeout_usec,
3037 const std::string &intf,
Error &error);
3040 const char *def,
size_t id);
3049 std::string &boundary);
3054 std::vector<std::string> &content_types);
3074 ssize_t
read(
char *ptr,
size_t size)
override;
3075 ssize_t
write(
const char *ptr,
size_t size)
override;
3085 size_t position = 0;
3092 typedef std::function<bool(
const char *data,
size_t data_len)>
Callback;
3093 virtual bool compress(
const char *data,
size_t data_length,
bool last,
3103 typedef std::function<bool(
const char *data,
size_t data_len)>
Callback;
3112 bool compress(
const char *data,
size_t data_length,
bool ,
3116#ifdef CPPHTTPLIB_ZLIB_SUPPORT
3117class gzip_compressor final :
public compressor {
3120 ~gzip_compressor()
override;
3122 bool compress(
const char *data,
size_t data_length,
bool last,
3123 Callback callback)
override;
3126 bool is_valid_ =
false;
3130class gzip_decompressor final :
public decompressor {
3132 gzip_decompressor();
3133 ~gzip_decompressor()
override;
3135 bool is_valid()
const override;
3137 bool decompress(
const char *data,
size_t data_length,
3138 Callback callback)
override;
3141 bool is_valid_ =
false;
3146#ifdef CPPHTTPLIB_BROTLI_SUPPORT
3147class brotli_compressor final :
public compressor {
3149 brotli_compressor();
3150 ~brotli_compressor();
3152 bool compress(
const char *data,
size_t data_length,
bool last,
3153 Callback callback)
override;
3156 BrotliEncoderState *state_ =
nullptr;
3159class brotli_decompressor final :
public decompressor {
3161 brotli_decompressor();
3162 ~brotli_decompressor();
3164 bool is_valid()
const override;
3166 bool decompress(
const char *data,
size_t data_length,
3167 Callback callback)
override;
3170 BrotliDecoderResult decoder_r;
3171 BrotliDecoderState *decoder_s =
nullptr;
3175#ifdef CPPHTTPLIB_ZSTD_SUPPORT
3176class zstd_compressor :
public compressor {
3181 bool compress(
const char *data,
size_t data_length,
bool last,
3182 Callback callback)
override;
3185 ZSTD_CCtx *ctx_ =
nullptr;
3188class zstd_decompressor :
public decompressor {
3190 zstd_decompressor();
3191 ~zstd_decompressor();
3193 bool is_valid()
const override;
3195 bool decompress(
const char *data,
size_t data_length,
3196 Callback callback)
override;
3199 ZSTD_DCtx *ctx_ =
nullptr;
3208 size_t fixed_buffer_size);
3209 const char *
ptr()
const;
3210 size_t size()
const;
3215 void append(
char c);
3218 char *fixed_buffer_;
3219 const size_t fixed_buffer_size_;
3220 size_t fixed_buffer_used_size_ = 0;
3221 std::string growable_buffer_;
3237 ssize_t
read_payload(
char *buf,
size_t len,
size_t &out_chunk_offset,
3238 size_t &out_chunk_total);
3245 mmap(
const char *path);
3248 bool open(
const char *path);
3252 size_t size()
const;
3253 const char *
data()
const;
3257 HANDLE hFile_ = NULL;
3258 HANDLE hMapping_ = NULL;
3263 void *addr_ =
nullptr;
3264 bool is_open_empty_file =
false;
3271bool is_token(
const std::string &s);
3286#ifdef CPPHTTPLIB_SSL_ENABLED
3288#ifdef CPPHTTPLIB_MBEDTLS_SUPPORT
3295struct MbedTlsContext {
3296 mbedtls_ssl_config
conf;
3297 mbedtls_entropy_context entropy;
3298 mbedtls_ctr_drbg_context ctr_drbg;
3299 mbedtls_x509_crt ca_chain;
3300 mbedtls_x509_crt own_cert;
3301 mbedtls_pk_context own_key;
3302 bool is_server =
false;
3303 bool verify_client =
false;
3304 bool has_verify_callback =
false;
3309 MbedTlsContext(
const MbedTlsContext &) =
delete;
3310 MbedTlsContext &operator=(
const MbedTlsContext &) =
delete;
3317#ifdef CPPHTTPLIB_WOLFSSL_SUPPORT
3324struct WolfSSLContext {
3325 WOLFSSL_CTX *ctx =
nullptr;
3326 bool is_server =
false;
3327 bool verify_client =
false;
3328 bool has_verify_callback =
false;
3329 std::string ca_pem_data_;
3334 WolfSSLContext(
const WolfSSLContext &) =
delete;
3335 WolfSSLContext &operator=(
const WolfSSLContext &) =
delete;
3339struct WolfSSLCAStore {
3340 std::string pem_data;
3362 explicit operator bool()
const;
3366 const char *def =
"")
const;
3367 bool has_header(
const std::string &key)
const;
3374 const char *
data()
const;
3375 size_t size()
const;
3380 std::string buffer_;
3381 size_t current_size_ = 0;
3383 bool finished_ =
false;
3387template <
typename ClientType>
3389 size_t chunk_size = 8192) {
3390 return Result{cli.open_stream(
"GET", path), chunk_size};
3393template <
typename ClientType>
3395 const Headers &headers,
size_t chunk_size = 8192) {
3396 return Result{cli.open_stream(
"GET", path, {}, headers), chunk_size};
3399template <
typename ClientType>
3401 const Params ¶ms,
size_t chunk_size = 8192) {
3402 return Result{cli.open_stream(
"GET", path, params), chunk_size};
3405template <
typename ClientType>
3408 size_t chunk_size = 8192) {
3409 return Result{cli.open_stream(
"GET", path, params, headers), chunk_size};
3413template <
typename ClientType>
3415 const std::string &body,
const std::string &content_type,
3416 size_t chunk_size = 8192) {
3417 return Result{cli.open_stream(
"POST", path, {}, {}, body, content_type),
3421template <
typename ClientType>
3423 const Headers &headers,
const std::string &body,
3424 const std::string &content_type,
size_t chunk_size = 8192) {
3425 return Result{cli.open_stream(
"POST", path, {}, headers, body, content_type),
3429template <
typename ClientType>
3431 const Params ¶ms,
const std::string &body,
3432 const std::string &content_type,
size_t chunk_size = 8192) {
3433 return Result{cli.open_stream(
"POST", path, params, {}, body, content_type),
3437template <
typename ClientType>
3440 const std::string &body,
const std::string &content_type,
3441 size_t chunk_size = 8192) {
3443 cli.open_stream(
"POST", path, params, headers, body, content_type),
3448template <
typename ClientType>
3450 const std::string &body,
const std::string &content_type,
3451 size_t chunk_size = 8192) {
3452 return Result{cli.open_stream(
"PUT", path, {}, {}, body, content_type),
3456template <
typename ClientType>
3458 const Headers &headers,
const std::string &body,
3459 const std::string &content_type,
size_t chunk_size = 8192) {
3460 return Result{cli.open_stream(
"PUT", path, {}, headers, body, content_type),
3464template <
typename ClientType>
3466 const Params ¶ms,
const std::string &body,
3467 const std::string &content_type,
size_t chunk_size = 8192) {
3468 return Result{cli.open_stream(
"PUT", path, params, {}, body, content_type),
3472template <
typename ClientType>
3475 const std::string &body,
const std::string &content_type,
3476 size_t chunk_size = 8192) {
3478 cli.open_stream(
"PUT", path, params, headers, body, content_type),
3483template <
typename ClientType>
3485 const std::string &body,
const std::string &content_type,
3486 size_t chunk_size = 8192) {
3487 return Result{cli.open_stream(
"PATCH", path, {}, {}, body, content_type),
3491template <
typename ClientType>
3493 const Headers &headers,
const std::string &body,
3494 const std::string &content_type,
size_t chunk_size = 8192) {
3495 return Result{cli.open_stream(
"PATCH", path, {}, headers, body, content_type),
3499template <
typename ClientType>
3501 const Params ¶ms,
const std::string &body,
3502 const std::string &content_type,
size_t chunk_size = 8192) {
3503 return Result{cli.open_stream(
"PATCH", path, params, {}, body, content_type),
3507template <
typename ClientType>
3510 const std::string &body,
const std::string &content_type,
3511 size_t chunk_size = 8192) {
3513 cli.open_stream(
"PATCH", path, params, headers, body, content_type),
3518template <
typename ClientType>
3520 size_t chunk_size = 8192) {
3521 return Result{cli.open_stream(
"DELETE", path), chunk_size};
3524template <
typename ClientType>
3526 const Headers &headers,
size_t chunk_size = 8192) {
3527 return Result{cli.open_stream(
"DELETE", path, {}, headers), chunk_size};
3530template <
typename ClientType>
3532 const std::string &body,
const std::string &content_type,
3533 size_t chunk_size = 8192) {
3534 return Result{cli.open_stream(
"DELETE", path, {}, {}, body, content_type),
3538template <
typename ClientType>
3540 const Headers &headers,
const std::string &body,
3541 const std::string &content_type,
3542 size_t chunk_size = 8192) {
3544 cli.open_stream(
"DELETE", path, {}, headers, body, content_type),
3548template <
typename ClientType>
3550 const Params ¶ms,
size_t chunk_size = 8192) {
3551 return Result{cli.open_stream(
"DELETE", path, params), chunk_size};
3554template <
typename ClientType>
3557 size_t chunk_size = 8192) {
3558 return Result{cli.open_stream(
"DELETE", path, params, headers), chunk_size};
3561template <
typename ClientType>
3563 const Params ¶ms,
const std::string &body,
3564 const std::string &content_type,
3565 size_t chunk_size = 8192) {
3566 return Result{cli.open_stream(
"DELETE", path, params, {}, body, content_type),
3570template <
typename ClientType>
3573 const std::string &body,
const std::string &content_type,
3574 size_t chunk_size = 8192) {
3576 cli.open_stream(
"DELETE", path, params, headers, body, content_type),
3581template <
typename ClientType>
3583 size_t chunk_size = 8192) {
3584 return Result{cli.open_stream(
"HEAD", path), chunk_size};
3587template <
typename ClientType>
3589 const Headers &headers,
size_t chunk_size = 8192) {
3590 return Result{cli.open_stream(
"HEAD", path, {}, headers), chunk_size};
3593template <
typename ClientType>
3595 const Params ¶ms,
size_t chunk_size = 8192) {
3596 return Result{cli.open_stream(
"HEAD", path, params), chunk_size};
3599template <
typename ClientType>
3602 size_t chunk_size = 8192) {
3603 return Result{cli.open_stream(
"HEAD", path, params, headers), chunk_size};
3607template <
typename ClientType>
3609 size_t chunk_size = 8192) {
3610 return Result{cli.open_stream(
"OPTIONS", path), chunk_size};
3613template <
typename ClientType>
3615 const Headers &headers,
size_t chunk_size = 8192) {
3616 return Result{cli.open_stream(
"OPTIONS", path, {}, headers), chunk_size};
3619template <
typename ClientType>
3621 const Params ¶ms,
size_t chunk_size = 8192) {
3622 return Result{cli.open_stream(
"OPTIONS", path, params), chunk_size};
3625template <
typename ClientType>
3628 size_t chunk_size = 8192) {
3629 return Result{cli.open_stream(
"OPTIONS", path, params, headers), chunk_size};
3683 bool parse_sse_line(
const std::string &line,
SSEMessage &msg,
int &retry_ms);
3684 void run_event_loop();
3686 bool should_reconnect(
int count)
const;
3687 void wait_for_reconnect();
3693 mutable std::mutex headers_mutex_;
3697 std::map<std::string, MessageHandler> event_handlers_;
3702 int reconnect_interval_ms_ = 3000;
3703 int max_reconnect_attempts_ = 0;
3706 std::atomic<bool> running_{
false};
3707 std::atomic<bool> connected_{
false};
3708 std::string last_event_id_;
3711 std::thread async_thread_;
3750 bool send(
const std::string &data);
3751 bool send(
const char *data,
size_t len);
3753 const std::string &reason =
"");
3764 : strm_(strm), req_(req), is_server_(is_server),
3765 ping_interval_sec_(ping_interval_sec) {
3770 std::unique_ptr<Stream> &&owned_strm,
const Request &req,
bool is_server,
3772 : strm_(*owned_strm), owned_strm_(std::move(owned_strm)), req_(req),
3773 is_server_(is_server), ping_interval_sec_(ping_interval_sec) {
3777 void start_heartbeat();
3778 bool send_frame(Opcode op,
const char *data,
size_t len,
bool fin =
true);
3781 std::unique_ptr<Stream> owned_strm_;
3784 time_t ping_interval_sec_;
3785 std::atomic<bool> closed_{
false};
3786 std::mutex write_mutex_;
3787 std::thread ping_thread_;
3788 std::mutex ping_mutex_;
3789 std::condition_variable ping_cv_;
3805 bool send(
const std::string &data);
3806 bool send(
const char *data,
size_t len);
3808 const std::string &reason =
"");
3821#ifdef CPPHTTPLIB_SSL_ENABLED
3822 void set_ca_cert_path(
const std::string &path);
3823 void set_ca_cert_store(tls::ca_store_t store);
3824 void enable_server_certificate_verification(
bool enabled);
3828 void shutdown_and_close();
3829 bool create_stream(std::unique_ptr<Stream> &strm);
3835 std::string subprotocol_;
3836 bool is_valid_ =
false;
3838 std::unique_ptr<WebSocket> ws_;
3840 time_t read_timeout_usec_ = 0;
3843 time_t websocket_ping_interval_sec_ =
3845 int address_family_ = AF_UNSPEC;
3851 std::string interface_;
3853#ifdef CPPHTTPLIB_SSL_ENABLED
3854 bool is_ssl_ =
false;
3855 tls::ctx_t tls_ctx_ =
nullptr;
3856 tls::session_t tls_session_ =
nullptr;
3857 std::string ca_cert_file_path_;
3858 tls::ca_store_t ca_cert_store_ =
nullptr;
3859 bool server_certificate_verification_ =
true;
3868 bool &fin,
bool expect_masked,
size_t max_len);
3886 : handle_(std::move(handle)), chunk_size_(chunk_size) {}
3889 : handle_(std::move(other.handle_)), buffer_(std::move(other.buffer_)),
3890 current_size_(other.current_size_), chunk_size_(other.chunk_size_),
3891 finished_(other.finished_) {
3892 other.current_size_ = 0;
3893 other.finished_ =
true;
3897 if (
this != &other) {
3898 handle_ = std::move(other.handle_);
3899 buffer_ = std::move(other.buffer_);
3900 current_size_ = other.current_size_;
3901 chunk_size_ = other.chunk_size_;
3902 finished_ = other.finished_;
3903 other.current_size_ = 0;
3904 other.finished_ =
true;
3910inline Result::operator bool()
const {
return is_valid(); }
3913 return handle_.response ? handle_.response->status : -1;
3917 static const Headers empty_headers;
3918 return handle_.response ? handle_.response->headers : empty_headers;
3922 const char *def)
const {
3923 return handle_.response ? handle_.response->get_header_value(key, def) : def;
3927 return handle_.response ? handle_.response->has_header(key) :
false;
3935 if (!handle_.is_valid() || finished_) {
return false; }
3937 if (buffer_.size() < chunk_size_) { buffer_.resize(chunk_size_); }
3939 ssize_t n = handle_.read(&buffer_[0], chunk_size_);
3941 current_size_ =
static_cast<size_t>(n);
3976 : client_(client), path_(path) {}
3980 : client_(client), path_(path), headers_(headers) {}
3985 on_message_ = std::move(handler);
3991 event_handlers_[type] = std::move(handler);
3996 on_open_ = std::move(handler);
4001 on_error_ = std::move(handler);
4006 reconnect_interval_ms_ = ms;
4011 max_reconnect_attempts_ = n;
4016 std::lock_guard<std::mutex> lock(headers_mutex_);
4024 return last_event_id_;
4028 running_.store(
true);
4033 running_.store(
true);
4034 async_thread_ = std::thread([
this]() { run_event_loop(); });
4038 running_.store(
false);
4040 if (async_thread_.joinable()) { async_thread_.join(); }
4043inline bool SSEClient::parse_sse_line(
const std::string &line,
SSEMessage &msg,
4046 if (line.empty() || line ==
"\r") {
return true; }
4049 if (!line.empty() && line[0] ==
':') {
return false; }
4052 auto colon_pos = line.find(
':');
4053 if (colon_pos == std::string::npos) {
4058 auto field = line.substr(0, colon_pos);
4062 if (colon_pos + 1 < line.size()) {
4063 auto value_start = colon_pos + 1;
4064 if (line[value_start] ==
' ') { value_start++; }
4065 value = line.substr(value_start);
4067 if (!value.empty() && value.back() ==
'\r') { value.pop_back(); }
4071 if (field ==
"event") {
4073 }
else if (field ==
"data") {
4075 if (!msg.
data.empty()) { msg.
data +=
"\n"; }
4077 }
else if (field ==
"id") {
4080 }
else if (field ==
"retry") {
4086 if (res.ec == std::errc{}) { retry_ms = v; }
4094inline void SSEClient::run_event_loop() {
4095 auto reconnect_count = 0;
4097 while (running_.load()) {
4101 std::lock_guard<std::mutex> lock(headers_mutex_);
4102 request_headers = headers_;
4104 if (!last_event_id_.empty()) {
4105 request_headers.emplace(
"Last-Event-ID", last_event_id_);
4109 auto result =
stream::Get(client_, path_, request_headers);
4113 connected_.store(
false);
4114 if (on_error_) { on_error_(result.error()); }
4116 if (!should_reconnect(reconnect_count)) {
break; }
4117 wait_for_reconnect();
4123 connected_.store(
false);
4135 if (!should_reconnect(reconnect_count)) {
break; }
4136 wait_for_reconnect();
4142 connected_.store(
true);
4143 reconnect_count = 0;
4144 if (on_open_) { on_open_(); }
4148 SSEMessage current_msg;
4150 while (running_.load() && result.next()) {
4151 buffer.append(result.data(), result.size());
4154 size_t line_start = 0;
4157 while ((newline_pos = buffer.find(
'\n', line_start)) !=
4158 std::string::npos) {
4159 auto line = buffer.substr(line_start, newline_pos - line_start);
4160 line_start = newline_pos + 1;
4163 auto event_complete =
4164 parse_sse_line(line, current_msg, reconnect_interval_ms_);
4166 if (event_complete && !current_msg.data.empty()) {
4168 if (!current_msg.id.empty()) { last_event_id_ = current_msg.id; }
4171 dispatch_event(current_msg);
4173 current_msg.clear();
4178 buffer.erase(0, line_start);
4182 connected_.store(
false);
4184 if (!running_.load()) {
break; }
4187 if (result.has_read_error()) {
4188 if (on_error_) { on_error_(result.read_error()); }
4191 if (!should_reconnect(reconnect_count)) {
break; }
4192 wait_for_reconnect();
4196 connected_.store(
false);
4199inline void SSEClient::dispatch_event(
const SSEMessage &msg) {
4201 auto it = event_handlers_.find(msg.event);
4202 if (it != event_handlers_.end()) {
4208 if (on_message_) { on_message_(msg); }
4211inline bool SSEClient::should_reconnect(
int count)
const {
4212 if (!running_.load()) {
return false; }
4213 if (max_reconnect_attempts_ == 0) {
return true; }
4214 return count < max_reconnect_attempts_;
4217inline void SSEClient::wait_for_reconnect() {
4220 while (running_.load() && waited < reconnect_interval_ms_) {
4221 std::this_thread::sleep_for(std::chrono::milliseconds(100));
4228#ifdef CPPHTTPLIB_SSL_ENABLED
4236ctx_t create_client_context();
4237void free_context(ctx_t ctx);
4238bool set_min_version(ctx_t ctx, Version version);
4239bool load_ca_pem(ctx_t ctx,
const char *pem,
size_t len);
4240bool load_ca_file(ctx_t ctx,
const char *file_path);
4241bool load_ca_dir(ctx_t ctx,
const char *dir_path);
4242bool load_system_certs(ctx_t ctx);
4243bool set_client_cert_pem(ctx_t ctx,
const char *cert,
const char *key,
4244 const char *password);
4245bool set_client_cert_file(ctx_t ctx,
const char *cert_path,
4246 const char *key_path,
const char *password);
4249ctx_t create_server_context();
4250bool set_server_cert_pem(ctx_t ctx,
const char *cert,
const char *key,
4251 const char *password);
4252bool set_server_cert_file(ctx_t ctx,
const char *cert_path,
4253 const char *key_path,
const char *password);
4254bool set_client_ca_file(ctx_t ctx,
const char *ca_file,
const char *ca_dir);
4255void set_verify_client(ctx_t ctx,
bool require);
4258session_t create_session(ctx_t ctx,
socket_t sock);
4259void free_session(session_t session);
4260bool set_sni(session_t session,
const char *hostname);
4261bool set_hostname(session_t session,
const char *hostname);
4264TlsError connect(session_t session);
4265TlsError accept(session_t session);
4268bool connect_nonblocking(session_t session,
socket_t sock, time_t timeout_sec,
4269 time_t timeout_usec, TlsError *err);
4270bool accept_nonblocking(session_t session,
socket_t sock, time_t timeout_sec,
4271 time_t timeout_usec, TlsError *err);
4274ssize_t read(session_t session,
void *buf,
size_t len, TlsError &err);
4275ssize_t write(session_t session,
const void *buf,
size_t len, TlsError &err);
4276int pending(const_session_t session);
4277void shutdown(session_t session,
bool graceful);
4280bool is_peer_closed(session_t session,
socket_t sock);
4283cert_t get_peer_cert(const_session_t session);
4284void free_cert(cert_t cert);
4285bool verify_hostname(cert_t cert,
const char *hostname);
4286uint64_t hostname_mismatch_code();
4287long get_verify_result(const_session_t session);
4290std::string get_cert_subject_cn(cert_t cert);
4291std::string get_cert_issuer_name(cert_t cert);
4292bool get_cert_sans(cert_t cert, std::vector<SanEntry> &sans);
4293bool get_cert_validity(cert_t cert, time_t ¬_before, time_t ¬_after);
4294std::string get_cert_serial(cert_t cert);
4295bool get_cert_der(cert_t cert, std::vector<unsigned char> &der);
4296const char *get_sni(const_session_t session);
4299ca_store_t create_ca_store(
const char *pem,
size_t len);
4300void free_ca_store(ca_store_t store);
4301bool set_ca_store(ctx_t ctx, ca_store_t store);
4302size_t get_ca_certs(ctx_t ctx, std::vector<cert_t> &certs);
4303std::vector<std::string> get_ca_names(ctx_t ctx);
4306bool update_server_cert(ctx_t ctx,
const char *cert_pem,
const char *key_pem,
4307 const char *password);
4308bool update_server_client_ca(ctx_t ctx,
const char *ca_pem);
4311bool set_verify_callback(ctx_t ctx, VerifyCallback callback);
4312long get_verify_error(const_session_t session);
4313std::string verify_error_string(
long error_code);
4316uint64_t peek_error();
4317uint64_t get_error();
4318std::string error_string(uint64_t code);
4330 const void *optval, socklen_t optlen) {
4331 return setsockopt(sock, level, optname,
4333 reinterpret_cast<const char *
>(optval),
4345 time_t sec, time_t usec) {
4347 auto timeout =
static_cast<uint32_t
>(sec * 1000 + usec / 1000);
4350 timeout.tv_sec =
static_cast<long>(sec);
4351 timeout.tv_usec =
static_cast<decltype(timeout.tv_usec)
>(usec);
4360 }
else if (
'A' <= c && c <=
'F') {
4363 }
else if (
'a' <= c && c <=
'f') {
4372 if (i >= s.size()) {
return false; }
4375 for (; cnt; i++, cnt--) {
4376 if (!s[i]) {
return false; }
4388 static const auto charset =
"0123456789abcdef";
4391 ret = charset[n & 15] + ret;
4398 if (!fs.
is_file()) {
return std::string(); }
4404 auto mtime_raw = fs.
mtime();
4405 if (mtime_raw < 0) {
return std::string(); }
4407 auto mtime =
static_cast<size_t>(mtime_raw);
4408 auto size = fs.
size();
4418 if (mtime < 0) {
return std::string(); }
4422 if (gmtime_s(&tm_buf, &mtime) != 0) {
return std::string(); }
4424 if (gmtime_r(&mtime, &tm_buf) ==
nullptr) {
return std::string(); }
4427 if (strftime(buf,
sizeof(buf),
"%a, %d %b %Y %H:%M:%S GMT", &tm_buf) == 0) {
4428 return std::string();
4431 return std::string(buf);
4439 const std::locale classic_locale = std::locale::classic();
4442 auto try_parse = [&](
const char *
fmt) ->
bool {
4443 std::istringstream ss(date_str);
4444 ss.imbue(classic_locale);
4446 memset(&tm_buf, 0,
sizeof(tm_buf));
4447 ss >> std::get_time(&tm_buf,
fmt);
4453 if (!try_parse(
"%a, %d %b %Y %H:%M:%S")) {
4455 if (!try_parse(
"%A, %d-%b-%y %H:%M:%S")) {
4457 if (!try_parse(
"%a %b %d %H:%M:%S %Y")) {
4458 return static_cast<time_t
>(-1);
4464 return _mkgmtime(&tm_buf);
4466 return mktime(&tm_buf);
4468 return timegm(&tm_buf);
4474 return s.size() > 3 && s[0] ==
'W' && s[1] ==
'/' && s[2] ==
'"';
4480 return s.size() >= 2 && s[0] ==
'"' && s.back() ==
'"';
4484 if (code < 0x0080) {
4485 buff[0] =
static_cast<char>(code & 0x7F);
4487 }
else if (code < 0x0800) {
4488 buff[0] =
static_cast<char>(0xC0 | ((code >> 6) & 0x1F));
4489 buff[1] =
static_cast<char>(0x80 | (code & 0x3F));
4491 }
else if (code < 0xD800) {
4492 buff[0] =
static_cast<char>(0xE0 | ((code >> 12) & 0xF));
4493 buff[1] =
static_cast<char>(0x80 | ((code >> 6) & 0x3F));
4494 buff[2] =
static_cast<char>(0x80 | (code & 0x3F));
4496 }
else if (code < 0xE000) {
4498 }
else if (code < 0x10000) {
4499 buff[0] =
static_cast<char>(0xE0 | ((code >> 12) & 0xF));
4500 buff[1] =
static_cast<char>(0x80 | ((code >> 6) & 0x3F));
4501 buff[2] =
static_cast<char>(0x80 | (code & 0x3F));
4503 }
else if (code < 0x110000) {
4504 buff[0] =
static_cast<char>(0xF0 | ((code >> 18) & 0x7));
4505 buff[1] =
static_cast<char>(0x80 | ((code >> 12) & 0x3F));
4506 buff[2] =
static_cast<char>(0x80 | ((code >> 6) & 0x3F));
4507 buff[3] =
static_cast<char>(0x80 | (code & 0x3F));
4524 auto c =
static_cast<unsigned char>(s[i]);
4530 }
else if ((c & 0xE0) == 0xC0) {
4533 }
else if ((c & 0xF0) == 0xE0) {
4536 }
else if ((c & 0xF8) == 0xF0) {
4542 if (i + len > n) {
return false; }
4543 for (
size_t j = 1; j < len; j++) {
4544 auto b =
static_cast<unsigned char>(s[i + j]);
4545 if ((b & 0xC0) != 0x80) {
return false; }
4546 cp = (cp << 6) | (b & 0x3F);
4549 if (len == 2 && cp < 0x80) {
return false; }
4550 if (len == 3 && cp < 0x800) {
return false; }
4551 if (len == 4 && cp < 0x10000) {
return false; }
4553 if (cp >= 0xD800 && cp <= 0xDFFF) {
return false; }
4554 if (cp > 0x10FFFF) {
return false; }
4568 static const auto lookup =
4569 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4572 out.reserve(in.size());
4578 val = (val << 8) + static_cast<uint8_t>(c);
4581 out.push_back(lookup[(val >> valb) & 0x3F]);
4586 if (valb > -6) { out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); }
4588 while (out.size() % 4) {
4595inline std::string
sha1(
const std::string &input) {
4597 auto left_rotate = [](uint32_t x, uint32_t n) -> uint32_t {
4598 return (x << n) | (x >> (32 - n));
4601 uint32_t h0 = 0x67452301;
4602 uint32_t h1 = 0xEFCDAB89;
4603 uint32_t h2 = 0x98BADCFE;
4604 uint32_t h3 = 0x10325476;
4605 uint32_t h4 = 0xC3D2E1F0;
4608 std::string msg = input;
4609 uint64_t original_bit_len =
static_cast<uint64_t
>(msg.size()) * 8;
4610 msg.push_back(
static_cast<char>(0x80));
4611 while (msg.size() % 64 != 56) {
4616 for (
int i = 56; i >= 0; i -= 8) {
4617 msg.push_back(
static_cast<char>((original_bit_len >> i) & 0xFF));
4621 for (
size_t offset = 0; offset < msg.size(); offset += 64) {
4624 for (
size_t i = 0; i < 16; i++) {
4626 (
static_cast<uint32_t
>(
static_cast<uint8_t
>(msg[offset + i * 4]))
4628 (
static_cast<uint32_t
>(
static_cast<uint8_t
>(msg[offset + i * 4 + 1]))
4630 (
static_cast<uint32_t
>(
static_cast<uint8_t
>(msg[offset + i * 4 + 2]))
4632 (
static_cast<uint32_t
>(
4633 static_cast<uint8_t
>(msg[offset + i * 4 + 3])));
4636 for (
int i = 16; i < 80; i++) {
4637 w[i] = left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);
4640 uint32_t a = h0, b = h1, c = h2, d = h3, e = h4;
4642 for (
int i = 0; i < 80; i++) {
4645 f = (b & c) | ((~b) & d);
4647 }
else if (i < 40) {
4650 }
else if (i < 60) {
4651 f = (b & c) | (b & d) | (c & d);
4658 uint32_t temp = left_rotate(a, 5) + f + e + k + w[i];
4661 c = left_rotate(b, 30);
4674 std::string hash(20,
'\0');
4675 for (
size_t i = 0; i < 4; i++) {
4676 hash[i] =
static_cast<char>((h0 >> (24 - i * 8)) & 0xFF);
4677 hash[4 + i] =
static_cast<char>((h1 >> (24 - i * 8)) & 0xFF);
4678 hash[8 + i] =
static_cast<char>((h2 >> (24 - i * 8)) & 0xFF);
4679 hash[12 + i] =
static_cast<char>((h3 >> (24 - i * 8)) & 0xFF);
4680 hash[16 + i] =
static_cast<char>((h4 >> (24 - i * 8)) & 0xFF);
4686 const std::string magic =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
4691 if (req.
method !=
"GET") {
return false; }
4694 auto upgrade_it = req.
headers.find(
"Upgrade");
4695 if (upgrade_it == req.
headers.end()) {
return false; }
4697 if (upgrade_val !=
"websocket") {
return false; }
4700 auto connection_it = req.
headers.find(
"Connection");
4701 if (connection_it == req.
headers.end()) {
return false; }
4703 if (connection_val.find(
"upgrade") == std::string::npos) {
return false; }
4708 if (ws_key.size() != 24 || ws_key[22] !=
'=' || ws_key[23] !=
'=') {
4711 static const std::string b64chars =
4712 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4713 for (
size_t i = 0; i < 22; i++) {
4714 if (b64chars.find(ws_key[i]) == std::string::npos) {
return false; }
4719 if (version !=
"13") {
return false; }
4725 const char *data,
size_t len,
bool fin,
4729 header[0] =
static_cast<uint8_t
>((fin ? 0x80 : 0x00) |
4730 (
static_cast<uint8_t
>(opcode) & 0x0F));
4734 header[1] =
static_cast<uint8_t
>(len);
4735 if (mask) { header[1] |= 0x80; }
4736 if (strm.
write(
reinterpret_cast<char *
>(header), 2) < 0) {
return false; }
4737 }
else if (len <= 0xFFFF) {
4739 if (mask) { header[1] |= 0x80; }
4740 if (strm.
write(
reinterpret_cast<char *
>(header), 2) < 0) {
return false; }
4742 ext[0] =
static_cast<uint8_t
>((len >> 8) & 0xFF);
4743 ext[1] =
static_cast<uint8_t
>(len & 0xFF);
4744 if (strm.
write(
reinterpret_cast<char *
>(ext), 2) < 0) {
return false; }
4747 if (mask) { header[1] |= 0x80; }
4748 if (strm.
write(
reinterpret_cast<char *
>(header), 2) < 0) {
return false; }
4750 for (
int i = 7; i >= 0; i--) {
4751 ext[7 - i] =
static_cast<uint8_t
>((len >> (i * 8)) & 0xFF);
4753 if (strm.
write(
reinterpret_cast<char *
>(ext), 8) < 0) {
return false; }
4758 thread_local std::mt19937 rng(std::random_device{}());
4759 uint8_t mask_key[4];
4761 std::memcpy(mask_key, &r, 4);
4762 if (strm.
write(
reinterpret_cast<char *
>(mask_key), 4) < 0) {
return false; }
4765 const size_t chunk_size = 4096;
4766 std::vector<char> buf((std::min)(len, chunk_size));
4767 for (
size_t offset = 0; offset < len; offset += chunk_size) {
4768 size_t n = (std::min)(chunk_size, len - offset);
4769 for (
size_t i = 0; i < n; i++) {
4771 data[offset + i] ^
static_cast<char>(mask_key[(offset + i) % 4]);
4773 if (strm.
write(buf.data(), n) < 0) {
return false; }
4777 if (strm.
write(data, len) < 0) {
return false; }
4790 std::string &payload,
bool &fin,
4791 bool expect_masked,
size_t max_len) {
4794 if (strm.
read(
reinterpret_cast<char *
>(header), 2) != 2) {
return false; }
4796 fin = (header[0] & 0x80) != 0;
4799 if (header[0] & 0x70) {
return false; }
4801 opcode =
static_cast<Opcode>(header[0] & 0x0F);
4802 bool masked = (header[1] & 0x80) != 0;
4803 uint64_t payload_len = header[1] & 0x7F;
4807 bool is_control = (
static_cast<uint8_t
>(opcode) & 0x08) != 0;
4809 if (!fin) {
return false; }
4810 if (payload_len > 125) {
return false; }
4813 if (masked != expect_masked) {
return false; }
4816 if (payload_len == 126) {
4818 if (strm.
read(
reinterpret_cast<char *
>(ext), 2) != 2) {
return false; }
4819 payload_len = (
static_cast<uint64_t
>(ext[0]) << 8) | ext[1];
4820 }
else if (payload_len == 127) {
4822 if (strm.
read(
reinterpret_cast<char *
>(ext), 8) != 8) {
return false; }
4824 if (ext[0] & 0x80) {
return false; }
4826 for (
int i = 0; i < 8; i++) {
4827 payload_len = (payload_len << 8) | ext[i];
4831 if (payload_len > max_len) {
return false; }
4834 uint8_t mask_key[4] = {0};
4836 if (strm.
read(
reinterpret_cast<char *
>(mask_key), 4) != 4) {
return false; }
4840 payload.resize(
static_cast<size_t>(payload_len));
4841 if (payload_len > 0) {
4842 size_t total_read = 0;
4843 while (total_read < payload_len) {
4844 auto n = strm.
read(&payload[total_read],
4845 static_cast<size_t>(payload_len - total_read));
4846 if (n <= 0) {
return false; }
4847 total_read +=
static_cast<size_t>(n);
4853 for (
size_t i = 0; i < payload.size(); i++) {
4854 payload[i] ^=
static_cast<char>(mask_key[i % 4]);
4871 while (i < path.size() && path[i] ==
'/') {
4875 while (i < path.size()) {
4878 while (i < path.size() && path[i] !=
'/') {
4879 if (path[i] ==
'\0') {
4881 }
else if (path[i] ==
'\\') {
4890 if (!path.compare(beg, len,
".")) {
4892 }
else if (!path.compare(beg, len,
"..")) {
4893 if (level == 0) {
return false; }
4900 while (i < path.size() && path[i] ==
'/') {
4910 char buf[_MAX_PATH];
4911 if (_fullpath(buf, path, _MAX_PATH) ==
nullptr) {
return false; }
4915 if (realpath(path, buf) ==
nullptr) {
return false; }
4922 const std::string &resolved_base) {
4924 return _strnicmp(resolved_path.c_str(), resolved_base.c_str(),
4925 resolved_base.size()) == 0;
4927 return strncmp(resolved_path.c_str(), resolved_base.c_str(),
4928 resolved_base.size()) == 0;
4934 auto wpath = u8string_to_wstring(path.c_str());
4935 ret_ = _wstat(wpath.c_str(), &st_);
4937 ret_ = stat(path.c_str(), &st_);
4941 return ret_ >= 0 && S_ISREG(st_.st_mode);
4944 return ret_ >= 0 && S_ISDIR(st_.st_mode);
4948 return ret_ >= 0 ?
static_cast<time_t
>(st_.st_mtime)
4949 :
static_cast<time_t
>(-1);
4953 return ret_ >= 0 ?
static_cast<size_t>(st_.st_size) : 0;
4958 result.reserve(s.size());
4960 for (
size_t i = 0; s[i]; i++) {
4962 case ' ': result +=
"%20";
break;
4963 case '+': result +=
"%2B";
break;
4964 case '\r': result +=
"%0D";
break;
4965 case '\n': result +=
"%0A";
break;
4966 case '\'': result +=
"%27";
break;
4967 case ',': result +=
"%2C";
break;
4969 case ';': result +=
"%3B";
break;
4971 auto c =
static_cast<uint8_t
>(s[i]);
4975 auto len = snprintf(hex,
sizeof(hex) - 1,
"%02X", c);
4977 result.append(hex,
static_cast<size_t>(len));
4990 thread_local auto re = std::regex(
"\\.([a-zA-Z0-9]+)$");
4991 if (std::regex_search(path, m, re)) {
return m[1].str(); }
4992 return std::string();
4997template <
typename T>
4998inline bool parse_header(
const char *beg,
const char *end, T fn);
5000template <
typename T>
5008 while (p < end && *p !=
':') {
5012 auto name = std::string(beg, p);
5015 if (p == end) {
return false; }
5019 if (*p++ !=
':') {
return false; }
5026 auto key_len = key_end - beg;
5027 if (!key_len) {
return false; }
5029 auto key = std::string(beg, key_end);
5030 auto val = std::string(p, end);
5064 "transfer-encoding",
5069 "proxy-authenticate",
5070 "proxy-authorization",
5093 if (trailer_header && std::strlen(trailer_header)) {
5094 auto len = std::strlen(trailer_header);
5095 split(trailer_header, trailer_header + len,
',',
5096 [&](
const char *b,
const char *e) {
5097 const char *kbeg = b;
5098 const char *kend = e;
5099 while (kbeg < kend && (*kbeg ==
' ' || *kbeg ==
'\t')) {
5102 while (kend > kbeg && (kend[-1] ==
' ' || kend[-1] ==
'\t')) {
5105 std::string key(kbeg,
static_cast<size_t>(kend - kbeg));
5107 prohibited_trailers.find(key) == prohibited_trailers.end()) {
5108 declared_trailers.insert(key);
5113 size_t trailer_header_count = 0;
5114 while (strcmp(line_reader.
ptr(),
"\r\n") != 0) {
5118 constexpr auto line_terminator_len = 2;
5119 auto line_beg = line_reader.
ptr();
5121 line_reader.
ptr() + line_reader.
size() - line_terminator_len;
5124 [&](
const std::string &key,
const std::string &val) {
5125 if (declared_trailers.find(key) !=
5126 declared_trailers.end()) {
5127 dest.emplace(key, val);
5128 trailer_header_count++;
5134 if (!line_reader.
getline()) {
return false; }
5140inline std::pair<size_t, size_t>
trim(
const char *b,
const char *e,
size_t left,
5148 return std::make_pair(left, right);
5152 auto r =
trim(s.data(), s.data() + s.size(), 0, s.size());
5153 return s.substr(r.first, r.second - r.first);
5157 if (s.length() >= 2 && s.front() ==
'"' && s.back() ==
'"') {
5158 return s.substr(1, s.size() - 2);
5164divide(
const char *data, std::size_t size,
char d,
5165 std::function<
void(
const char *, std::size_t,
const char *, std::size_t)>
5167 const auto it = std::find(data, data + size, d);
5168 const auto found =
static_cast<std::size_t
>(it != data + size);
5169 const auto lhs_data = data;
5170 const auto lhs_size =
static_cast<std::size_t
>(it - data);
5171 const auto rhs_data = it + found;
5172 const auto rhs_size = size - lhs_size - found;
5174 fn(lhs_data, lhs_size, rhs_data, rhs_size);
5179 std::function<
void(
const char *, std::size_t,
const char *, std::size_t)>
5181 divide(str.data(), str.size(), d, std::move(fn));
5184inline void split(
const char *b,
const char *e,
char d,
5185 std::function<
void(
const char *,
const char *)> fn) {
5186 return split(b, e, d, (std::numeric_limits<size_t>::max)(), std::move(fn));
5189inline void split(
const char *b,
const char *e,
char d,
size_t m,
5190 std::function<
void(
const char *,
const char *)> fn) {
5195 while (e ? (b + i < e) : (b[i] !=
'\0')) {
5196 if (b[i] == d && count < m) {
5197 auto r =
trim(b, e, beg, i);
5198 if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
5206 auto r =
trim(b, e, beg, i);
5207 if (r.first < r.second) { fn(&b[r.first], &b[r.second]); }
5211inline bool split_find(
const char *b,
const char *e,
char d,
size_t m,
5212 std::function<
bool(
const char *,
const char *)> fn) {
5217 while (e ? (b + i < e) : (b[i] !=
'\0')) {
5218 if (b[i] == d && count < m) {
5219 auto r =
trim(b, e, beg, i);
5220 if (r.first < r.second) {
5221 auto found = fn(&b[r.first], &b[r.second]);
5222 if (found) {
return true; }
5231 auto r =
trim(b, e, beg, i);
5232 if (r.first < r.second) {
5233 auto found = fn(&b[r.first], &b[r.second]);
5234 if (found) {
return true; }
5242 std::function<
bool(
const char *,
const char *)> fn) {
5243 return split_find(b, e, d, (std::numeric_limits<size_t>::max)(),
5248 size_t fixed_buffer_size)
5249 : strm_(strm), fixed_buffer_(fixed_buffer),
5250 fixed_buffer_size_(fixed_buffer_size) {}
5253 if (growable_buffer_.empty()) {
5254 return fixed_buffer_;
5256 return growable_buffer_.data();
5261 if (growable_buffer_.empty()) {
5262 return fixed_buffer_used_size_;
5264 return growable_buffer_.size();
5270 return size() >= 2 && end[-2] ==
'\r' && end[-1] ==
'\n';
5274 fixed_buffer_used_size_ = 0;
5275 growable_buffer_.clear();
5277#ifndef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
5281 for (
size_t i = 0;; i++) {
5288 auto n = strm_.read(&
byte, 1);
5292 }
else if (n == 0) {
5302#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
5303 if (
byte ==
'\n') {
break; }
5305 if (prev_byte ==
'\r' &&
byte ==
'\n') {
break; }
5313inline void stream_line_reader::append(
char c) {
5314 if (fixed_buffer_used_size_ < fixed_buffer_size_ - 1) {
5315 fixed_buffer_[fixed_buffer_used_size_++] = c;
5316 fixed_buffer_[fixed_buffer_used_size_] =
'\0';
5318 if (growable_buffer_.empty()) {
5319 assert(fixed_buffer_[fixed_buffer_used_size_] ==
'\0');
5320 growable_buffer_.assign(fixed_buffer_, fixed_buffer_used_size_);
5322 growable_buffer_ += c;
5334 auto wpath = u8string_to_wstring(path);
5335 if (wpath.empty()) {
return false; }
5337 hFile_ = ::CreateFile2(wpath.c_str(), GENERIC_READ, FILE_SHARE_READ,
5338 OPEN_EXISTING, NULL);
5340 if (hFile_ == INVALID_HANDLE_VALUE) {
return false; }
5342 LARGE_INTEGER
size{};
5343 if (!::GetFileSizeEx(hFile_, &
size)) {
return false; }
5347 if (
static_cast<ULONGLONG
>(
size.QuadPart) >
5348 (std::numeric_limits<
decltype(size_)>::max)()) {
5352 size_ =
static_cast<size_t>(
size.QuadPart);
5355 ::CreateFileMappingFromApp(hFile_, NULL, PAGE_READONLY, size_, NULL);
5358 if (hMapping_ == NULL && size_ == 0) {
5360 is_open_empty_file =
true;
5364 if (hMapping_ == NULL) {
5369 addr_ = ::MapViewOfFileFromApp(hMapping_, FILE_MAP_READ, 0, 0);
5371 if (addr_ ==
nullptr) {
5376 fd_ =
::open(path, O_RDONLY);
5377 if (fd_ == -1) {
return false; }
5380 if (fstat(fd_, &sb) == -1) {
5384 size_ =
static_cast<size_t>(sb.st_size);
5386 addr_ =
::mmap(NULL, size_, PROT_READ, MAP_PRIVATE, fd_, 0);
5389 if (addr_ == MAP_FAILED && size_ == 0) {
5391 is_open_empty_file =
true;
5400 return is_open_empty_file ? true : addr_ !=
nullptr;
5406 return is_open_empty_file ?
"" :
static_cast<const char *
>(addr_);
5412 ::UnmapViewOfFile(addr_);
5417 ::CloseHandle(hMapping_);
5421 if (hFile_ != INVALID_HANDLE_VALUE) {
5422 ::CloseHandle(hFile_);
5423 hFile_ = INVALID_HANDLE_VALUE;
5426 is_open_empty_file =
false;
5428 if (addr_ !=
nullptr) {
5429 munmap(addr_, size_);
5442 return closesocket(sock);
5452 if (res < 0 && errno == EINTR) {
5453 std::this_thread::sleep_for(std::chrono::microseconds{1});
5465 static_cast<char *
>(ptr),
static_cast<int>(size),
5478 static_cast<const char *
>(ptr),
static_cast<int>(size),
5488 return ::WSAPoll(fds, nfds, timeout);
5490 return ::poll(fds, nfds, timeout);
5498 pfd.events = events;
5501 auto timeout =
static_cast<int>(sec * 1000 + usec / 1000);
5516 struct pollfd pfd_read;
5518 pfd_read.events = POLLIN | POLLOUT;
5519 pfd_read.revents = 0;
5521 auto timeout =
static_cast<int>(sec * 1000 + usec / 1000);
5528 if (poll_res > 0 && pfd_read.revents & (POLLIN | POLLOUT)) {
5530 socklen_t len =
sizeof(error);
5531 auto res = getsockopt(sock, SOL_SOCKET, SO_ERROR,
5532 reinterpret_cast<char *
>(&error), &len);
5533 auto successful = res >= 0 && !error;
5544 }
else if (val < 0 && errno == EBADF) {
5554 time_t write_timeout_sec, time_t write_timeout_usec,
5555 time_t max_timeout_msec = 0,
5556 std::chrono::time_point<std::chrono::steady_clock> start_time =
5557 (std::chrono::steady_clock::time_point::min)());
5564 ssize_t
read(
char *ptr,
size_t size)
override;
5565 ssize_t
write(
const char *ptr,
size_t size)
override;
5574 time_t read_timeout_sec_;
5575 time_t read_timeout_usec_;
5576 time_t write_timeout_sec_;
5577 time_t write_timeout_usec_;
5578 time_t max_timeout_msec_;
5579 const std::chrono::time_point<std::chrono::steady_clock> start_time_;
5581 std::vector<char> read_buff_;
5582 size_t read_buff_off_ = 0;
5583 size_t read_buff_content_size_ = 0;
5585 static const size_t read_buff_size_ = 1024l * 4;
5589 time_t keep_alive_timeout_sec) {
5590 using namespace std::chrono;
5592 const auto interval_usec =
5596 if (
select_read(sock, 0, interval_usec) > 0) {
return true; }
5598 const auto start = steady_clock::now() - microseconds{interval_usec};
5599 const auto timeout = seconds{keep_alive_timeout_sec};
5609 }
else if (val == 0) {
5610 if (steady_clock::now() - start > timeout) {
5621template <
typename T>
5624 size_t keep_alive_max_count,
5625 time_t keep_alive_timeout_sec, T callback) {
5626 assert(keep_alive_max_count > 0);
5628 auto count = keep_alive_max_count;
5629 while (count > 0 &&
keep_alive(svr_sock, sock, keep_alive_timeout_sec)) {
5630 auto close_connection = count == 1;
5631 auto connection_closed =
false;
5632 ret = callback(close_connection, connection_closed);
5633 if (!ret || connection_closed) {
break; }
5639template <
typename T>
5642 size_t keep_alive_max_count,
5643 time_t keep_alive_timeout_sec, time_t read_timeout_sec,
5644 time_t read_timeout_usec, time_t write_timeout_sec,
5645 time_t write_timeout_usec, T callback) {
5647 svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
5648 [&](
bool close_connection,
bool &connection_closed) {
5649 SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
5650 write_timeout_sec, write_timeout_usec);
5651 return callback(strm, close_connection, connection_closed);
5656 socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
5657 time_t write_timeout_sec, time_t write_timeout_usec,
5658 time_t max_timeout_msec,
5659 std::chrono::time_point<std::chrono::steady_clock> start_time,
5660 std::function<
bool(
Stream &)> callback) {
5661 SocketStream strm(sock, read_timeout_sec, read_timeout_usec,
5662 write_timeout_sec, write_timeout_usec, max_timeout_msec,
5664 return callback(strm);
5669 return shutdown(sock, SD_BOTH);
5671 return shutdown(sock, SHUT_RDWR);
5676 if (s.size() > 1 && s[0] ==
'\0') {
5686 if (s.size() > 1 && s[0] ==
'@') {
5695 const struct addrinfo *hints,
5696 struct addrinfo **res, time_t timeout_sec) {
5697#ifdef CPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO
5698 if (timeout_sec <= 0) {
5700 return getaddrinfo(node, service, hints, res);
5705 OVERLAPPED overlapped = {0};
5706 HANDLE
event = CreateEventW(
nullptr, TRUE, FALSE,
nullptr);
5707 if (!event) {
return EAI_FAIL; }
5709 overlapped.hEvent = event;
5711 PADDRINFOEXW result_addrinfo =
nullptr;
5712 HANDLE cancel_handle =
nullptr;
5714 ADDRINFOEXW hints_ex = {0};
5716 hints_ex.ai_flags = hints->ai_flags;
5717 hints_ex.ai_family = hints->ai_family;
5718 hints_ex.ai_socktype = hints->ai_socktype;
5719 hints_ex.ai_protocol = hints->ai_protocol;
5722 auto wnode = u8string_to_wstring(node);
5723 auto wservice = u8string_to_wstring(service);
5725 auto ret = ::GetAddrInfoExW(wnode.data(), wservice.data(), NS_DNS,
nullptr,
5726 hints ? &hints_ex :
nullptr, &result_addrinfo,
5727 nullptr, &overlapped,
nullptr, &cancel_handle);
5729 if (ret == WSA_IO_PENDING) {
5731 ::WaitForSingleObject(event,
static_cast<DWORD
>(timeout_sec * 1000));
5732 if (wait_result == WAIT_TIMEOUT) {
5733 if (cancel_handle) { ::GetAddrInfoExCancel(&cancel_handle); }
5734 ::CloseHandle(event);
5738 DWORD bytes_returned;
5740 &bytes_returned, FALSE)) {
5741 ::CloseHandle(event);
5742 return ::WSAGetLastError();
5746 ::CloseHandle(event);
5748 if (ret == NO_ERROR || ret == WSA_IO_PENDING) {
5749 *res =
reinterpret_cast<struct addrinfo *
>(result_addrinfo);
5755 if (!node) {
return EAI_NONAME; }
5757 CFStringRef hostname_ref = CFStringCreateWithCString(
5758 kCFAllocatorDefault, node, kCFStringEncodingUTF8);
5759 if (!hostname_ref) {
return EAI_MEMORY; }
5761 CFHostRef host_ref = CFHostCreateWithName(kCFAllocatorDefault, hostname_ref);
5762 CFRelease(hostname_ref);
5763 if (!host_ref) {
return EAI_MEMORY; }
5766 struct CFHostContext {
5767 bool completed =
false;
5768 bool success =
false;
5769 CFArrayRef addresses =
nullptr;
5771 std::condition_variable cv;
5774 CFHostClientContext client_context;
5775 memset(&client_context, 0,
sizeof(client_context));
5776 client_context.info = &context;
5779 auto callback = [](CFHostRef theHost, CFHostInfoType ,
5780 const CFStreamError *error,
void *info) {
5781 auto ctx =
static_cast<CFHostContext *
>(info);
5782 std::lock_guard<std::mutex> lock(ctx->mutex);
5784 if (error && error->error != 0) {
5785 ctx->success =
false;
5787 Boolean hasBeenResolved;
5788 ctx->addresses = CFHostGetAddressing(theHost, &hasBeenResolved);
5789 if (ctx->addresses && hasBeenResolved) {
5790 CFRetain(ctx->addresses);
5791 ctx->success =
true;
5793 ctx->success =
false;
5796 ctx->completed =
true;
5797 ctx->cv.notify_one();
5800 if (!CFHostSetClient(host_ref, callback, &client_context)) {
5801 CFRelease(host_ref);
5806 CFRunLoopRef run_loop = CFRunLoopGetCurrent();
5807 CFHostScheduleWithRunLoop(host_ref, run_loop, kCFRunLoopDefaultMode);
5810 CFStreamError stream_error;
5811 if (!CFHostStartInfoResolution(host_ref, kCFHostAddresses, &stream_error)) {
5812 CFHostUnscheduleFromRunLoop(host_ref, run_loop, kCFRunLoopDefaultMode);
5813 CFRelease(host_ref);
5819 std::chrono::steady_clock::now() + std::chrono::seconds(timeout_sec);
5820 bool timed_out =
false;
5823 std::unique_lock<std::mutex> lock(context.mutex);
5825 while (!context.completed) {
5826 auto now = std::chrono::steady_clock::now();
5827 if (now >= timeout_time) {
5834 CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.1,
true);
5840 CFHostUnscheduleFromRunLoop(host_ref, run_loop, kCFRunLoopDefaultMode);
5841 CFHostSetClient(host_ref,
nullptr,
nullptr);
5843 if (timed_out || !context.completed) {
5844 CFHostCancelInfoResolution(host_ref, kCFHostAddresses);
5845 CFRelease(host_ref);
5849 if (!context.success || !context.addresses) {
5850 CFRelease(host_ref);
5855 CFIndex count = CFArrayGetCount(context.addresses);
5857 CFRelease(context.addresses);
5858 CFRelease(host_ref);
5862 struct addrinfo *result_addrinfo =
nullptr;
5863 struct addrinfo **current = &result_addrinfo;
5865 for (CFIndex i = 0; i < count; i++) {
5866 CFDataRef addr_data =
5867 static_cast<CFDataRef
>(CFArrayGetValueAtIndex(context.addresses, i));
5868 if (!addr_data)
continue;
5870 const struct sockaddr *sockaddr_ptr =
5871 reinterpret_cast<const struct sockaddr *
>(CFDataGetBytePtr(addr_data));
5872 socklen_t sockaddr_len =
static_cast<socklen_t
>(CFDataGetLength(addr_data));
5875 *current =
static_cast<struct addrinfo *
>(malloc(
sizeof(
struct addrinfo)));
5877 freeaddrinfo(result_addrinfo);
5878 CFRelease(context.addresses);
5879 CFRelease(host_ref);
5883 memset(*current, 0,
sizeof(
struct addrinfo));
5886 (*current)->ai_family = sockaddr_ptr->sa_family;
5887 (*current)->ai_socktype = hints ? hints->ai_socktype : SOCK_STREAM;
5888 (*current)->ai_protocol = hints ? hints->ai_protocol : IPPROTO_TCP;
5889 (*current)->ai_addrlen = sockaddr_len;
5892 (*current)->ai_addr =
static_cast<struct sockaddr *
>(malloc(sockaddr_len));
5893 if (!(*current)->ai_addr) {
5894 freeaddrinfo(result_addrinfo);
5895 CFRelease(context.addresses);
5896 CFRelease(host_ref);
5899 memcpy((*current)->ai_addr, sockaddr_ptr, sockaddr_len);
5902 if (service && *service) {
5904 if (
parse_port(service, strlen(service), port)) {
5905 if (sockaddr_ptr->sa_family == AF_INET) {
5906 reinterpret_cast<struct sockaddr_in *
>((*current)->ai_addr)
5907 ->sin_port = htons(
static_cast<uint16_t
>(port));
5908 }
else if (sockaddr_ptr->sa_family == AF_INET6) {
5909 reinterpret_cast<struct sockaddr_in6 *
>((*current)->ai_addr)
5910 ->sin6_port = htons(
static_cast<uint16_t
>(port));
5915 current = &((*current)->ai_next);
5918 CFRelease(context.addresses);
5919 CFRelease(host_ref);
5921 *res = result_addrinfo;
5923#elif defined(_GNU_SOURCE) && defined(__GLIBC__) && \
5924 (__GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 2))
5926 struct gaicb request;
5927 struct gaicb *requests[1] = {&request};
5928 struct sigevent sevp;
5929 struct timespec timeout;
5932 memset(&request, 0,
sizeof(request));
5933 request.ar_name = node;
5934 request.ar_service = service;
5935 request.ar_request = hints;
5938 timeout.tv_sec = timeout_sec;
5939 timeout.tv_nsec = 0;
5942 memset(&sevp, 0,
sizeof(sevp));
5943 sevp.sigev_notify = SIGEV_NONE;
5946 int start_result = getaddrinfo_a(GAI_NOWAIT, requests, 1, &sevp);
5947 if (start_result != 0) {
return start_result; }
5951 gai_suspend((
const struct gaicb *
const *)requests, 1, &timeout);
5953 if (wait_result == 0 || wait_result == EAI_ALLDONE) {
5955 int gai_result = gai_error(&request);
5956 if (gai_result == 0) {
5957 *res = request.ar_result;
5961 if (request.ar_result) { freeaddrinfo(request.ar_result); }
5964 }
else if (wait_result == EAI_AGAIN) {
5966 gai_cancel(&request);
5970 gai_cancel(&request);
5976 struct GetAddrInfoState {
5977 ~GetAddrInfoState() {
5978 if (info) { freeaddrinfo(info); }
5982 std::condition_variable result_cv;
5983 bool completed =
false;
5984 int result = EAI_SYSTEM;
5986 std::string service;
5987 struct addrinfo hints;
5988 struct addrinfo *info =
nullptr;
5992 auto state = std::make_shared<GetAddrInfoState>();
5993 if (node) { state->node = node; }
5994 state->service = service;
5995 state->hints = *hints;
5997 std::thread resolve_thread([state]() {
5998 auto thread_result =
5999 getaddrinfo(state->node.c_str(), state->service.c_str(), &state->hints,
6002 std::lock_guard<std::mutex> lock(state->mutex);
6003 state->result = thread_result;
6004 state->completed =
true;
6005 state->result_cv.notify_one();
6009 std::unique_lock<std::mutex> lock(state->mutex);
6011 state->result_cv.wait_for(lock, std::chrono::seconds(timeout_sec),
6012 [&] {
return state->completed; });
6016 resolve_thread.join();
6018 state->info =
nullptr;
6019 return state->result;
6022 resolve_thread.detach();
6027 (void)(timeout_sec);
6028 return getaddrinfo(node, service, hints, res);
6032template <
typename BindOrConnect>
6034 int address_family,
int socket_flags,
bool tcp_nodelay,
6036 BindOrConnect bind_or_connect, time_t timeout_sec = 0) {
6038 const char *node =
nullptr;
6039 struct addrinfo hints;
6040 struct addrinfo *result;
6042 memset(&hints, 0,
sizeof(
struct addrinfo));
6043 hints.ai_socktype = SOCK_STREAM;
6044 hints.ai_protocol = IPPROTO_IP;
6049 hints.ai_family = AF_UNSPEC;
6050 hints.ai_flags = AI_NUMERICHOST;
6052 if (!host.empty()) { node = host.c_str(); }
6053 hints.ai_family = address_family;
6054 hints.ai_flags = socket_flags;
6057#if !defined(_WIN32) || defined(CPPHTTPLIB_HAVE_AFUNIX_H)
6058 if (hints.ai_family == AF_UNIX) {
6059 const auto addrlen = host.length();
6060 if (addrlen >
sizeof(sockaddr_un::sun_path)) {
return INVALID_SOCKET; }
6063 auto sock = socket(hints.ai_family, hints.ai_socktype | SOCK_CLOEXEC,
6066 auto sock = socket(hints.ai_family, hints.ai_socktype, hints.ai_protocol);
6071 addr.sun_family = AF_UNIX;
6074 std::copy(unescaped_host.begin(), unescaped_host.end(), addr.sun_path);
6076 hints.ai_addr =
reinterpret_cast<sockaddr *
>(&addr);
6077 hints.ai_addrlen =
static_cast<socklen_t
>(
6078 sizeof(addr) -
sizeof(addr.sun_path) + addrlen);
6082 fcntl(sock, F_SETFD, FD_CLOEXEC);
6086 if (socket_options) { socket_options(sock); }
6095 if (!bind_or_connect(sock, hints, dummy)) {
6104 auto service = std::to_string(port);
6108#if defined __linux__ && !defined __ANDROID__
6115 for (
auto rp = result; rp; rp = rp->ai_next) {
6119 WSASocketW(rp->ai_family, rp->ai_socktype, rp->ai_protocol,
nullptr, 0,
6120 WSA_FLAG_NO_HANDLE_INHERIT | WSA_FLAG_OVERLAPPED);
6136 sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
6142 socket(rp->ai_family, rp->ai_socktype | SOCK_CLOEXEC, rp->ai_protocol);
6144 auto sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
6150#if !defined _WIN32 && !defined SOCK_CLOEXEC
6151 if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1) {
6157 if (tcp_nodelay) {
set_socket_opt(sock, IPPROTO_TCP, TCP_NODELAY, 1); }
6159 if (rp->ai_family == AF_INET6) {
6160 set_socket_opt(sock, IPPROTO_IPV6, IPV6_V6ONLY, ipv6_v6only ? 1 : 0);
6163 if (socket_options) { socket_options(sock); }
6167 if (bind_or_connect(sock, *rp, quit)) {
return sock; }
6171 if (quit) {
break; }
6179 auto flags = nonblocking ? 1UL : 0UL;
6180 ioctlsocket(sock, FIONBIO, &flags);
6182 auto flags = fcntl(sock, F_GETFL, 0);
6183 fcntl(sock, F_SETFL,
6184 nonblocking ? (flags | O_NONBLOCK) : (flags & (~O_NONBLOCK)));
6190 return WSAGetLastError() != WSAEWOULDBLOCK;
6192 return errno != EINPROGRESS;
6197 struct addrinfo hints;
6198 struct addrinfo *result;
6200 memset(&hints, 0,
sizeof(
struct addrinfo));
6201 hints.ai_family = AF_UNSPEC;
6202 hints.ai_socktype = SOCK_STREAM;
6203 hints.ai_protocol = 0;
6212 for (
auto rp = result; rp; rp = rp->ai_next) {
6213 const auto &ai = *rp;
6214 if (!::bind(sock, ai.ai_addr,
static_cast<socklen_t
>(ai.ai_addrlen))) {
6223#if !defined _WIN32 && !defined ANDROID && !defined _AIX && !defined __MVS__
6228inline std::string
if2ip(
int address_family,
const std::string &ifn) {
6229 struct ifaddrs *ifap;
6233 std::string addr_candidate;
6234 for (
auto ifa = ifap; ifa; ifa = ifa->ifa_next) {
6235 if (ifa->ifa_addr && ifn == ifa->ifa_name &&
6236 (AF_UNSPEC == address_family ||
6237 ifa->ifa_addr->sa_family == address_family)) {
6238 if (ifa->ifa_addr->sa_family == AF_INET) {
6239 auto sa =
reinterpret_cast<struct sockaddr_in *
>(ifa->ifa_addr);
6240 char buf[INET_ADDRSTRLEN];
6241 if (inet_ntop(AF_INET, &sa->sin_addr, buf, INET_ADDRSTRLEN)) {
6242 return std::string(buf, INET_ADDRSTRLEN);
6244 }
else if (ifa->ifa_addr->sa_family == AF_INET6) {
6245 auto sa =
reinterpret_cast<struct sockaddr_in6 *
>(ifa->ifa_addr);
6246 if (!IN6_IS_ADDR_LINKLOCAL(&sa->sin6_addr)) {
6247 char buf[INET6_ADDRSTRLEN] = {};
6248 if (inet_ntop(AF_INET6, &sa->sin6_addr, buf, INET6_ADDRSTRLEN)) {
6250 auto s6_addr_head = sa->sin6_addr.s6_addr[0];
6251 if (s6_addr_head == 0xfc || s6_addr_head == 0xfd) {
6252 addr_candidate = std::string(buf, INET6_ADDRSTRLEN);
6254 return std::string(buf, INET6_ADDRSTRLEN);
6261 return addr_candidate;
6266 const std::string &host,
const std::string &ip,
int port,
6267 int address_family,
bool tcp_nodelay,
bool ipv6_v6only,
6268 SocketOptions socket_options, time_t connection_timeout_sec,
6269 time_t connection_timeout_usec, time_t read_timeout_sec,
6270 time_t read_timeout_usec, time_t write_timeout_sec,
6271 time_t write_timeout_usec,
const std::string &intf,
Error &error) {
6273 host, ip, port, address_family, 0, tcp_nodelay, ipv6_v6only,
6274 std::move(socket_options),
6275 [&](
socket_t sock2,
struct addrinfo &ai,
bool &quit) ->
bool {
6276 if (!intf.empty()) {
6278 auto ip_from_if =
if2ip(address_family, intf);
6279 if (ip_from_if.empty()) { ip_from_if = intf; }
6290 ::connect(sock2, ai.ai_addr,
static_cast<socklen_t
>(ai.ai_addrlen));
6298 connection_timeout_usec);
6309 write_timeout_usec);
6314 connection_timeout_sec);
6326 socklen_t addr_len, std::string &ip,
int &port) {
6327 if (addr.ss_family == AF_INET) {
6328 port = ntohs(
reinterpret_cast<const struct sockaddr_in *
>(&addr)->sin_port);
6329 }
else if (addr.ss_family == AF_INET6) {
6331 ntohs(
reinterpret_cast<const struct sockaddr_in6 *
>(&addr)->sin6_port);
6336 std::array<char, NI_MAXHOST> ipstr{};
6337 if (getnameinfo(
reinterpret_cast<const struct sockaddr *
>(&addr), addr_len,
6338 ipstr.data(),
static_cast<socklen_t
>(ipstr.size()),
nullptr,
6339 0, NI_NUMERICHOST)) {
6348 struct sockaddr_storage addr;
6349 socklen_t addr_len =
sizeof(addr);
6350 if (!getsockname(sock,
reinterpret_cast<struct sockaddr *
>(&addr),
6357 struct sockaddr_storage addr;
6358 socklen_t addr_len =
sizeof(addr);
6360 if (!getpeername(sock,
reinterpret_cast<struct sockaddr *
>(&addr),
6363 if (addr.ss_family == AF_UNIX) {
6364#if defined(__linux__)
6366 socklen_t len =
sizeof(ucred);
6367 if (getsockopt(sock, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == 0) {
6370#elif defined(SOL_LOCAL) && defined(SO_PEERPID)
6372 socklen_t len =
sizeof(pid);
6373 if (getsockopt(sock, SOL_LOCAL, SO_PEERPID, &pid, &len) == 0) {
6391 (((std::numeric_limits<unsigned int>::max)() >> 6) &
6393 static_cast<unsigned char>(*s));
6396inline unsigned int str2tag(
const std::string &s) {
6402inline constexpr unsigned int operator""_t(
const char *s,
size_t l) {
6410 const std::map<std::string, std::string> &user_data,
6411 const std::string &default_content_type) {
6414 auto it = user_data.find(ext);
6415 if (it != user_data.end()) {
return it->second; }
6417 using udl::operator
""_t;
6420 default:
return default_content_type;
6422 case "css"_t:
return "text/css";
6423 case "csv"_t:
return "text/csv";
6425 case "html"_t:
return "text/html";
6427 case "mjs"_t:
return "text/javascript";
6428 case "txt"_t:
return "text/plain";
6429 case "vtt"_t:
return "text/vtt";
6431 case "apng"_t:
return "image/apng";
6432 case "avif"_t:
return "image/avif";
6433 case "bmp"_t:
return "image/bmp";
6434 case "gif"_t:
return "image/gif";
6435 case "png"_t:
return "image/png";
6436 case "svg"_t:
return "image/svg+xml";
6437 case "webp"_t:
return "image/webp";
6438 case "ico"_t:
return "image/x-icon";
6439 case "tif"_t:
return "image/tiff";
6440 case "tiff"_t:
return "image/tiff";
6442 case "jpeg"_t:
return "image/jpeg";
6444 case "mp4"_t:
return "video/mp4";
6445 case "mpeg"_t:
return "video/mpeg";
6446 case "webm"_t:
return "video/webm";
6448 case "mp3"_t:
return "audio/mp3";
6449 case "mpga"_t:
return "audio/mpeg";
6450 case "weba"_t:
return "audio/webm";
6451 case "wav"_t:
return "audio/wave";
6453 case "otf"_t:
return "font/otf";
6454 case "ttf"_t:
return "font/ttf";
6455 case "woff"_t:
return "font/woff";
6456 case "woff2"_t:
return "font/woff2";
6458 case "7z"_t:
return "application/x-7z-compressed";
6459 case "atom"_t:
return "application/atom+xml";
6460 case "pdf"_t:
return "application/pdf";
6461 case "json"_t:
return "application/json";
6462 case "rss"_t:
return "application/rss+xml";
6463 case "tar"_t:
return "application/x-tar";
6465 case "xhtml"_t:
return "application/xhtml+xml";
6466 case "xslt"_t:
return "application/xslt+xml";
6467 case "xml"_t:
return "application/xml";
6468 case "gz"_t:
return "application/gzip";
6469 case "zip"_t:
return "application/zip";
6470 case "wasm"_t:
return "application/wasm";
6476 std::map<std::string, std::string> *params =
nullptr) {
6479 auto media_type = content_type;
6480 auto semicolon_pos = media_type.find(
';');
6481 if (semicolon_pos != std::string::npos) {
6482 auto param_str = media_type.substr(semicolon_pos + 1);
6483 media_type = media_type.substr(0, semicolon_pos);
6487 split(param_str.data(), param_str.data() + param_str.size(),
';',
6488 [&](
const char *b,
const char *e) {
6491 split(b, e,
'=', [&](const char *b2, const char *e2) {
6510 using udl::operator
""_t;
6513 auto tag =
str2tag(mime_type);
6516 case "image/svg+xml"_t:
6517 case "application/javascript"_t:
6518 case "application/x-javascript"_t:
6519 case "application/json"_t:
6520 case "application/ld+json"_t:
6521 case "application/xml"_t:
6522 case "application/xhtml+xml"_t:
6523 case "application/rss+xml"_t:
6524 case "application/atom+xml"_t:
6525 case "application/xslt+xml"_t:
6526 case "application/protobuf"_t:
return true;
6528 case "text/event-stream"_t:
return false;
6530 default:
return !mime_type.rfind(
"text/", 0);
6540 const char *params_b =
nullptr;
6541 std::size_t params_len = 0;
6544 b,
static_cast<std::size_t
>(e - b),
';',
6545 [&](
const char *lb, std::size_t llen,
const char *rb, std::size_t rlen) {
6546 auto r =
trim(lb, lb + llen, 0, llen);
6547 if (r.first < r.second) { token.assign(lb + r.first, lb + r.second); }
6552 if (token.empty()) {
return false; }
6553 if (params_len == 0) {
return true; }
6556 bool invalid =
false;
6557 split_find(params_b, params_b + params_len,
';',
6558 (std::numeric_limits<size_t>::max)(),
6559 [&](
const char *pb,
const char *pe) ->
bool {
6561 auto len =
static_cast<size_t>(pe - pb);
6562 if (len < 2) {
return false; }
6563 if ((pb[0] !=
'q' && pb[0] !=
'Q') || pb[1] !=
'=') {
6568 auto r =
trim(pb, pe, 2, len);
6569 if (r.first >= r.second) {
6575 auto res =
from_chars(pb + r.first, pb + r.second, v);
6576 if (res.ec != std::errc{} || v < 0.0 || v > 1.0) {
6598 double best_q = 0.0;
6611 split(s.data(), s.data() + s.size(),
',', [&](
const char *b,
const char *e) {
6612 double quality = 1.0;
6613 if (!parse_quality(b, e, name, quality)) { return; }
6614 if (quality <= 0.0) {
return; }
6617#ifdef CPPHTTPLIB_BROTLI_SUPPORT
6620#ifdef CPPHTTPLIB_ZLIB_SUPPORT
6625#ifdef CPPHTTPLIB_ZSTD_SUPPORT
6634 if (quality > best_q ||
6635 (quality == best_q && priority(type) < priority(best))) {
6646 if (!data_length) {
return true; }
6647 return callback(data, data_length);
6650#ifdef CPPHTTPLIB_ZLIB_SUPPORT
6651inline gzip_compressor::gzip_compressor() {
6652 std::memset(&strm_, 0,
sizeof(strm_));
6653 strm_.zalloc = Z_NULL;
6654 strm_.zfree = Z_NULL;
6655 strm_.opaque = Z_NULL;
6657 is_valid_ = deflateInit2(&strm_, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 8,
6658 Z_DEFAULT_STRATEGY) == Z_OK;
6661inline gzip_compressor::~gzip_compressor() { deflateEnd(&strm_); }
6663inline bool gzip_compressor::compress(
const char *data,
size_t data_length,
6664 bool last, Callback callback) {
6668 constexpr size_t max_avail_in =
6669 (std::numeric_limits<
decltype(strm_.avail_in)>::max)();
6671 strm_.avail_in =
static_cast<decltype(strm_.avail_in)
>(
6672 (std::min)(data_length, max_avail_in));
6673 strm_.next_in =
const_cast<Bytef *
>(
reinterpret_cast<const Bytef *
>(data));
6675 data_length -= strm_.avail_in;
6676 data += strm_.avail_in;
6678 auto flush = (last && data_length == 0) ? Z_FINISH : Z_NO_FLUSH;
6681 std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
6683 strm_.avail_out =
static_cast<uInt
>(buff.size());
6684 strm_.next_out =
reinterpret_cast<Bytef *
>(buff.data());
6686 ret = deflate(&strm_, flush);
6687 if (ret == Z_STREAM_ERROR) {
return false; }
6689 if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
6692 }
while (strm_.avail_out == 0);
6694 assert((flush == Z_FINISH && ret == Z_STREAM_END) ||
6695 (flush == Z_NO_FLUSH && ret == Z_OK));
6696 assert(strm_.avail_in == 0);
6697 }
while (data_length > 0);
6702inline gzip_decompressor::gzip_decompressor() {
6703 std::memset(&strm_, 0,
sizeof(strm_));
6704 strm_.zalloc = Z_NULL;
6705 strm_.zfree = Z_NULL;
6706 strm_.opaque = Z_NULL;
6712 is_valid_ = inflateInit2(&strm_, 32 + 15) == Z_OK;
6715inline gzip_decompressor::~gzip_decompressor() { inflateEnd(&strm_); }
6717inline bool gzip_decompressor::is_valid()
const {
return is_valid_; }
6719inline bool gzip_decompressor::decompress(
const char *data,
size_t data_length,
6720 Callback callback) {
6726 constexpr size_t max_avail_in =
6727 (std::numeric_limits<
decltype(strm_.avail_in)>::max)();
6729 strm_.avail_in =
static_cast<decltype(strm_.avail_in)
>(
6730 (std::min)(data_length, max_avail_in));
6731 strm_.next_in =
const_cast<Bytef *
>(
reinterpret_cast<const Bytef *
>(data));
6733 data_length -= strm_.avail_in;
6734 data += strm_.avail_in;
6736 std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
6737 while (strm_.avail_in > 0 && ret == Z_OK) {
6738 strm_.avail_out = static_cast<uInt>(buff.size());
6739 strm_.next_out = reinterpret_cast<Bytef *>(buff.data());
6741 ret = inflate(&strm_, Z_NO_FLUSH);
6743 assert(ret != Z_STREAM_ERROR);
6747 case Z_MEM_ERROR: inflateEnd(&strm_); return false;
6750 if (!callback(buff.data(), buff.size() - strm_.avail_out)) {
6755 if (ret != Z_OK && ret != Z_STREAM_END) {
return false; }
6757 }
while (data_length > 0);
6763#ifdef CPPHTTPLIB_BROTLI_SUPPORT
6764inline brotli_compressor::brotli_compressor() {
6765 state_ = BrotliEncoderCreateInstance(
nullptr,
nullptr,
nullptr);
6768inline brotli_compressor::~brotli_compressor() {
6769 BrotliEncoderDestroyInstance(state_);
6772inline bool brotli_compressor::compress(
const char *data,
size_t data_length,
6773 bool last, Callback callback) {
6774 std::array<uint8_t, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
6776 auto operation = last ? BROTLI_OPERATION_FINISH : BROTLI_OPERATION_PROCESS;
6777 auto available_in = data_length;
6778 auto next_in =
reinterpret_cast<const uint8_t *
>(data);
6782 if (BrotliEncoderIsFinished(state_)) {
break; }
6784 if (!available_in) {
break; }
6787 auto available_out = buff.size();
6788 auto next_out = buff.data();
6790 if (!BrotliEncoderCompressStream(state_, operation, &available_in, &next_in,
6791 &available_out, &next_out,
nullptr)) {
6795 auto output_bytes = buff.size() - available_out;
6797 callback(
reinterpret_cast<const char *
>(buff.data()), output_bytes);
6804inline brotli_decompressor::brotli_decompressor() {
6805 decoder_s = BrotliDecoderCreateInstance(0, 0, 0);
6806 decoder_r = decoder_s ? BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT
6807 : BROTLI_DECODER_RESULT_ERROR;
6810inline brotli_decompressor::~brotli_decompressor() {
6811 if (decoder_s) { BrotliDecoderDestroyInstance(decoder_s); }
6814inline bool brotli_decompressor::is_valid()
const {
return decoder_s; }
6816inline bool brotli_decompressor::decompress(
const char *data,
6818 Callback callback) {
6819 if (decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
6820 decoder_r == BROTLI_DECODER_RESULT_ERROR) {
6824 auto next_in =
reinterpret_cast<const uint8_t *
>(data);
6825 size_t avail_in = data_length;
6828 decoder_r = BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT;
6830 std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
6831 while (decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) {
6832 char *next_out = buff.data();
6833 size_t avail_out = buff.size();
6835 decoder_r = BrotliDecoderDecompressStream(
6836 decoder_s, &avail_in, &next_in, &avail_out,
6837 reinterpret_cast<uint8_t **
>(&next_out), &total_out);
6839 if (decoder_r == BROTLI_DECODER_RESULT_ERROR) {
return false; }
6841 if (!callback(buff.data(), buff.size() - avail_out)) {
return false; }
6844 return decoder_r == BROTLI_DECODER_RESULT_SUCCESS ||
6845 decoder_r == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT;
6849#ifdef CPPHTTPLIB_ZSTD_SUPPORT
6850inline zstd_compressor::zstd_compressor() {
6851 ctx_ = ZSTD_createCCtx();
6852 ZSTD_CCtx_setParameter(ctx_, ZSTD_c_compressionLevel, ZSTD_fast);
6855inline zstd_compressor::~zstd_compressor() { ZSTD_freeCCtx(ctx_); }
6857inline bool zstd_compressor::compress(
const char *data,
size_t data_length,
6858 bool last, Callback callback) {
6859 std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
6861 ZSTD_EndDirective mode = last ? ZSTD_e_end : ZSTD_e_continue;
6862 ZSTD_inBuffer input = {data, data_length, 0};
6867 size_t const remaining = ZSTD_compressStream2(ctx_, &output, &input, mode);
6869 if (ZSTD_isError(remaining)) {
return false; }
6871 if (!callback(buff.data(), output.pos)) {
return false; }
6873 finished = last ? (remaining == 0) : (input.pos == input.size);
6875 }
while (!finished);
6880inline zstd_decompressor::zstd_decompressor() { ctx_ = ZSTD_createDCtx(); }
6882inline zstd_decompressor::~zstd_decompressor() { ZSTD_freeDCtx(ctx_); }
6884inline bool zstd_decompressor::is_valid()
const {
return ctx_ !=
nullptr; }
6886inline bool zstd_decompressor::decompress(
const char *data,
size_t data_length,
6887 Callback callback) {
6888 std::array<char, CPPHTTPLIB_COMPRESSION_BUFSIZ> buff{};
6889 ZSTD_inBuffer input = {data, data_length, 0};
6891 while (input.pos < input.size) {
6893 size_t const remaining = ZSTD_decompressStream(ctx_, &output, &input);
6895 if (ZSTD_isError(remaining)) {
return false; }
6897 if (!callback(buff.data(), output.pos)) {
return false; }
6904inline std::unique_ptr<decompressor>
6908 if (encoding ==
"gzip" || encoding ==
"deflate") {
6909#ifdef CPPHTTPLIB_ZLIB_SUPPORT
6912 }
else if (encoding.find(
"br") != std::string::npos) {
6913#ifdef CPPHTTPLIB_BROTLI_SUPPORT
6916 }
else if (encoding ==
"zstd" || encoding.find(
"zstd") != std::string::npos) {
6917#ifdef CPPHTTPLIB_ZSTD_SUPPORT
6927inline std::pair<std::unique_ptr<compressor>,
const char *>
6929#ifdef CPPHTTPLIB_BROTLI_SUPPORT
6931#elif defined(CPPHTTPLIB_ZLIB_SUPPORT)
6933#elif defined(CPPHTTPLIB_ZSTD_SUPPORT)
6936 return {
nullptr,
nullptr};
6941 using udl::operator
""_t;
6944 case "REMOTE_ADDR"_t:
6945 case "REMOTE_PORT"_t:
6946 case "LOCAL_ADDR"_t:
6947 case "LOCAL_PORT"_t:
return true;
6948 default:
return false;
6954 return headers.find(key) != headers.end();
6958 const std::string &key,
const char *def,
6961#ifndef CPPHTTPLIB_NO_EXCEPTIONS
6962 std::string msg =
"Prohibited header name '" + key +
"' is specified.";
6963 throw std::invalid_argument(msg);
6969 auto rng = headers.equal_range(key);
6970 auto it = rng.first;
6971 std::advance(it,
static_cast<ssize_t
>(
id));
6972 if (it != rng.second) {
return it->second.c_str(); }
6977 const auto bufsiz = 2048;
6981 size_t header_count = 0;
6984 if (!line_reader.
getline()) {
return false; }
6987 auto line_terminator_len = 2;
6990 if (line_reader.
size() == 2) {
break; }
6992#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
6994 if (line_reader.
size() == 1) {
break; }
6995 line_terminator_len = 1;
7007 auto end = line_reader.
ptr() + line_reader.
size() - line_terminator_len;
7010 [&](
const std::string &key,
const std::string &val) {
7011 headers.emplace(key, val);
7021 auto cl_range = headers.equal_range(
"Content-Length");
7022 if (cl_range.first != cl_range.second) {
7023 const auto &first_val = cl_range.first->second;
7024 for (
auto it = std::next(cl_range.first); it != cl_range.second; ++it) {
7025 if (it->second != first_val) {
return false; }
7033 const std::string &expected_accept,
7034 std::string &selected_subprotocol) {
7036 const auto bufsiz = 2048;
7039 if (!line_reader.
getline()) {
return false; }
7042 auto line = std::string(line_reader.
ptr(), line_reader.
size());
7043 if (line.find(
"HTTP/1.1 101") == std::string::npos) {
return false; }
7050 auto upgrade_it = headers.find(
"Upgrade");
7051 if (upgrade_it == headers.end()) {
return false; }
7053 if (upgrade_val !=
"websocket") {
return false; }
7056 auto connection_it = headers.find(
"Connection");
7057 if (connection_it == headers.end()) {
return false; }
7059 if (connection_val.find(
"upgrade") == std::string::npos) {
return false; }
7062 auto it = headers.find(
"Sec-WebSocket-Accept");
7063 if (it == headers.end() || it->second != expected_accept) {
return false; }
7066 auto proto_it = headers.find(
"Sec-WebSocket-Protocol");
7067 if (proto_it != headers.end()) { selected_subprotocol = proto_it->second; }
7081 size_t payload_max_length = (std::numeric_limits<size_t>::max)()) {
7095 auto read_len =
static_cast<size_t>(len - r);
7106 if (!out(buf,
static_cast<size_t>(n), r, len)) {
7109 r +=
static_cast<size_t>(n);
7119inline ReadContentResult
7130 if (r > payload_max_length ||
7131 payload_max_length - r <
static_cast<size_t>(n)) {
7135 if (!out(buf,
static_cast<size_t>(n), r, 0)) {
7138 r +=
static_cast<size_t>(n);
7144template <
typename T>
7146 size_t payload_max_length,
7151 size_t total_len = 0;
7154 size_t chunk_offset = 0;
7155 size_t chunk_total = 0;
7156 auto n = dec.
read_payload(buf,
sizeof(buf), chunk_offset, chunk_total);
7166 if (total_len > payload_max_length ||
7167 payload_max_length - total_len <
static_cast<size_t>(n)) {
7171 if (!out(buf,
static_cast<size_t>(n), chunk_offset, chunk_total)) {
7175 total_len +=
static_cast<size_t>(n);
7184template <
typename T,
typename U>
7187 bool decompress,
size_t payload_max_length,
7188 bool &exceed_payload_max_length, U callback) {
7190 std::string encoding = x.get_header_value(
"Content-Encoding");
7193 if (!encoding.empty()) {
7204 size_t decompressed_size = 0;
7206 size_t off,
size_t len) {
7208 buf, n, [&](
const char *buf2,
size_t n2) {
7211 if (payload_max_length > 0 &&
7212 (decompressed_size >= payload_max_length ||
7213 n2 > payload_max_length - decompressed_size)) {
7214 exceed_payload_max_length =
true;
7217 decompressed_size += n2;
7218 return receiver(buf2, n2, off, len);
7221 return callback(std::move(out));
7231 return receiver(buf, n, off, len);
7233 return callback(std::move(out));
7236template <
typename T>
7240 bool exceed_payload_max_length =
false;
7242 x, status, std::move(receiver), decompress, payload_max_length,
7254 exceed_payload_max_length =
true;
7259 }
else if (!
has_header(x.headers,
"Content-Length")) {
7265 exceed_payload_max_length =
true;
7271 auto is_invalid_value =
false;
7273 (std::numeric_limits<size_t>::max)(),
7274 0, is_invalid_value);
7276 if (is_invalid_value) {
7278 }
else if (len > 0) {
7280 strm, len, std::move(progress), out, payload_max_length);
7283 exceed_payload_max_length =
true;
7297 const std::string &path) {
7298 std::string s = method;
7301 s +=
" HTTP/1.1\r\n";
7302 return strm.
write(s.data(), s.size());
7306 std::string s =
"HTTP/1.1 ";
7307 s += std::to_string(status);
7311 return strm.
write(s.data(), s.size());
7315 ssize_t write_len = 0;
7316 for (
const auto &x : headers) {
7323 auto len = strm.
write(s.data(), s.size());
7324 if (len < 0) {
return len; }
7327 auto len = strm.
write(
"\r\n");
7328 if (len < 0) {
return len; }
7335 while (offset < l) {
7336 auto length = strm.
write(d + offset, l - offset);
7337 if (length < 0) {
return false; }
7338 offset +=
static_cast<size_t>(length);
7343template <
typename T>
7346 size_t offset,
size_t length,
7350 size_t end_offset = offset + length;
7351 size_t start_offset = offset;
7355 data_sink.
write = [&](
const char *d,
size_t l) ->
bool {
7360 if (upload_progress && length > 0) {
7361 size_t current_written = offset - start_offset;
7362 if (!upload_progress(current_written, length)) {
7376 while (offset < end_offset && !is_shutting_down()) {
7380 }
else if (!content_provider(offset, end_offset - offset, data_sink)) {
7389 if (offset < end_offset) {
7398template <
typename T>
7400 size_t offset,
size_t length, T is_shutting_down,
7403 is_shutting_down,
nullptr, error);
7406template <
typename T>
7408 size_t offset,
size_t length,
7409 const T &is_shutting_down) {
7411 return write_content(strm, content_provider, offset, length, is_shutting_down,
7415template <
typename T>
7419 const T &is_shutting_down) {
7421 auto data_available =
true;
7425 data_sink.
write = [&](
const char *d,
size_t l) ->
bool {
7435 data_sink.
done = [&](void) { data_available =
false; };
7437 while (data_available && !is_shutting_down()) {
7440 }
else if (!content_provider(offset, 0, data_sink)) {
7446 return !data_available;
7450template <
typename T,
typename U>
7455 auto data_available =
true;
7459 data_sink.
write = [&](
const char *d,
size_t l) ->
bool {
7461 data_available = l > 0;
7464 std::string payload;
7466 [&](
const char *data,
size_t data_len) {
7467 payload.append(data, data_len);
7470 if (!payload.empty()) {
7474 if (!
write_data(strm, chunk.data(), chunk.size())) { ok =
false; }
7485 auto done_with_trailer = [&](
const Headers *trailer) {
7486 if (!ok) {
return; }
7488 data_available =
false;
7490 std::string payload;
7492 [&](
const char *data,
size_t data_len) {
7493 payload.append(data, data_len);
7500 if (!payload.empty()) {
7502 auto chunk =
from_i_to_hex(payload.size()) +
"\r\n" + payload +
"\r\n";
7503 if (!
write_data(strm, chunk.data(), chunk.size())) {
7509 constexpr const char done_marker[] =
"0\r\n";
7514 for (
const auto &kv : *trailer) {
7515 std::string field_line = kv.first +
": " + kv.second +
"\r\n";
7516 if (!
write_data(strm, field_line.data(), field_line.size())) {
7522 constexpr const char crlf[] =
"\r\n";
7526 data_sink.
done = [&](void) { done_with_trailer(
nullptr); };
7529 done_with_trailer(&trailer);
7532 while (data_available && !is_shutting_down()) {
7536 }
else if (!content_provider(offset, 0, data_sink)) {
7545 if (data_available) {
7554template <
typename T,
typename U>
7563template <
typename T>
7565 const std::string &path,
const std::string &location,
7568 new_req.
path = path;
7574 new_req.
body.clear();
7580 auto ret = cli.send(new_req, new_res, error);
7582 req = std::move(new_req);
7583 res = std::move(new_res);
7593 for (
auto it = params.begin(); it != params.end(); ++it) {
7594 if (it != params.begin()) { query +=
'&'; }
7604 std::set<std::string> cache;
7605 split(data, data + size,
'&', [&](
const char *b,
const char *e) {
7606 std::string kv(b, e);
7607 if (cache.find(kv) != cache.end()) {
return; }
7608 cache.insert(std::move(kv));
7612 divide(b,
static_cast<std::size_t
>(e - b),
'=',
7613 [&](
const char *lhs_data, std::size_t lhs_size,
const char *rhs_data,
7614 std::size_t rhs_size) {
7615 key.assign(lhs_data, lhs_size);
7616 val.assign(rhs_data, rhs_size);
7635 split(query.data(), query.data() + query.size(),
'&',
7636 [&](
const char *b,
const char *e) {
7639 divide(b, static_cast<std::size_t>(e - b),
'=',
7640 [&](const char *lhs_data, std::size_t lhs_size,
7641 const char *rhs_data, std::size_t rhs_size) {
7642 key.assign(lhs_data, lhs_size);
7643 val.assign(rhs_data, rhs_size);
7650 if (!result.empty()) { result +=
'&'; }
7652 if (!val.empty() || std::find(b, e,
'=') != e) {
7662 std::string &boundary) {
7663 std::map<std::string, std::string> params;
7665 auto it = params.find(
"boundary");
7666 if (it == params.end()) {
return false; }
7667 boundary = it->second;
7668 return !boundary.empty();
7672 std::set<std::string> cache;
7673 split(s.data(), s.data() + s.size(),
';', [&](
const char *b,
const char *e) {
7674 std::string kv(b, e);
7675 if (cache.find(kv) != cache.end()) { return; }
7680 split(b, e,
'=', [&](
const char *b2,
const char *e2) {
7689 params.emplace(trim_double_quotes_copy((key)),
7690 trim_double_quotes_copy((val)));
7695#ifdef CPPHTTPLIB_NO_EXCEPTIONS
7696inline bool parse_range_header(
const std::string &s, Ranges &ranges) {
7700 auto is_valid = [](
const std::string &str) {
7701 return std::all_of(str.cbegin(), str.cend(),
7702 [](
unsigned char c) { return std::isdigit(c); });
7705 if (s.size() > 7 && s.compare(0, 6,
"bytes=") == 0) {
7706 const auto pos =
static_cast<size_t>(6);
7707 const auto len =
static_cast<size_t>(s.size() - 6);
7708 auto all_valid_ranges =
true;
7709 split(&s[pos], &s[pos + len],
',', [&](
const char *b,
const char *e) {
7710 if (!all_valid_ranges) {
return; }
7712 const auto it = std::find(b, e,
'-');
7714 all_valid_ranges =
false;
7718 const auto lhs = std::string(b, it);
7719 const auto rhs = std::string(it + 1, e);
7720 if (!is_valid(lhs) || !is_valid(rhs)) {
7721 all_valid_ranges =
false;
7729 if (res.ec == std::errc{}) { first = v; }
7736 if (res.ec == std::errc{}) { last = v; }
7739 if ((first == -1 && last == -1) ||
7740 (first != -1 && last != -1 && first > last)) {
7741 all_valid_ranges =
false;
7745 ranges.emplace_back(first, last);
7747 return all_valid_ranges && !ranges.empty();
7750#ifdef CPPHTTPLIB_NO_EXCEPTIONS
7753}
catch (...) {
return false; }
7757 std::vector<std::string> &content_types) {
7758 content_types.clear();
7761 if (s.empty()) {
return true; }
7764 if (s.front() ==
',' || s.back() ==
',' ||
7765 s.find(
",,") != std::string::npos) {
7769 struct AcceptEntry {
7770 std::string media_type;
7775 std::vector<AcceptEntry> entries;
7777 bool has_invalid_entry =
false;
7780 split(s.data(), s.data() + s.size(),
',', [&](
const char *b,
const char *e) {
7781 std::string entry(b, e);
7782 entry = trim_copy(entry);
7784 if (entry.empty()) {
7785 has_invalid_entry = true;
7789 AcceptEntry accept_entry;
7790 accept_entry.order = order++;
7792 if (!
parse_quality(entry.data(), entry.data() + entry.size(),
7793 accept_entry.media_type, accept_entry.quality)) {
7794 has_invalid_entry = true;
7802 if (accept_entry.media_type.empty()) {
7803 has_invalid_entry = true;
7808 if (accept_entry.media_type !=
"*" &&
7809 accept_entry.media_type.find(
'/') == std::string::npos) {
7810 has_invalid_entry = true;
7814 entries.push_back(std::move(accept_entry));
7818 if (has_invalid_entry) {
return false; }
7821 std::sort(entries.begin(), entries.end(),
7822 [](
const AcceptEntry &a,
const AcceptEntry &b) {
7823 if (a.quality != b.quality) {
7824 return a.quality > b.quality;
7826 return a.order < b.order;
7830 content_types.reserve(entries.size());
7831 for (
auto &entry : entries) {
7832 content_types.push_back(std::move(entry.media_type));
7843 boundary_ = std::move(boundary);
7844 dash_boundary_crlf_ = dash_ + boundary_ + crlf_;
7845 crlf_dash_boundary_ = crlf_ + dash_ + boundary_;
7855 while (buf_size() > 0) {
7858 auto pos = buf_find(dash_boundary_crlf_);
7859 if (pos == buf_size()) {
return true; }
7860 buf_erase(pos + dash_boundary_crlf_.size());
7870 auto pos = buf_find(crlf_);
7872 while (pos < buf_size()) {
7875 if (!header_callback(file_)) {
7879 buf_erase(crlf_.size());
7884 const auto header = buf_head(pos);
7886 if (!
parse_header(header.data(), header.data() + header.size(),
7887 [&](
const std::string &,
const std::string &) {})) {
7894 header.data(), header.data() + header.size(),
7895 [&](
const std::string &key,
const std::string &val) {
7896 file_.headers.emplace(key, val);
7902 constexpr const char header_content_type[] =
"Content-Type:";
7904 if (start_with_case_ignore(header, header_content_type)) {
7905 file_.content_type =
7908 std::string disposition_params;
7909 if (parse_content_disposition(header, disposition_params)) {
7913 auto it = params.find(
"name");
7914 if (it != params.end()) {
7915 file_.name = it->second;
7921 it = params.find(
"filename");
7922 if (it != params.end()) { file_.filename = it->second; }
7924 it = params.find(
"filename*");
7925 if (it != params.end()) {
7927 const auto &val = it->second;
7928 constexpr const char utf8_prefix[] =
"UTF-8''";
7929 constexpr size_t prefix_len =
str_len(utf8_prefix);
7930 if (val.size() > prefix_len &&
7931 start_with_case_ignore(val, utf8_prefix)) {
7933 val.substr(prefix_len));
7941 buf_erase(pos + crlf_.size());
7942 pos = buf_find(crlf_);
7944 if (state_ != 3) {
return true; }
7948 if (crlf_dash_boundary_.size() > buf_size()) {
return true; }
7949 auto pos = buf_find(crlf_dash_boundary_);
7950 if (pos < buf_size()) {
7951 if (!content_callback(buf_data(), pos)) {
7955 buf_erase(pos + crlf_dash_boundary_.size());
7958 auto len = buf_size() - crlf_dash_boundary_.size();
7960 if (!content_callback(buf_data(), len)) {
7971 if (crlf_.size() > buf_size()) {
return true; }
7972 if (buf_start_with(crlf_)) {
7973 buf_erase(crlf_.size());
7976 if (dash_.size() > buf_size()) {
return true; }
7977 if (buf_start_with(dash_)) {
7978 buf_erase(dash_.size());
7980 buf_erase(buf_size());
7994 void clear_file_info() {
7996 file_.filename.clear();
7997 file_.content_type.clear();
7998 file_.headers.clear();
8001 bool start_with_case_ignore(
const std::string &a,
const char *b,
8002 size_t offset = 0)
const {
8003 const auto b_len = strlen(b);
8004 if (a.size() < offset + b_len) {
return false; }
8005 for (
size_t i = 0; i < b_len; i++) {
8006 if (case_ignore::to_lower(a[offset + i]) != case_ignore::to_lower(b[i])) {
8015 bool parse_content_disposition(
const std::string &header,
8016 std::string ¶ms_out)
const {
8017 constexpr const char prefix[] =
"Content-Disposition:";
8018 constexpr size_t prefix_len =
str_len(prefix);
8020 if (!start_with_case_ignore(header, prefix)) {
return false; }
8023 auto pos = prefix_len;
8024 while (pos < header.size() && (header[pos] ==
' ' || header[pos] ==
'\t')) {
8029 constexpr const char form_data[] =
"form-data;";
8030 constexpr size_t form_data_len =
str_len(form_data);
8031 if (!start_with_case_ignore(header, form_data, pos)) {
return false; }
8032 pos += form_data_len;
8035 while (pos < header.size() && (header[pos] ==
' ' || header[pos] ==
'\t')) {
8039 params_out = header.substr(pos);
8043 const std::string dash_ =
"--";
8044 const std::string crlf_ =
"\r\n";
8045 std::string boundary_;
8046 std::string dash_boundary_crlf_;
8047 std::string crlf_dash_boundary_;
8050 bool is_valid_ =
false;
8054 bool start_with(
const std::string &a,
size_t spos,
size_t epos,
8055 const std::string &b)
const {
8056 if (epos - spos < b.size()) {
return false; }
8057 for (
size_t i = 0; i < b.size(); i++) {
8058 if (a[i + spos] != b[i]) {
return false; }
8063 size_t buf_size()
const {
return buf_epos_ - buf_spos_; }
8065 const char *buf_data()
const {
return &buf_[buf_spos_]; }
8067 std::string buf_head(
size_t l)
const {
return buf_.substr(buf_spos_, l); }
8069 bool buf_start_with(
const std::string &s)
const {
8070 return start_with(buf_, buf_spos_, buf_epos_, s);
8073 size_t buf_find(
const std::string &s)
const {
8076 size_t off = buf_spos_;
8077 while (off < buf_epos_) {
8080 if (pos == buf_epos_) {
return buf_size(); }
8081 if (buf_[pos] == c) {
break; }
8085 auto remaining_size = buf_epos_ - pos;
8086 if (s.size() > remaining_size) {
return buf_size(); }
8088 if (start_with(buf_, pos, buf_epos_, s)) {
return pos - buf_spos_; }
8096 void buf_append(
const char *data,
size_t n) {
8097 auto remaining_size = buf_size();
8098 if (remaining_size > 0 && buf_spos_ > 0) {
8099 for (
size_t i = 0; i < remaining_size; i++) {
8100 buf_[i] = buf_[buf_spos_ + i];
8104 buf_epos_ = remaining_size;
8106 if (remaining_size + n > buf_.size()) { buf_.resize(remaining_size + n); }
8108 for (
size_t i = 0; i < n; i++) {
8109 buf_[buf_epos_ + i] = data[i];
8114 void buf_erase(
size_t size) { buf_spos_ += size; }
8117 size_t buf_spos_ = 0;
8118 size_t buf_epos_ = 0;
8122 constexpr const char data[] =
8123 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
8125 thread_local auto engine([]() {
8129 std::random_device seed_gen;
8131 std::seed_seq seed_sequence{seed_gen(), seed_gen(), seed_gen(), seed_gen()};
8132 return std::mt19937(seed_sequence);
8136 for (
size_t i = 0; i < length; i++) {
8137 result += data[engine() % (
sizeof(data) - 1)];
8148 for (
size_t i = 0; i < boundary.size(); i++) {
8149 auto c = boundary[i];
8150 if (!std::isalnum(c) && c !=
'-' && c !=
'_') {
8158template <
typename T>
8161 const std::string &boundary) {
8162 std::string body =
"--" + boundary +
"\r\n";
8163 body +=
"Content-Disposition: form-data; name=\"" + item.name +
"\"";
8164 if (!item.filename.empty()) {
8165 body +=
"; filename=\"" + item.filename +
"\"";
8168 if (!item.content_type.empty()) {
8169 body +=
"Content-Type: " + item.content_type +
"\r\n";
8180 return "--" + boundary +
"--\r\n";
8185 return "multipart/form-data; boundary=" + boundary;
8190 const std::string &boundary,
bool finish =
true) {
8193 for (
const auto &item : items) {
8204 const std::string &boundary) {
8206 for (
const auto &item : items) {
8208 total += item.content.size();
8224 const std::string &boundary) {
8226 std::vector<std::string> owned;
8227 owned.reserve(items.size() + 1);
8228 for (
const auto &item : items)
8233 std::vector<MultipartSegment> segs;
8234 segs.reserve(items.size() * 3 + 1);
8235 static const char crlf[] =
"\r\n";
8236 for (
size_t i = 0; i < items.size(); i++) {
8237 segs.push_back({owned[i].data(), owned[i].size()});
8238 segs.push_back({items[i].content.data(), items[i].content.size()});
8239 segs.push_back({crlf, 2});
8241 segs.push_back({owned.back().data(), owned.back().size()});
8243 struct MultipartState {
8244 std::vector<std::string> owned;
8245 std::vector<MultipartSegment> segs;
8247 auto state = std::make_shared<MultipartState>();
8248 state->owned = std::move(owned);
8251 state->segs = std::move(segs);
8253 return [state](
size_t offset,
size_t length,
DataSink &sink) ->
bool {
8255 for (
const auto &seg : state->segs) {
8258 if (seg.size > 0 && offset - pos < seg.size) {
8259 size_t seg_offset = offset - pos;
8260 size_t available = seg.size - seg_offset;
8261 size_t to_write = (std::min)(available, length);
8262 return sink.write(seg.data + seg_offset, to_write);
8271 if (ranges.size() <= 1)
return;
8274 std::sort(ranges.begin(), ranges.end(),
8275 [](
const Range &a,
const Range &b) { return a.first < b.first; });
8278 coalesced.reserve(ranges.size());
8280 for (
auto &r : ranges) {
8281 auto first_pos = r.first;
8282 auto last_pos = r.second;
8285 if (first_pos == -1 && last_pos == -1) {
8287 last_pos =
static_cast<ssize_t
>(content_length);
8290 if (first_pos == -1) {
8291 first_pos =
static_cast<ssize_t
>(content_length) - last_pos;
8292 last_pos =
static_cast<ssize_t
>(content_length) - 1;
8295 if (last_pos == -1 || last_pos >=
static_cast<ssize_t
>(content_length)) {
8296 last_pos =
static_cast<ssize_t
>(content_length) - 1;
8300 if (!(0 <= first_pos && first_pos <= last_pos &&
8301 last_pos <
static_cast<ssize_t
>(content_length))) {
8307 if (!coalesced.empty()) {
8308 auto &prev = coalesced.back();
8311 if (first_pos <= prev.second + 1 &&
8312 !(first_pos == prev.first && last_pos == prev.second)) {
8314 prev.second = (std::max)(prev.second, last_pos);
8320 coalesced.emplace_back(first_pos, last_pos);
8323 ranges = std::move(coalesced);
8328 ssize_t content_len =
static_cast<ssize_t
>(
8331 std::vector<std::pair<ssize_t, ssize_t>> processed_ranges;
8332 size_t overwrapping_count = 0;
8341 for (
auto &r : req.
ranges) {
8342 auto &first_pos = r.first;
8343 auto &last_pos = r.second;
8345 if (first_pos == -1 && last_pos == -1) {
8347 last_pos = content_len;
8350 if (first_pos == -1) {
8351 first_pos = content_len - last_pos;
8352 last_pos = content_len - 1;
8364 if (last_pos == -1 || last_pos >= content_len) {
8365 last_pos = content_len - 1;
8369 if (!(0 <= first_pos && first_pos <= last_pos &&
8370 last_pos <= content_len - 1)) {
8375 for (
const auto &processed_range : processed_ranges) {
8376 if (!(last_pos < processed_range.first ||
8377 first_pos > processed_range.second)) {
8378 overwrapping_count++;
8379 if (overwrapping_count > 2) {
return true; }
8384 processed_ranges.emplace_back(first_pos, last_pos);
8394inline std::pair<size_t, size_t>
8396 assert(r.first != -1 && r.second != -1);
8397 assert(0 <= r.first && r.first <
static_cast<ssize_t
>(content_length));
8398 assert(r.first <= r.second &&
8399 r.second <
static_cast<ssize_t
>(content_length));
8400 (void)(content_length);
8401 return std::make_pair(
static_cast<size_t>(r.first),
8402 static_cast<size_t>(r.second - r.first) + 1);
8406 const std::pair<size_t, size_t> &offset_and_length,
size_t content_length) {
8407 auto st = offset_and_length.first;
8408 auto ed = st + offset_and_length.second - 1;
8410 std::string field =
"bytes ";
8411 field += std::to_string(st);
8413 field += std::to_string(ed);
8415 field += std::to_string(content_length);
8419template <
typename SToken,
typename CToken,
typename Content>
8421 const std::string &boundary,
8422 const std::string &content_type,
8423 size_t content_length, SToken stoken,
8424 CToken ctoken, Content content) {
8425 for (
size_t i = 0; i < req.
ranges.size(); i++) {
8429 if (!content_type.empty()) {
8430 ctoken(
"Content-Type: ");
8431 stoken(content_type);
8435 auto offset_and_length =
8438 ctoken(
"Content-Range: ");
8443 if (!content(offset_and_length.first, offset_and_length.second)) {
8457 const std::string &boundary,
8458 const std::string &content_type,
8459 size_t content_length,
8460 std::string &data) {
8462 req, boundary, content_type, content_length,
8463 [&](
const std::string &token) { data += token; },
8464 [&](
const std::string &token) { data += token; },
8465 [&](
size_t offset,
size_t length) {
8466 assert(offset + length <= content_length);
8467 data += res.
body.substr(offset, length);
8473 const std::string &boundary,
8474 const std::string &content_type,
8475 size_t content_length) {
8476 size_t data_length = 0;
8479 req, boundary, content_type, content_length,
8480 [&](
const std::string &token) { data_length += token.size(); },
8481 [&](
const std::string &token) { data_length += token.size(); },
8482 [&](
size_t ,
size_t length) {
8483 data_length += length;
8490template <
typename T>
8493 const std::string &boundary,
8494 const std::string &content_type,
8495 size_t content_length,
const T &is_shutting_down) {
8497 req, boundary, content_type, content_length,
8498 [&](
const std::string &token) { strm.
write(token); },
8499 [&](
const std::string &token) { strm.
write(token); },
8500 [&](
size_t offset,
size_t length) {
8508 req.
method ==
"DELETE") {
8524 if (WSAStartup(0x0002, &wsaData) == 0) is_valid_ =
true;
8528 if (is_valid_) WSACleanup();
8531 bool is_valid_ =
false;
8534static WSInit wsinit_;
8538 std::map<std::string, std::string> &auth,
8540 auto auth_key = is_proxy ?
"Proxy-Authenticate" :
"WWW-Authenticate";
8542 thread_local auto re =
8543 std::regex(R
"~((?:(?:,\s*)?(.+?)=(?:"(.*?)"|([^,]*))))~");
8545 auto pos = s.find(
' ');
8546 if (pos != std::string::npos) {
8547 auto type = s.substr(0, pos);
8548 if (type ==
"Basic") {
8550 }
else if (type ==
"Digest") {
8551 s = s.substr(pos + 1);
8552 auto beg = std::sregex_iterator(s.begin(), s.end(), re);
8553 for (
auto i = beg; i != std::sregex_iterator(); ++i) {
8555 auto key = s.substr(
static_cast<size_t>(m.position(1)),
8556 static_cast<size_t>(m.length(1)));
8557 auto val = m.length(2) > 0
8558 ? s.substr(
static_cast<size_t>(m.position(2)),
8559 static_cast<size_t>(m.length(2)))
8560 : s.substr(
static_cast<size_t>(m.position(3)),
8561 static_cast<size_t>(m.length(3)));
8562 auth[std::move(key)] = std::move(val);
8575 : content_provider_(std::move(content_provider)) {}
8578 return content_provider_(offset, sink);
8589 return std::isalnum(c) || c ==
'!' || c ==
'#' || c ==
'$' || c ==
'%' ||
8590 c ==
'&' || c ==
'\'' || c ==
'*' || c ==
'+' || c ==
'-' ||
8591 c ==
'.' || c ==
'^' || c ==
'_' || c ==
'`' || c ==
'|' || c ==
'~';
8595 if (s.empty()) {
return false; }
8604inline bool is_vchar(
char c) {
return c >= 33 && c <= 126; }
8606inline bool is_obs_text(
char c) {
return 128 <=
static_cast<unsigned char>(c); }
8611 if (s.empty()) {
return true; }
8613 if (s.size() == 1) {
8615 }
else if (s.size() == 2) {
8623 while (i < s.size() - 1) {
8640 int port,
const std::string &path,
8642 std::string &selected_subprotocol) {
8649 for (
const auto &h : headers) {
8656 thread_local std::mt19937 rng(std::random_device{}());
8657 std::string key_bytes(16,
'\0');
8658 for (
size_t i = 0; i < 16; i += 4) {
8660 std::memcpy(&key_bytes[i], &r, (std::min)(
size_t(4),
size_t(16 - i)));
8665 std::string req_str =
"GET " + path +
" HTTP/1.1\r\n";
8666 req_str +=
"Host: " + host +
":" + std::to_string(port) +
"\r\n";
8667 req_str +=
"Upgrade: websocket\r\n";
8668 req_str +=
"Connection: Upgrade\r\n";
8669 req_str +=
"Sec-WebSocket-Key: " + client_key +
"\r\n";
8670 req_str +=
"Sec-WebSocket-Version: 13\r\n";
8671 for (
const auto &h : headers) {
8672 req_str += h.first +
": " + h.second +
"\r\n";
8676 if (strm.
write(req_str.data(), req_str.size()) < 0) {
return false; }
8681 selected_subprotocol);
8690#ifdef CPPHTTPLIB_SSL_ENABLED
8693class SSLSocketStream final :
public Stream {
8696 socket_t sock, tls::session_t session, time_t read_timeout_sec,
8697 time_t read_timeout_usec, time_t write_timeout_sec,
8698 time_t write_timeout_usec, time_t max_timeout_msec = 0,
8699 std::chrono::time_point<std::chrono::steady_clock> start_time =
8700 (std::chrono::steady_clock::time_point::min)());
8701 ~SSLSocketStream()
override;
8703 bool is_readable()
const override;
8704 bool wait_readable()
const override;
8705 bool wait_writable()
const override;
8706 bool is_peer_alive()
const override;
8707 ssize_t read(
char *ptr,
size_t size)
override;
8708 ssize_t write(
const char *ptr,
size_t size)
override;
8709 void get_remote_ip_and_port(std::string &ip,
int &port)
const override;
8710 void get_local_ip_and_port(std::string &ip,
int &port)
const override;
8712 time_t duration()
const override;
8713 void set_read_timeout(time_t sec, time_t usec = 0)
override;
8717 tls::session_t session_;
8718 time_t read_timeout_sec_;
8719 time_t read_timeout_usec_;
8720 time_t write_timeout_sec_;
8721 time_t write_timeout_usec_;
8722 time_t max_timeout_msec_;
8723 const std::chrono::time_point<std::chrono::steady_clock> start_time_;
8726#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
8727inline std::string message_digest(
const std::string &s,
const EVP_MD *algo) {
8728 auto context = std::unique_ptr<EVP_MD_CTX, decltype(&EVP_MD_CTX_free)>(
8729 EVP_MD_CTX_new(), EVP_MD_CTX_free);
8731 unsigned int hash_length = 0;
8732 unsigned char hash[EVP_MAX_MD_SIZE];
8734 EVP_DigestInit_ex(context.get(), algo,
nullptr);
8735 EVP_DigestUpdate(context.get(), s.c_str(), s.size());
8736 EVP_DigestFinal_ex(context.get(), hash, &hash_length);
8738 std::stringstream ss;
8739 for (
auto i = 0u; i < hash_length; ++i) {
8740 ss << std::hex << std::setw(2) << std::setfill(
'0')
8741 <<
static_cast<unsigned int>(hash[i]);
8747inline std::string MD5(
const std::string &s) {
8748 return message_digest(s, EVP_md5());
8751inline std::string SHA_256(
const std::string &s) {
8752 return message_digest(s, EVP_sha256());
8755inline std::string SHA_512(
const std::string &s) {
8756 return message_digest(s, EVP_sha512());
8758#elif defined(CPPHTTPLIB_MBEDTLS_SUPPORT)
8761inline std::string hash_to_hex(
const unsigned char (&hash)[N]) {
8762 std::stringstream ss;
8763 for (
size_t i = 0; i < N; ++i) {
8764 ss << std::hex << std::setw(2) << std::setfill(
'0')
8765 <<
static_cast<unsigned int>(hash[i]);
8771inline std::string MD5(
const std::string &s) {
8772 unsigned char hash[16];
8773#ifdef CPPHTTPLIB_MBEDTLS_V3
8774 mbedtls_md5(
reinterpret_cast<const unsigned char *
>(s.c_str()), s.size(),
8777 mbedtls_md5_ret(
reinterpret_cast<const unsigned char *
>(s.c_str()), s.size(),
8780 return hash_to_hex(hash);
8783inline std::string SHA_256(
const std::string &s) {
8784 unsigned char hash[32];
8785#ifdef CPPHTTPLIB_MBEDTLS_V3
8786 mbedtls_sha256(
reinterpret_cast<const unsigned char *
>(s.c_str()), s.size(),
8789 mbedtls_sha256_ret(
reinterpret_cast<const unsigned char *
>(s.c_str()),
8792 return hash_to_hex(hash);
8795inline std::string SHA_512(
const std::string &s) {
8796 unsigned char hash[64];
8797#ifdef CPPHTTPLIB_MBEDTLS_V3
8798 mbedtls_sha512(
reinterpret_cast<const unsigned char *
>(s.c_str()), s.size(),
8801 mbedtls_sha512_ret(
reinterpret_cast<const unsigned char *
>(s.c_str()),
8804 return hash_to_hex(hash);
8806#elif defined(CPPHTTPLIB_WOLFSSL_SUPPORT)
8809inline std::string hash_to_hex(
const unsigned char (&hash)[N]) {
8810 std::stringstream ss;
8811 for (
size_t i = 0; i < N; ++i) {
8812 ss << std::hex << std::setw(2) << std::setfill(
'0')
8813 <<
static_cast<unsigned int>(hash[i]);
8819inline std::string MD5(
const std::string &s) {
8820 unsigned char hash[WC_MD5_DIGEST_SIZE];
8821 wc_Md5Hash(
reinterpret_cast<const unsigned char *
>(s.c_str()),
8822 static_cast<word32
>(s.size()), hash);
8823 return hash_to_hex(hash);
8826inline std::string SHA_256(
const std::string &s) {
8827 unsigned char hash[WC_SHA256_DIGEST_SIZE];
8828 wc_Sha256Hash(
reinterpret_cast<const unsigned char *
>(s.c_str()),
8829 static_cast<word32
>(s.size()), hash);
8830 return hash_to_hex(hash);
8833inline std::string SHA_512(
const std::string &s) {
8834 unsigned char hash[WC_SHA512_DIGEST_SIZE];
8835 wc_Sha512Hash(
reinterpret_cast<const unsigned char *
>(s.c_str()),
8836 static_cast<word32
>(s.size()), hash);
8837 return hash_to_hex(hash);
8841inline bool is_ip_address(
const std::string &host) {
8842 struct in_addr addr4;
8843 struct in6_addr addr6;
8844 return inet_pton(AF_INET, host.c_str(), &addr4) == 1 ||
8845 inet_pton(AF_INET6, host.c_str(), &addr6) == 1;
8848template <
typename T>
8849inline bool process_server_socket_ssl(
8850 const std::atomic<socket_t> &svr_sock, tls::session_t session,
8851 socket_t sock,
size_t keep_alive_max_count, time_t keep_alive_timeout_sec,
8852 time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec,
8853 time_t write_timeout_usec, T callback) {
8855 svr_sock, sock, keep_alive_max_count, keep_alive_timeout_sec,
8856 [&](
bool close_connection,
bool &connection_closed) {
8857 SSLSocketStream strm(sock, session, read_timeout_sec, read_timeout_usec,
8858 write_timeout_sec, write_timeout_usec);
8859 return callback(strm, close_connection, connection_closed);
8863template <
typename T>
8864inline bool process_client_socket_ssl(
8865 tls::session_t session,
socket_t sock, time_t read_timeout_sec,
8866 time_t read_timeout_usec, time_t write_timeout_sec,
8867 time_t write_timeout_usec, time_t max_timeout_msec,
8868 std::chrono::time_point<std::chrono::steady_clock> start_time, T callback) {
8869 SSLSocketStream strm(sock, session, read_timeout_sec, read_timeout_usec,
8870 write_timeout_sec, write_timeout_usec, max_timeout_msec,
8872 return callback(strm);
8875inline std::pair<std::string, std::string> make_digest_authentication_header(
8876 const Request &req,
const std::map<std::string, std::string> &auth,
8877 size_t cnonce_count,
const std::string &cnonce,
const std::string &username,
8878 const std::string &password,
bool is_proxy =
false) {
8881 std::stringstream ss;
8882 ss << std::setfill(
'0') << std::setw(8) << std::hex << cnonce_count;
8887 if (auth.find(
"qop") != auth.end()) {
8888 qop = auth.at(
"qop");
8889 if (qop.find(
"auth-int") != std::string::npos) {
8891 }
else if (qop.find(
"auth") != std::string::npos) {
8898 std::string algo =
"MD5";
8899 if (auth.find(
"algorithm") != auth.end()) { algo = auth.at(
"algorithm"); }
8901 std::string response;
8903 auto H = algo ==
"SHA-256" ? detail::SHA_256
8904 : algo ==
"SHA-512" ? detail::SHA_512
8907 auto A1 = username +
":" + auth.at(
"realm") +
":" + password;
8909 auto A2 = req.method +
":" + req.path;
8910 if (qop ==
"auth-int") { A2 +=
":" + H(req.body); }
8913 response = H(H(A1) +
":" + auth.at(
"nonce") +
":" + H(A2));
8915 response = H(H(A1) +
":" + auth.at(
"nonce") +
":" + nc +
":" + cnonce +
8916 ":" + qop +
":" + H(A2));
8920 auto opaque = (auth.find(
"opaque") != auth.end()) ? auth.at(
"opaque") :
"";
8922 auto field =
"Digest username=\"" + username +
"\", realm=\"" +
8923 auth.at(
"realm") +
"\", nonce=\"" + auth.at(
"nonce") +
8924 "\", uri=\"" + req.path +
"\", algorithm=" + algo +
8925 (qop.empty() ?
", response=\""
8926 :
", qop=" + qop +
", nc=" + nc +
", cnonce=\"" +
8927 cnonce +
"\", response=\"") +
8929 (opaque.empty() ?
"" :
", opaque=\"" + opaque +
"\"");
8931 auto key = is_proxy ?
"Proxy-Authorization" :
"Authorization";
8932 return std::make_pair(key, field);
8935inline bool match_hostname(
const std::string &pattern,
8936 const std::string &hostname) {
8938 if (detail::case_ignore::equal(hostname, pattern)) {
return true; }
8941 std::vector<std::string> pattern_components;
8942 if (!pattern.empty()) {
8943 split(pattern.data(), pattern.data() + pattern.size(),
'.',
8944 [&](
const char *b,
const char *e) {
8945 pattern_components.emplace_back(b, e);
8949 std::vector<std::string> host_components;
8950 if (!hostname.empty()) {
8951 split(hostname.data(), hostname.data() + hostname.size(),
'.',
8952 [&](
const char *b,
const char *e) {
8953 host_components.emplace_back(b, e);
8958 if (host_components.size() != pattern_components.size()) {
return false; }
8963 auto itr = pattern_components.begin();
8964 for (
const auto &h : host_components) {
8966 if (!detail::case_ignore::equal(p, h) && p !=
"*") {
8967 bool partial_match =
false;
8968 if (!p.empty() && p[p.size() - 1] ==
'*') {
8969 const auto prefix_length = p.size() - 1;
8970 if (prefix_length == 0) {
8971 partial_match =
true;
8972 }
else if (h.size() >= prefix_length) {
8974 std::equal(p.begin(),
8975 p.begin() +
static_cast<std::string::difference_type
>(
8977 h.begin(), [](
const char ca,
const char cb) {
8978 return detail::case_ignore::to_lower(ca) ==
8979 detail::case_ignore::to_lower(cb);
8983 if (!partial_match) {
return false; }
8996verify_cert_with_windows_schannel(
const std::vector<unsigned char> &der_cert,
8997 const std::string &hostname,
8998 bool verify_hostname, uint64_t &out_error) {
8999 if (der_cert.empty()) {
return false; }
9004 auto cert_context = CertCreateCertificateContext(
9005 X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, der_cert.data(),
9006 static_cast<DWORD
>(der_cert.size()));
9008 if (!cert_context) {
9009 out_error = GetLastError();
9014 scope_exit([&] { CertFreeCertificateContext(cert_context); });
9017 CERT_CHAIN_PARA chain_para = {};
9018 chain_para.cbSize =
sizeof(chain_para);
9021 PCCERT_CHAIN_CONTEXT chain_context =
nullptr;
9022 auto chain_result = CertGetCertificateChain(
9023 nullptr, cert_context,
nullptr, cert_context->hCertStore, &chain_para,
9024 CERT_CHAIN_CACHE_END_CERT | CERT_CHAIN_REVOCATION_CHECK_END_CERT |
9025 CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT,
9026 nullptr, &chain_context);
9028 if (!chain_result || !chain_context) {
9029 out_error = GetLastError();
9034 scope_exit([&] { CertFreeCertificateChain(chain_context); });
9037 if (chain_context->TrustStatus.dwErrorStatus != CERT_TRUST_NO_ERROR) {
9038 out_error = chain_context->TrustStatus.dwErrorStatus;
9043 SSL_EXTRA_CERT_CHAIN_POLICY_PARA extra_policy_para = {};
9044 extra_policy_para.cbSize =
sizeof(extra_policy_para);
9045#ifdef AUTHTYPE_SERVER
9046 extra_policy_para.dwAuthType = AUTHTYPE_SERVER;
9050 if (verify_hostname) {
9051 whost = u8string_to_wstring(hostname.c_str());
9052 extra_policy_para.pwszServerName =
const_cast<wchar_t *
>(whost.c_str());
9055 CERT_CHAIN_POLICY_PARA policy_para = {};
9056 policy_para.cbSize =
sizeof(policy_para);
9057#ifdef CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS
9058 policy_para.dwFlags = CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS;
9060 policy_para.dwFlags = 0;
9062 policy_para.pvExtraPolicyPara = &extra_policy_para;
9064 CERT_CHAIN_POLICY_STATUS policy_status = {};
9065 policy_status.cbSize =
sizeof(policy_status);
9067 if (!CertVerifyCertificateChainPolicy(CERT_CHAIN_POLICY_SSL, chain_context,
9068 &policy_para, &policy_status)) {
9069 out_error = GetLastError();
9073 if (policy_status.dwError != 0) {
9074 out_error = policy_status.dwError;
9082inline bool setup_client_tls_session(
const std::string &host, tls::ctx_t &ctx,
9083 tls::session_t &session,
socket_t sock,
9084 bool server_certificate_verification,
9085 const std::string &ca_cert_file_path,
9086 tls::ca_store_t ca_cert_store,
9087 time_t timeout_sec, time_t timeout_usec) {
9088 using namespace tls;
9090 ctx = create_client_context();
9091 if (!ctx) {
return false; }
9093 if (server_certificate_verification) {
9094 if (!ca_cert_file_path.empty()) {
9095 load_ca_file(ctx, ca_cert_file_path.c_str());
9097 if (ca_cert_store) { set_ca_store(ctx, ca_cert_store); }
9098 load_system_certs(ctx);
9101 bool is_ip = is_ip_address(host);
9103#ifdef CPPHTTPLIB_MBEDTLS_SUPPORT
9104 if (is_ip && server_certificate_verification) {
9105 set_verify_client(ctx,
false);
9107 set_verify_client(ctx, server_certificate_verification);
9111 session = create_session(ctx, sock);
9112 if (!session) {
return false; }
9115 if (!is_ip) { set_sni(session, host.c_str()); }
9116 if (server_certificate_verification) { set_hostname(session, host.c_str()); }
9118 if (!connect_nonblocking(session, sock, timeout_sec, timeout_usec,
nullptr)) {
9122 if (server_certificate_verification) {
9123 if (get_verify_result(session) != 0) {
return false; }
9150 .substr(bearer_header_prefix_len);
9165 return "Non-Authoritative Information";
9189 return "Proxy Authentication Required";
9210 return "Request Header Fields Too Large";
9212 return "Unavailable For Legal Reasons";
9218 return "HTTP Version Not Supported";
9224 return "Network Authentication Required";
9237 case Error::Read:
return "Failed to read connection";
9238 case Error::Write:
return "Failed to write connection";
9245 return "SSL server hostname verification failed";
9247 return "Unsupported HTTP multipart boundary characters";
9258 return "Exceeded maximum socket descriptor count";
9278 os <<
" (" <<
static_cast<std::underlying_type<Error>::type
>(obj) <<
')';
9283 std::vector<std::string> addrs;
9285 if (addrs.empty()) {
return std::string(); }
9290 std::vector<std::string> &addrs) {
9291 struct addrinfo hints;
9292 struct addrinfo *result;
9294 memset(&hints, 0,
sizeof(
struct addrinfo));
9295 hints.ai_family = AF_UNSPEC;
9296 hints.ai_socktype = SOCK_STREAM;
9297 hints.ai_protocol = 0;
9301#if defined __linux__ && !defined __ANDROID__
9308 for (
auto rp = result; rp; rp = rp->ai_next) {
9310 *
reinterpret_cast<struct sockaddr_storage *
>(rp->ai_addr);
9315 addrs.emplace_back(std::move(ip));
9321 std::ostringstream escaped;
9323 escaped << std::hex;
9325 for (
auto c : value) {
9326 if (std::isalnum(
static_cast<uint8_t
>(c)) || c ==
'-' || c ==
'_' ||
9327 c ==
'.' || c ==
'!' || c ==
'~' || c ==
'*' || c ==
'\'' || c ==
'(' ||
9331 escaped << std::uppercase;
9332 escaped <<
'%' << std::setw(2)
9333 <<
static_cast<int>(
static_cast<unsigned char>(c));
9334 escaped << std::nouppercase;
9338 return escaped.str();
9342 std::ostringstream escaped;
9344 escaped << std::hex;
9346 for (
auto c : value) {
9347 if (std::isalnum(
static_cast<uint8_t
>(c)) || c ==
'-' || c ==
'_' ||
9348 c ==
'.' || c ==
'!' || c ==
'~' || c ==
'*' || c ==
'\'' || c ==
'(' ||
9349 c ==
')' || c ==
';' || c ==
'/' || c ==
'?' || c ==
':' || c ==
'@' ||
9350 c ==
'&' || c ==
'=' || c ==
'+' || c ==
'$' || c ==
',' || c ==
'#') {
9353 escaped << std::uppercase;
9354 escaped <<
'%' << std::setw(2)
9355 <<
static_cast<int>(
static_cast<unsigned char>(c));
9356 escaped << std::nouppercase;
9360 return escaped.str();
9366 for (
size_t i = 0; i < value.size(); i++) {
9367 if (value[i] ==
'%' && i + 2 < value.size()) {
9370 result +=
static_cast<char>(val);
9386 for (
size_t i = 0; i < value.size(); i++) {
9387 if (value[i] ==
'%' && i + 2 < value.size()) {
9390 result +=
static_cast<char>(val);
9405 result.reserve(component.size() * 3);
9407 for (
size_t i = 0; i < component.size(); i++) {
9408 auto c =
static_cast<unsigned char>(component[i]);
9411 if (std::isalnum(c) || c ==
'-' || c ==
'.' || c ==
'_' || c ==
'~') {
9412 result +=
static_cast<char>(c);
9416 else if (c ==
'!' || c ==
'$' || c ==
'&' || c ==
'\'' || c ==
'(' ||
9417 c ==
')' || c ==
'*' || c ==
'+' || c ==
',' || c ==
';' ||
9419 result +=
static_cast<char>(c);
9422 else if (c ==
':') {
9423 result +=
static_cast<char>(c);
9426 else if (c ==
'@') {
9427 result +=
static_cast<char>(c);
9431 snprintf(hex,
sizeof(hex),
"%02X", c);
9432 result.append(hex, 2);
9440 result.reserve(component.size());
9442 for (
size_t i = 0; i < component.size(); i++) {
9443 if (component[i] ==
'%' && i + 1 < component.size()) {
9444 if (component[i + 1] ==
'u') {
9452 if (len > 0) { result.append(buff, len); }
9455 result += component[i];
9462 result +=
static_cast<char>(val);
9465 result += component[i];
9469 result += component[i];
9476 bool space_as_plus) {
9478 result.reserve(component.size() * 3);
9480 for (
size_t i = 0; i < component.size(); i++) {
9481 auto c =
static_cast<unsigned char>(component[i]);
9484 if (std::isalnum(c) || c ==
'-' || c ==
'.' || c ==
'_' || c ==
'~') {
9485 result +=
static_cast<char>(c);
9488 else if (c ==
' ') {
9489 if (space_as_plus) {
9496 else if (c ==
'+') {
9497 if (space_as_plus) {
9500 result +=
static_cast<char>(c);
9504 else if (c ==
'!' || c ==
'$' || c ==
'\'' || c ==
'(' || c ==
')' ||
9505 c ==
'*' || c ==
',' || c ==
';') {
9506 result +=
static_cast<char>(c);
9509 else if (c ==
':' || c ==
'@') {
9510 result +=
static_cast<char>(c);
9513 else if (c ==
'/') {
9514 result +=
static_cast<char>(c);
9517 else if (c ==
'?') {
9518 result +=
static_cast<char>(c);
9522 snprintf(hex,
sizeof(hex),
"%02X", c);
9523 result.append(hex, 2);
9530 bool plus_as_space) {
9532 result.reserve(component.size());
9534 for (
size_t i = 0; i < component.size(); i++) {
9535 if (component[i] ==
'%' && i + 2 < component.size()) {
9536 std::string hex = component.substr(i + 1, 2);
9538 unsigned long value = std::strtoul(hex.c_str(), &end, 16);
9539 if (end == hex.c_str() + 2) {
9540 result +=
static_cast<char>(value);
9543 result += component[i];
9545 }
else if (component[i] ==
'+' && plus_as_space) {
9548 result += component[i];
9556 auto pos = filename.find_last_of(
"/\\");
9558 (pos != std::string::npos) ? filename.substr(pos + 1) : filename;
9561 result.erase(std::remove(result.begin(), result.end(),
'\0'), result.end());
9565 auto start = result.find_first_not_of(
" \t");
9566 auto end = result.find_last_not_of(
" \t");
9567 result = (start == std::string::npos)
9569 : result.substr(start, end - start + 1);
9573 if (result ==
"." || result ==
"..") {
return ""; }
9580 std::string path_with_query = path;
9581 thread_local const std::regex re(
"[^?]+\\?.*");
9582 auto delm = std::regex_match(path, re) ?
'&' :
'?';
9584 return path_with_query;
9588inline std::pair<std::string, std::string>
9590 std::string field =
"bytes=";
9592 for (
const auto &r : ranges) {
9593 if (i != 0) { field +=
", "; }
9594 if (r.first != -1) { field += std::to_string(r.first); }
9596 if (r.second != -1) { field += std::to_string(r.second); }
9599 return std::make_pair(
"Range", std::move(field));
9602inline std::pair<std::string, std::string>
9604 const std::string &password,
bool is_proxy) {
9606 auto key = is_proxy ?
"Proxy-Authorization" :
"Authorization";
9607 return std::make_pair(key, std::move(field));
9610inline std::pair<std::string, std::string>
9612 bool is_proxy =
false) {
9613 auto field =
"Bearer " + token;
9614 auto key = is_proxy ?
"Proxy-Authorization" :
"Authorization";
9615 return std::make_pair(key, std::move(field));
9629 const char *def,
size_t id)
const {
9634 auto r =
headers.equal_range(key);
9635 return static_cast<size_t>(std::distance(r.first, r.second));
9639 const std::string &val) {
9652 auto rng =
trailers.equal_range(key);
9653 auto it = rng.first;
9654 std::advance(it,
static_cast<ssize_t
>(
id));
9655 if (it != rng.second) {
return it->second; }
9656 return std::string();
9660 auto r =
trailers.equal_range(key);
9661 return static_cast<size_t>(std::distance(r.first, r.second));
9670 auto rng =
params.equal_range(key);
9671 auto it = rng.first;
9672 std::advance(it,
static_cast<ssize_t
>(
id));
9673 if (it != rng.second) {
return it->second; }
9674 return std::string();
9678 auto r =
params.equal_range(key);
9679 return static_cast<size_t>(std::distance(r.first, r.second));
9690 auto rng =
fields.equal_range(key);
9691 auto it = rng.first;
9692 std::advance(it,
static_cast<ssize_t
>(
id));
9693 if (it != rng.second) {
return it->second.content; }
9694 return std::string();
9697inline std::vector<std::string>
9699 std::vector<std::string> values;
9700 auto rng =
fields.equal_range(key);
9701 for (
auto it = rng.first; it != rng.second; it++) {
9702 values.push_back(it->second.content);
9712 auto r =
fields.equal_range(key);
9713 return static_cast<size_t>(std::distance(r.first, r.second));
9718 auto rng =
files.equal_range(key);
9719 auto it = rng.first;
9720 std::advance(it,
static_cast<ssize_t
>(
id));
9721 if (it != rng.second) {
return it->second; }
9725inline std::vector<FormData>
9727 std::vector<FormData> values;
9728 auto rng =
files.equal_range(key);
9729 for (
auto it = rng.first; it != rng.second; it++) {
9730 values.push_back(it->second);
9740 auto r =
files.equal_range(key);
9741 return static_cast<size_t>(std::distance(r.first, r.second));
9761 auto r =
headers.equal_range(key);
9762 return static_cast<size_t>(std::distance(r.first, r.second));
9766 const std::string &val) {
9778 auto rng =
trailers.equal_range(key);
9779 auto it = rng.first;
9780 std::advance(it,
static_cast<ssize_t
>(
id));
9781 if (it != rng.second) {
return it->second; }
9782 return std::string();
9786 auto r =
trailers.equal_range(key);
9787 return static_cast<size_t>(std::distance(r.first, r.second));
9793 if (300 <= stat && stat < 400) {
9802 const std::string &content_type) {
9805 auto rng =
headers.equal_range(
"Content-Type");
9806 headers.erase(rng.first, rng.second);
9811 const std::string &content_type) {
9816 const std::string &content_type) {
9817 body = std::move(s);
9819 auto rng =
headers.equal_range(
"Content-Type");
9820 headers.erase(rng.first, rng.second);
9825 size_t in_length,
const std::string &content_type,
ContentProvider provider,
9855 const std::string &content_type) {
9872 return request_headers_.find(key) != request_headers_.end();
9883 auto r = request_headers_.equal_range(key);
9884 return static_cast<size_t>(std::distance(r.first, r.second));
9889 return write(ptr, strlen(ptr));
9893 return write(s.data(), s.size());
9902 if (
eof) {
return 0; }
9914 to_read = (std::min)(len, remaining);
9916 auto n =
stream->read(buf, to_read);
9945 size_t chunk_offset = 0;
9946 size_t chunk_total = 0;
9947 auto n =
chunked_decoder->read_payload(buf, len, chunk_offset, chunk_total);
9972 : base_thread_count_(n), max_queued_requests_(mqr), idle_thread_count_(0),
9974#ifndef CPPHTTPLIB_NO_EXCEPTIONS
9975 if (max_n != 0 && max_n < n) {
9976 std::string msg =
"max_threads must be >= base_threads";
9977 throw std::invalid_argument(msg);
9980 max_thread_count_ = max_n == 0 ? n : max_n;
9981 threads_.reserve(base_thread_count_);
9982 for (
size_t i = 0; i < base_thread_count_; i++) {
9983 threads_.emplace_back(std::thread([
this]() { worker(
false); }));
9989 std::unique_lock<std::mutex> lock(mutex_);
9990 if (shutdown_) {
return false; }
9991 if (max_queued_requests_ > 0 && jobs_.size() >= max_queued_requests_) {
9994 jobs_.push_back(std::move(fn));
9997 if (idle_thread_count_ == 0 &&
9998 threads_.size() + dynamic_threads_.size() < max_thread_count_) {
9999 cleanup_finished_threads();
10000 dynamic_threads_.emplace_back(std::thread([
this]() { worker(
true); }));
10004 cond_.notify_one();
10010 std::unique_lock<std::mutex> lock(mutex_);
10014 cond_.notify_all();
10016 for (
auto &t : threads_) {
10017 if (t.joinable()) { t.join(); }
10022 std::list<std::thread> remaining_dynamic;
10024 std::unique_lock<std::mutex> lock(mutex_);
10025 remaining_dynamic = std::move(dynamic_threads_);
10027 for (
auto &t : remaining_dynamic) {
10028 if (t.joinable()) { t.join(); }
10031 std::unique_lock<std::mutex> lock(mutex_);
10032 cleanup_finished_threads();
10035inline void ThreadPool::move_to_finished(std::thread::id
id) {
10037 for (
auto it = dynamic_threads_.begin(); it != dynamic_threads_.end(); ++it) {
10038 if (it->get_id() ==
id) {
10039 finished_threads_.push_back(std::move(*it));
10040 dynamic_threads_.erase(it);
10046inline void ThreadPool::cleanup_finished_threads() {
10048 for (
auto &t : finished_threads_) {
10049 if (t.joinable()) { t.join(); }
10051 finished_threads_.clear();
10054inline void ThreadPool::worker(
bool is_dynamic) {
10056 std::function<void()> fn;
10058 std::unique_lock<std::mutex> lock(mutex_);
10059 idle_thread_count_++;
10062 auto has_work = cond_.wait_for(
10064 [&] {
return !jobs_.empty() || shutdown_; });
10067 idle_thread_count_--;
10068 move_to_finished(std::this_thread::get_id());
10072 cond_.wait(lock, [&] {
return !jobs_.empty() || shutdown_; });
10075 idle_thread_count_--;
10077 if (shutdown_ && jobs_.empty()) {
break; }
10079 fn = std::move(jobs_.front());
10083 assert(
true ==
static_cast<bool>(fn));
10088 std::unique_lock<std::mutex> lock(mutex_);
10089 if (jobs_.empty()) {
10090 move_to_finished(std::this_thread::get_id());
10096#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && !defined(OPENSSL_IS_BORINGSSL) && \
10097 !defined(LIBRESSL_VERSION_NUMBER)
10098 OPENSSL_thread_stop();
10109 time_t timeout_sec, time_t timeout_usec,
10110 time_t &actual_timeout_sec,
10111 time_t &actual_timeout_usec) {
10112 auto timeout_msec = (timeout_sec * 1000) + (timeout_usec / 1000);
10114 auto actual_timeout_msec =
10115 (std::min)(max_timeout_msec - duration_msec, timeout_msec);
10117 if (actual_timeout_msec < 0) { actual_timeout_msec = 0; }
10119 actual_timeout_sec = actual_timeout_msec / 1000;
10120 actual_timeout_usec = (actual_timeout_msec % 1000) * 1000;
10125 socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec,
10126 time_t write_timeout_sec, time_t write_timeout_usec,
10127 time_t max_timeout_msec,
10128 std::chrono::time_point<std::chrono::steady_clock> start_time)
10129 : sock_(sock), read_timeout_sec_(read_timeout_sec),
10130 read_timeout_usec_(read_timeout_usec),
10131 write_timeout_sec_(write_timeout_sec),
10132 write_timeout_usec_(write_timeout_usec),
10133 max_timeout_msec_(max_timeout_msec), start_time_(start_time),
10134 read_buff_(read_buff_size_, 0) {}
10139 return read_buff_off_ < read_buff_content_size_;
10143 if (max_timeout_msec_ <= 0) {
10144 return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
10147 time_t read_timeout_sec;
10148 time_t read_timeout_usec;
10150 read_timeout_usec_, read_timeout_sec, read_timeout_usec);
10152 return select_read(sock_, read_timeout_sec, read_timeout_usec) > 0;
10156 return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0;
10166 (std::min)(size,
static_cast<size_t>((std::numeric_limits<int>::max)()));
10168 size = (std::min)(size,
10169 static_cast<size_t>((std::numeric_limits<ssize_t>::max)()));
10172 if (read_buff_off_ < read_buff_content_size_) {
10173 auto remaining_size = read_buff_content_size_ - read_buff_off_;
10174 if (size <= remaining_size) {
10175 memcpy(ptr, read_buff_.data() + read_buff_off_, size);
10176 read_buff_off_ += size;
10177 return static_cast<ssize_t
>(size);
10179 memcpy(ptr, read_buff_.data() + read_buff_off_, remaining_size);
10180 read_buff_off_ += remaining_size;
10181 return static_cast<ssize_t
>(remaining_size);
10190 read_buff_off_ = 0;
10191 read_buff_content_size_ = 0;
10193 if (size < read_buff_size_) {
10194 auto n =
read_socket(sock_, read_buff_.data(), read_buff_size_,
10203 }
else if (n <=
static_cast<ssize_t
>(size)) {
10204 memcpy(ptr, read_buff_.data(),
static_cast<size_t>(n));
10207 memcpy(ptr, read_buff_.data(), size);
10208 read_buff_off_ = size;
10209 read_buff_content_size_ =
static_cast<size_t>(n);
10210 return static_cast<ssize_t
>(size);
10228#if defined(_WIN32) && !defined(_WIN64)
10230 (std::min)(size,
static_cast<size_t>((std::numeric_limits<int>::max)()));
10249 return std::chrono::duration_cast<std::chrono::milliseconds>(
10250 std::chrono::steady_clock::now() - start_time_)
10255 read_timeout_sec_ = sec;
10256 read_timeout_usec_ = usec;
10267#if defined(_MSC_VER) && _MSC_VER < 1910
10268 auto len_read = buffer._Copy_s(ptr, size, size, position);
10270 auto len_read = buffer.copy(ptr, size, position);
10272 position +=
static_cast<size_t>(len_read);
10273 return static_cast<ssize_t
>(len_read);
10277 buffer.append(ptr, size);
10278 return static_cast<ssize_t
>(size);
10295 constexpr const char marker[] =
"/:";
10298 std::size_t last_param_end = 0;
10300#ifndef CPPHTTPLIB_NO_EXCEPTIONS
10305 std::unordered_set<std::string> param_name_set;
10309 const auto marker_pos =
pattern.find(
10310 marker, last_param_end == 0 ? last_param_end : last_param_end - 1);
10311 if (marker_pos == std::string::npos) {
break; }
10313 static_fragments_.push_back(
10314 pattern.substr(last_param_end, marker_pos - last_param_end + 1));
10316 const auto param_name_start = marker_pos +
str_len(marker);
10318 auto sep_pos =
pattern.find(separator, param_name_start);
10319 if (sep_pos == std::string::npos) { sep_pos =
pattern.length(); }
10322 pattern.substr(param_name_start, sep_pos - param_name_start);
10324#ifndef CPPHTTPLIB_NO_EXCEPTIONS
10325 if (param_name_set.find(param_name) != param_name_set.cend()) {
10326 std::string msg =
"Encountered path parameter '" + param_name +
10327 "' multiple times in route pattern '" +
pattern +
"'.";
10328 throw std::invalid_argument(msg);
10332 param_names_.push_back(std::move(param_name));
10334 last_param_end = sep_pos + 1;
10337 if (last_param_end <
pattern.length()) {
10338 static_fragments_.push_back(pattern.substr(last_param_end));
10343 request.
matches = std::smatch();
10345 request.
path_params.reserve(param_names_.size());
10348 std::size_t starting_pos = 0;
10349 for (
size_t i = 0; i < static_fragments_.size(); ++i) {
10350 const auto &fragment = static_fragments_[i];
10352 if (starting_pos + fragment.length() > request.
path.length()) {
10358 if (std::strncmp(request.
path.c_str() + starting_pos, fragment.c_str(),
10359 fragment.length()) != 0) {
10363 starting_pos += fragment.length();
10368 if (i >= param_names_.size()) {
continue; }
10370 auto sep_pos = request.
path.find(separator, starting_pos);
10371 if (sep_pos == std::string::npos) { sep_pos = request.
path.length(); }
10373 const auto ¶m_name = param_names_[i];
10376 param_name, request.
path.substr(starting_pos, sep_pos - starting_pos));
10379 starting_pos = sep_pos + 1;
10382 return starting_pos >= request.
path.length();
10387 return std::regex_match(request.
path, request.
matches, regex_);
10393 if (host.find(
':') == std::string::npos ||
10394 (!host.empty() && host[0] ==
'[')) {
10399 return "[" + host +
"]";
10408 if ((!is_ssl && port == 80) || (is_ssl && port == 443)) {
10411 result +=
":" + std::to_string(port);
10423template <
typename T>
10425 T header_writer,
Error &error) {
10426 for (
const auto &h : headers) {
10433 if (header_writer(strm, headers) <= 0) {
10446#ifdef CPPHTTPLIB_SSL_ENABLED
10450inline SSLSocketStream::SSLSocketStream(
10451 socket_t sock, tls::session_t session, time_t read_timeout_sec,
10452 time_t read_timeout_usec, time_t write_timeout_sec,
10453 time_t write_timeout_usec, time_t max_timeout_msec,
10454 std::chrono::time_point<std::chrono::steady_clock> start_time)
10455 : sock_(sock), session_(session), read_timeout_sec_(read_timeout_sec),
10456 read_timeout_usec_(read_timeout_usec),
10457 write_timeout_sec_(write_timeout_sec),
10458 write_timeout_usec_(write_timeout_usec),
10459 max_timeout_msec_(max_timeout_msec), start_time_(start_time) {
10460#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
10466 SSL_clear_mode(
static_cast<SSL *
>(session), SSL_MODE_AUTO_RETRY);
10470inline SSLSocketStream::~SSLSocketStream() =
default;
10472inline bool SSLSocketStream::is_readable()
const {
10473 return tls::pending(session_) > 0;
10476inline bool SSLSocketStream::wait_readable()
const {
10477 if (max_timeout_msec_ <= 0) {
10478 return select_read(sock_, read_timeout_sec_, read_timeout_usec_) > 0;
10481 time_t read_timeout_sec;
10482 time_t read_timeout_usec;
10484 read_timeout_usec_, read_timeout_sec, read_timeout_usec);
10486 return select_read(sock_, read_timeout_sec, read_timeout_usec) > 0;
10489inline bool SSLSocketStream::wait_writable()
const {
10490 return select_write(sock_, write_timeout_sec_, write_timeout_usec_) > 0 &&
10491 !tls::is_peer_closed(session_, sock_);
10494inline bool SSLSocketStream::is_peer_alive()
const {
10495 return !tls::is_peer_closed(session_, sock_);
10498inline ssize_t SSLSocketStream::read(
char *ptr,
size_t size) {
10499 if (tls::pending(session_) > 0) {
10501 auto ret = tls::read(session_, ptr, size, err);
10502 if (ret == 0 || err.code == tls::ErrorCode::PeerClosed) {
10506 }
else if (wait_readable()) {
10508 auto ret = tls::read(session_, ptr, size, err);
10512 while (--n >= 0 && (err.code == tls::ErrorCode::WantRead ||
10513 (err.code == tls::ErrorCode::SyscallError &&
10514 WSAGetLastError() == WSAETIMEDOUT))) {
10516 while (--n >= 0 && err.code == tls::ErrorCode::WantRead) {
10518 if (tls::pending(session_) > 0) {
10519 return tls::read(session_, ptr, size, err);
10520 }
else if (wait_readable()) {
10521 std::this_thread::sleep_for(std::chrono::microseconds{10});
10522 ret = tls::read(session_, ptr, size, err);
10523 if (ret >= 0) {
return ret; }
10529 }
else if (ret == 0 || err.code == tls::ErrorCode::PeerClosed) {
10539inline ssize_t SSLSocketStream::write(
const char *ptr,
size_t size) {
10540 if (wait_writable()) {
10542 std::min<size_t>(size, (std::numeric_limits<int>::max)());
10545 auto ret = tls::write(session_, ptr, handle_size, err);
10549 while (--n >= 0 && (err.code == tls::ErrorCode::WantWrite ||
10550 (err.code == tls::ErrorCode::SyscallError &&
10551 WSAGetLastError() == WSAETIMEDOUT))) {
10553 while (--n >= 0 && err.code == tls::ErrorCode::WantWrite) {
10555 if (wait_writable()) {
10556 std::this_thread::sleep_for(std::chrono::microseconds{10});
10557 ret = tls::write(session_, ptr, handle_size, err);
10558 if (ret >= 0) {
return ret; }
10570inline void SSLSocketStream::get_remote_ip_and_port(std::string &ip,
10575inline void SSLSocketStream::get_local_ip_and_port(std::string &ip,
10580inline socket_t SSLSocketStream::socket()
const {
return sock_; }
10582inline time_t SSLSocketStream::duration()
const {
10583 return std::chrono::duration_cast<std::chrono::milliseconds>(
10584 std::chrono::steady_clock::now() - start_time_)
10588inline void SSLSocketStream::set_read_timeout(time_t sec, time_t usec) {
10589 read_timeout_sec_ = sec;
10590 read_timeout_usec_ = usec;
10607 signal(SIGPIPE, SIG_IGN);
10613inline std::unique_ptr<detail::MatcherBase>
10614Server::make_matcher(
const std::string &pattern) {
10615 if (pattern.find(
"/:") != std::string::npos) {
10623 get_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
10628 post_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
10634 post_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
10635 std::move(handler));
10640 put_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
10646 put_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
10647 std::move(handler));
10652 patch_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
10658 patch_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
10659 std::move(handler));
10664 delete_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
10670 delete_handlers_for_content_reader_.emplace_back(make_matcher(pattern),
10671 std::move(handler));
10676 options_handlers_.emplace_back(make_matcher(pattern), std::move(handler));
10682 websocket_handlers_.push_back(
10683 {make_matcher(pattern), std::move(handler),
nullptr});
10690 websocket_handlers_.push_back({make_matcher(pattern), std::move(handler),
10691 std::move(sub_protocol_selector)});
10696 const std::string &mount_point) {
10701 const std::string &dir,
Headers headers) {
10704 std::string mnt = !mount_point.empty() ? mount_point :
"/";
10705 if (!mnt.empty() && mnt[0] ==
'/') {
10706 std::string resolved_base;
10709 if (resolved_base.back() !=
'\\' && resolved_base.back() !=
'/') {
10710 resolved_base +=
'\\';
10713 if (resolved_base.back() !=
'/') { resolved_base +=
'/'; }
10716 base_dirs_.push_back(
10717 {std::move(mnt), dir, std::move(resolved_base), std::move(headers)});
10725 for (
auto it = base_dirs_.begin(); it != base_dirs_.end(); ++it) {
10726 if (it->mount_point == mount_point) {
10727 base_dirs_.erase(it);
10736 const std::string &mime) {
10737 file_extension_and_mimetype_map_[ext] = mime;
10742 default_file_mimetype_ = mime;
10747 file_request_handler_ = std::move(handler);
10751inline Server &Server::set_error_handler_core(HandlerWithResponse handler,
10753 error_handler_ = std::move(handler);
10757inline Server &Server::set_error_handler_core(Handler handler,
10759 error_handler_ = [handler](
const Request &req, Response &res) {
10767 exception_handler_ = std::move(handler);
10772 pre_routing_handler_ = std::move(handler);
10777 post_routing_handler_ = std::move(handler);
10782 pre_request_handler_ = std::move(handler);
10787 logger_ = std::move(logger);
10792 error_logger_ = std::move(error_logger);
10797 pre_compression_logger_ = std::move(logger);
10803 expect_100_continue_handler_ = std::move(handler);
10808 address_family_ = family;
10823 socket_options_ = std::move(socket_options);
10828 default_headers_ = std::move(headers);
10833 std::function<ssize_t(
Stream &,
Headers &)>
const &writer) {
10834 header_writer_ = writer;
10882template <
class Rep,
class Period>
10884 const std::chrono::duration<Rep, Period> &duration) {
10892 int socket_flags) {
10893 auto ret = bind_internal(host, port, socket_flags);
10894 if (ret == -1) { is_decommissioned =
true; }
10898 auto ret = bind_internal(host, 0, socket_flags);
10899 if (ret == -1) { is_decommissioned =
true; }
10906 int socket_flags) {
10907 return bind_to_port(host, port, socket_flags) && listen_internal();
10913 while (!is_running_ && !is_decommissioned) {
10914 std::this_thread::sleep_for(std::chrono::milliseconds{1});
10925 is_decommissioned =
false;
10930inline bool Server::parse_request_line(
const char *s,
Request &req)
const {
10931 auto len = strlen(s);
10932 if (len < 2 || s[len - 2] !=
'\r' || s[len - 1] !=
'\n') {
return false; }
10938 detail::split(s, s + len,
' ', [&](
const char *b,
const char *e) {
10940 case 0: req.
method = std::string(b, e);
break;
10941 case 1: req.
target = std::string(b, e);
break;
10942 case 2: req.
version = std::string(b, e);
break;
10948 if (count != 3) {
return false; }
10951 thread_local const std::set<std::string> methods{
10952 "GET",
"HEAD",
"POST",
"PUT",
"DELETE",
10953 "CONNECT",
"OPTIONS",
"TRACE",
"PATCH",
"PRI"};
10955 if (methods.find(req.
method) == methods.end()) {
10967 for (
size_t i = 0; i < req.
target.size(); i++) {
10968 if (req.
target[i] ==
'#') {
10975 [&](
const char *lhs_data, std::size_t lhs_size,
10976 const char *rhs_data, std::size_t rhs_size) {
10978 decode_path_component(std::string(lhs_data, lhs_size));
10979 detail::parse_query_text(rhs_data, rhs_size, req.params);
10986inline bool Server::write_response(
Stream &strm,
bool close_connection,
10990 req.ranges.clear();
10991 return write_response_core(strm, close_connection, req, res,
false);
10994inline bool Server::write_response_with_content(
Stream &strm,
10995 bool close_connection,
10998 return write_response_core(strm, close_connection, req, res,
true);
11001inline bool Server::write_response_core(
Stream &strm,
bool close_connection,
11003 bool need_apply_ranges) {
11004 assert(res.status != -1);
11006 if (400 <= res.status && error_handler_ &&
11008 need_apply_ranges =
true;
11011 std::string content_type;
11012 std::string boundary;
11013 if (need_apply_ranges) { apply_ranges(req, res, content_type, boundary); }
11016 if (close_connection || req.get_header_value(
"Connection") ==
"close" ||
11017 400 <= res.status) {
11018 res.set_header(
"Connection",
"close");
11020 std::string s =
"timeout=";
11024 res.set_header(
"Keep-Alive", s);
11027 if ((!res.body.empty() || res.content_length_ > 0 || res.content_provider_) &&
11028 !res.has_header(
"Content-Type")) {
11029 res.set_header(
"Content-Type",
"text/plain");
11032 if (res.body.empty() && !res.content_length_ && !res.content_provider_ &&
11033 !res.has_header(
"Content-Length")) {
11034 res.set_header(
"Content-Length",
"0");
11037 if (req.method ==
"HEAD" && !res.has_header(
"Accept-Ranges")) {
11038 res.set_header(
"Accept-Ranges",
"bytes");
11041 if (post_routing_handler_) { post_routing_handler_(req, res); }
11044 detail::BufferStream bstrm;
11046 if (header_writer_(bstrm, res.headers) <= 0) {
return false; }
11049 if (req.method !=
"HEAD" && !res.body.empty() && !res.content_provider_) {
11050 bstrm.write(res.body.data(), res.body.size());
11055 output_log(req, res);
11058 auto &data = bstrm.get_buffer();
11063 if (req.method !=
"HEAD" && res.content_provider_) {
11064 if (write_content_with_provider(strm, req, res, boundary, content_type)) {
11065 res.content_provider_success_ =
true;
11075Server::write_content_with_provider(
Stream &strm,
const Request &req,
11076 Response &res,
const std::string &boundary,
11077 const std::string &content_type) {
11078 auto is_shutting_down = [
this]() {
11082 if (res.content_length_ > 0) {
11083 if (req.ranges.empty()) {
11085 res.content_length_, is_shutting_down);
11086 }
else if (req.ranges.size() == 1) {
11088 req.ranges[0], res.content_length_);
11091 offset_and_length.first,
11092 offset_and_length.second, is_shutting_down);
11095 strm, req, res, boundary, content_type, res.content_length_,
11099 if (res.is_chunked_content_provider_) {
11102 std::unique_ptr<detail::compressor> compressor;
11104#ifdef CPPHTTPLIB_ZLIB_SUPPORT
11108#ifdef CPPHTTPLIB_BROTLI_SUPPORT
11112#ifdef CPPHTTPLIB_ZSTD_SUPPORT
11118 assert(compressor !=
nullptr);
11121 is_shutting_down, *compressor);
11130 FormFields::iterator cur_field;
11131 FormFiles::iterator cur_file;
11132 auto is_text_field =
false;
11134 if (read_content_core(
11137 [&](
const char *buf,
size_t n) {
11144 if (req.body.size() >= req.body.max_size() ||
11145 n > req.body.max_size() - req.body.size()) {
11158 req.body.append(buf, n);
11162 [&](
const FormData &file) {
11168 if (file.filename.empty()) {
11169 cur_field = req.form.fields.emplace(
11170 file.name, FormField{file.name, file.content, file.headers});
11171 is_text_field =
true;
11173 cur_file = req.form.files.emplace(file.name, file);
11174 is_text_field =
false;
11178 [&](
const char *buf,
size_t n) {
11179 if (is_text_field) {
11180 auto &content = cur_field->second.content;
11181 if (content.size() + n > content.max_size()) {
return false; }
11182 content.append(buf, n);
11184 auto &content = cur_file->second.content;
11185 if (content.size() + n > content.max_size()) {
return false; }
11186 content.append(buf, n);
11190 const auto &content_type = req.get_header_value(
"Content-Type");
11192 "application/x-www-form-urlencoded") {
11205inline bool Server::read_content_with_content_receiver(
11208 return read_content_core(strm, req, res, std::move(receiver),
11209 std::move(multipart_header),
11210 std::move(multipart_receiver));
11213inline bool Server::read_content_core(
11216 detail::FormDataParser multipart_form_data_parser;
11219 if (req.is_multipart_form_data()) {
11220 const auto &content_type = req.get_header_value(
"Content-Type");
11221 std::string boundary;
11228 multipart_form_data_parser.set_boundary(std::move(boundary));
11229 out = [&](
const char *buf,
size_t n,
size_t ,
size_t ) {
11230 return multipart_form_data_parser.parse(buf, n, multipart_header,
11231 multipart_receiver);
11234 out = [receiver](
const char *buf,
size_t n,
size_t ,
11235 size_t ) {
return receiver(buf, n); };
11249#if !defined(CPPHTTPLIB_SSL_ENABLED)
11250 if (!req.has_header(
"Content-Length") &&
11258 bool has_data = strm.is_readable();
11280 if (!req.has_header(
"Content-Length") &&
11291 if (req.is_multipart_form_data()) {
11292 if (!multipart_form_data_parser.is_valid()) {
11302inline bool Server::handle_file_request(
Request &req,
Response &res) {
11303 for (
const auto &entry : base_dirs_) {
11305 if (!req.path.compare(0, entry.mount_point.size(), entry.mount_point)) {
11306 std::string sub_path =
"/" + req.path.substr(entry.mount_point.size());
11308 auto path = entry.base_dir + sub_path;
11309 if (path.back() ==
'/') { path +=
"index.html"; }
11313 if (!entry.resolved_base_dir.empty()) {
11314 std::string resolved_path;
11317 entry.resolved_base_dir)) {
11323 detail::FileStat stat(path);
11325 if (stat.is_dir()) {
11330 if (stat.is_file()) {
11331 for (
const auto &kv : entry.headers) {
11332 res.set_header(kv.first, kv.second);
11336 if (!etag.empty()) { res.set_header(
"ETag", etag); }
11338 auto mtime = stat.mtime();
11341 if (!last_modified.empty()) {
11342 res.set_header(
"Last-Modified", last_modified);
11345 if (check_if_not_modified(req, res, etag, mtime)) {
return true; }
11347 check_if_range(req, etag, mtime);
11349 auto mm = std::make_shared<detail::mmap>(path.c_str());
11350 if (!mm->is_open()) {
11355 res.set_content_provider(
11358 default_file_mimetype_),
11359 [mm](
size_t offset,
size_t length, DataSink &sink) ->
bool {
11360 sink.write(mm->data() + offset, length);
11364 if (req.method !=
"HEAD" && file_request_handler_) {
11365 file_request_handler_(req, res);
11378inline bool Server::check_if_not_modified(
const Request &req,
Response &res,
11379 const std::string &etag,
11380 time_t mtime)
const {
11384 if (req.has_header(
"If-None-Match")) {
11385 if (!etag.empty()) {
11386 auto val = req.get_header_value(
"If-None-Match");
11395 [&](
const char *b,
const char *e) {
11396 auto seg_len = static_cast<size_t>(e - b);
11397 return (seg_len == 1 && *b ==
'*') ||
11398 (seg_len == etag.size() &&
11399 std::equal(b, e, etag.begin()));
11407 }
else if (req.has_header(
"If-Modified-Since")) {
11408 auto val = req.get_header_value(
"If-Modified-Since");
11411 if (t !=
static_cast<time_t
>(-1) && mtime <= t) {
11419inline bool Server::check_if_range(
Request &req,
const std::string &etag,
11420 time_t mtime)
const {
11425 if (!req.ranges.empty() && req.has_header(
"If-Range")) {
11426 auto val = req.get_header_value(
"If-Range");
11428 auto is_valid_range = [&]() {
11432 return (!etag.empty() && val == etag);
11439 return (t !=
static_cast<time_t
>(-1) && mtime <= t);
11443 if (!is_valid_range()) {
11445 req.ranges.clear();
11454Server::create_server_socket(
const std::string &host,
int port,
11458 host, std::string(), port, address_family_, socket_flags, tcp_nodelay_,
11459 ipv6_v6only_, std::move(socket_options),
11460 [&](
socket_t sock,
struct addrinfo &ai,
bool & ) ->
bool {
11461 if (::bind(sock, ai.ai_addr,
static_cast<socklen_t
>(ai.ai_addrlen))) {
11473inline int Server::bind_internal(
const std::string &host,
int port,
11474 int socket_flags) {
11475 if (is_decommissioned) {
return -1; }
11479 svr_sock_ = create_server_socket(host, port, socket_flags, socket_options_);
11483 struct sockaddr_storage addr;
11484 socklen_t addr_len =
sizeof(addr);
11485 if (getsockname(
svr_sock_,
reinterpret_cast<struct sockaddr *
>(&addr),
11486 &addr_len) == -1) {
11490 if (addr.ss_family == AF_INET) {
11491 return ntohs(
reinterpret_cast<struct sockaddr_in *
>(&addr)->sin_port);
11492 }
else if (addr.ss_family == AF_INET6) {
11493 return ntohs(
reinterpret_cast<struct sockaddr_in6 *
>(&addr)->sin6_port);
11503inline bool Server::listen_internal() {
11504 if (is_decommissioned) {
return false; }
11507 is_running_ =
true;
11508 auto se = detail::scope_exit([&]() { is_running_ =
false; });
11520 task_queue->on_idle();
11531#elif defined SOCK_CLOEXEC
11538 if (errno == EMFILE) {
11541 std::this_thread::sleep_for(std::chrono::microseconds{1});
11543 }
else if (errno == EINTR || errno == EAGAIN) {
11561 if (tcp_nodelay_) {
11565 if (!task_queue->enqueue(
11566 [
this, sock]() { process_and_close_socket(sock); })) {
11573 task_queue->shutdown();
11576 is_decommissioned = !ret;
11581 if (pre_routing_handler_ &&
11587 if ((req.method ==
"GET" || req.method ==
"HEAD") &&
11588 handle_file_request(req, res)) {
11599 bool content_reader_payload_too_large =
false;
11601 ContentReader reader(
11603 auto result = read_content_with_content_receiver(
11604 strm, req, res, std::move(receiver),
nullptr,
nullptr);
11608 content_reader_payload_too_large =
true;
11614 auto result = read_content_with_content_receiver(
11615 strm, req, res,
nullptr, std::move(header),
11616 std::move(receiver));
11620 content_reader_payload_too_large =
true;
11626 bool dispatched =
false;
11627 if (req.method ==
"POST") {
11628 dispatched = dispatch_request_for_content_reader(
11629 req, res, std::move(reader), post_handlers_for_content_reader_);
11630 }
else if (req.method ==
"PUT") {
11631 dispatched = dispatch_request_for_content_reader(
11632 req, res, std::move(reader), put_handlers_for_content_reader_);
11633 }
else if (req.method ==
"PATCH") {
11634 dispatched = dispatch_request_for_content_reader(
11635 req, res, std::move(reader), patch_handlers_for_content_reader_);
11636 }
else if (req.method ==
"DELETE") {
11637 dispatched = dispatch_request_for_content_reader(
11638 req, res, std::move(reader), delete_handlers_for_content_reader_);
11642 if (content_reader_payload_too_large) {
11647 res.content_length_ = 0;
11648 res.content_provider_ =
nullptr;
11656 if (!read_content(strm, req, res)) {
11663 if (req.method ==
"GET" || req.method ==
"HEAD") {
11664 return dispatch_request(req, res, get_handlers_);
11665 }
else if (req.method ==
"POST") {
11666 return dispatch_request(req, res, post_handlers_);
11667 }
else if (req.method ==
"PUT") {
11668 return dispatch_request(req, res, put_handlers_);
11669 }
else if (req.method ==
"DELETE") {
11670 return dispatch_request(req, res, delete_handlers_);
11671 }
else if (req.method ==
"OPTIONS") {
11672 return dispatch_request(req, res, options_handlers_);
11673 }
else if (req.method ==
"PATCH") {
11674 return dispatch_request(req, res, patch_handlers_);
11682 const Handlers &handlers)
const {
11683 for (
const auto &x : handlers) {
11684 const auto &matcher = x.first;
11685 const auto &handler = x.second;
11687 if (matcher->match(req)) {
11688 req.matched_route = matcher->pattern();
11689 if (!pre_request_handler_ ||
11700 std::string &content_type,
11701 std::string &boundary)
const {
11703 auto it = res.headers.find(
"Content-Type");
11704 if (it != res.headers.end()) {
11705 content_type = it->second;
11706 res.headers.erase(it);
11711 res.set_header(
"Content-Type",
11712 "multipart/byteranges; boundary=" + boundary);
11717 if (res.body.empty()) {
11718 if (res.content_length_ > 0) {
11721 length = res.content_length_;
11722 }
else if (req.ranges.size() == 1) {
11724 req.ranges[0], res.content_length_);
11726 length = offset_and_length.second;
11729 offset_and_length, res.content_length_);
11730 res.set_header(
"Content-Range", content_range);
11733 req, boundary, content_type, res.content_length_);
11735 res.set_header(
"Content-Length", std::to_string(length));
11737 if (res.content_provider_) {
11738 if (res.is_chunked_content_provider_) {
11739 res.set_header(
"Transfer-Encoding",
"chunked");
11741 res.set_header(
"Content-Encoding",
"gzip");
11742 res.set_header(
"Vary",
"Accept-Encoding");
11744 res.set_header(
"Content-Encoding",
"br");
11745 res.set_header(
"Vary",
"Accept-Encoding");
11747 res.set_header(
"Content-Encoding",
"zstd");
11748 res.set_header(
"Vary",
"Accept-Encoding");
11756 }
else if (req.ranges.size() == 1) {
11757 auto offset_and_length =
11759 auto offset = offset_and_length.first;
11760 auto length = offset_and_length.second;
11763 offset_and_length, res.body.size());
11764 res.set_header(
"Content-Range", content_range);
11766 assert(offset + length <= res.body.size());
11767 res.body = res.body.substr(offset, length);
11771 res.body.size(), data);
11772 res.body.swap(data);
11776 output_pre_compression_log(req, res);
11778 std::unique_ptr<detail::compressor> compressor;
11779 std::string content_encoding;
11782#ifdef CPPHTTPLIB_ZLIB_SUPPORT
11784 content_encoding =
"gzip";
11787#ifdef CPPHTTPLIB_BROTLI_SUPPORT
11789 content_encoding =
"br";
11792#ifdef CPPHTTPLIB_ZSTD_SUPPORT
11794 content_encoding =
"zstd";
11799 std::string compressed;
11800 if (compressor->compress(res.body.data(), res.body.size(),
true,
11801 [&](
const char *data,
size_t data_len) {
11802 compressed.append(data, data_len);
11805 res.body.swap(compressed);
11806 res.set_header(
"Content-Encoding", content_encoding);
11807 res.set_header(
"Vary",
"Accept-Encoding");
11812 auto length = std::to_string(res.body.size());
11813 res.set_header(
"Content-Length", length);
11817inline bool Server::dispatch_request_for_content_reader(
11819 const HandlersForContentReader &handlers)
const {
11820 for (
const auto &x : handlers) {
11821 const auto &matcher = x.first;
11822 const auto &handler = x.second;
11824 if (matcher->match(req)) {
11825 req.matched_route = matcher->pattern();
11826 if (!pre_request_handler_ ||
11828 handler(req, res, content_reader);
11838 const std::vector<std::string> &trusted_proxies) {
11840 std::vector<std::string> ip_list;
11842 x_forwarded_for.data() + x_forwarded_for.size(),
',',
11843 [&](
const char *b,
const char *e) {
11844 auto r = detail::trim(b, e, 0, static_cast<size_t>(e - b));
11845 ip_list.emplace_back(std::string(b + r.first, b + r.second));
11848 for (
size_t i = 0; i < ip_list.size(); ++i) {
11849 auto ip = ip_list[i];
11851 auto is_trusted_proxy =
11852 std::any_of(trusted_proxies.begin(), trusted_proxies.end(),
11853 [&](
const std::string &proxy) { return ip == proxy; });
11855 if (is_trusted_proxy) {
11861 return ip_list[i - 1];
11867 return ip_list.front();
11872 int remote_port,
const std::string &local_addr,
11873 int local_port,
bool close_connection,
11874 bool &connection_closed,
11875 const std::function<
void(
Request &)> &setup_request,
11876 bool *websocket_upgraded) {
11877 std::array<char, 2048> buf{};
11882 if (!line_reader.
getline()) {
return false; }
11885 req.
start_time_ = std::chrono::steady_clock::now();
11893 res.
headers = default_headers_;
11896 if (!parse_request_line(line_reader.
ptr(), req)) {
11899 return write_response(strm, close_connection, req, res);
11906 return write_response(strm, close_connection, req, res);
11913 return write_response(strm, close_connection, req, res);
11917 connection_closed =
true;
11920 if (req.
version ==
"HTTP/1.0" &&
11922 connection_closed =
true;
11941 return write_response(strm, close_connection, req, res);
11950 return write_response(strm, close_connection, req, res);
11954 if (setup_request) { setup_request(req); }
11958 if (expect_100_continue_handler_) {
11959 status = expect_100_continue_handler_(req, res);
11965 strm.
write(
"\r\n");
11968 connection_closed =
true;
11969 return write_response(strm,
true, req, res);
11974 auto sock = strm.
socket();
11984 if (pre_routing_handler_ &&
11987 return write_response(strm, close_connection, req, res);
11990 for (
const auto &entry : websocket_handlers_) {
11991 if (entry.matcher->match(req)) {
11997 std::string selected_subprotocol;
11998 if (entry.sub_protocol_selector) {
12000 if (!protocol_header.empty()) {
12001 std::vector<std::string> protocols;
12002 std::istringstream iss(protocol_header);
12004 while (std::getline(iss, token,
',')) {
12006 auto start = token.find_first_not_of(
' ');
12007 auto end = token.find_last_not_of(
' ');
12008 if (start != std::string::npos) {
12009 protocols.push_back(token.substr(start, end - start + 1));
12012 selected_subprotocol = entry.sub_protocol_selector(protocols);
12017 std::string handshake_response =
"HTTP/1.1 101 Switching Protocols\r\n"
12018 "Upgrade: websocket\r\n"
12019 "Connection: Upgrade\r\n"
12020 "Sec-WebSocket-Accept: " +
12021 accept_key +
"\r\n";
12022 if (!selected_subprotocol.empty()) {
12026 handshake_response +=
12027 "Sec-WebSocket-Protocol: " + selected_subprotocol +
"\r\n";
12029 handshake_response +=
"\r\n";
12030 if (strm.
write(handshake_response.data(), handshake_response.size()) <
12035 connection_closed =
true;
12036 if (websocket_upgraded) { *websocket_upgraded =
true; }
12042 entry.handler(req,
ws);
12051 auto routed =
false;
12052#ifdef CPPHTTPLIB_NO_EXCEPTIONS
12053 routed = routing(req, res, strm);
12056 routed = routing(req, res, strm);
12057 }
catch (std::exception &) {
12058 if (exception_handler_) {
12059 auto ep = std::current_exception();
12060 exception_handler_(req, res, ep);
12066 if (exception_handler_) {
12067 auto ep = std::current_exception();
12068 exception_handler_(req, res, ep);
12084 auto mm = std::make_shared<detail::mmap>(path.c_str());
12085 if (!mm->is_open()) {
12091 return write_response(strm, close_connection, req, res);
12095 if (content_type.empty()) {
12097 path, file_extension_and_mimetype_map_, default_file_mimetype_);
12101 mm->size(), content_type,
12102 [mm](
size_t offset,
size_t length,
DataSink &sink) ->
bool {
12103 sink.write(mm->data() + offset, length);
12113 return write_response(strm, close_connection, req, res);
12116 return write_response_with_content(strm, close_connection, req, res);
12120 return write_response(strm, close_connection, req, res);
12126inline bool Server::process_and_close_socket(
socket_t sock) {
12127 std::string remote_addr;
12128 int remote_port = 0;
12131 std::string local_addr;
12132 int local_port = 0;
12135 bool websocket_upgraded =
false;
12140 [&](
Stream &strm,
bool close_connection,
bool &connection_closed) {
12142 local_port, close_connection, connection_closed,
12143 nullptr, &websocket_upgraded);
12151inline void Server::output_log(
const Request &req,
const Response &res)
const {
12153 std::lock_guard<std::mutex> guard(logger_mutex_);
12158inline void Server::output_pre_compression_log(
const Request &req,
12160 if (pre_compression_logger_) {
12161 std::lock_guard<std::mutex> guard(logger_mutex_);
12162 pre_compression_logger_(req, res);
12166inline void Server::output_error_log(
const Error &err,
12168 if (error_logger_) {
12169 std::lock_guard<std::mutex> guard(logger_mutex_);
12170 error_logger_(err, req);
12185 const std::string &client_cert_path,
12186 const std::string &client_key_path)
12192 size_t retry_count = 10;
12193 while (retry_count-- > 0) {
12198 std::this_thread::sleep_for(std::chrono::milliseconds{1});
12240#ifdef CPPHTTPLIB_SSL_ENABLED
12241 digest_auth_username_ = rhs.digest_auth_username_;
12242 digest_auth_password_ = rhs.digest_auth_password_;
12243 proxy_digest_auth_username_ = rhs.proxy_digest_auth_username_;
12244 proxy_digest_auth_password_ = rhs.proxy_digest_auth_password_;
12245 ca_cert_file_path_ = rhs.ca_cert_file_path_;
12246 ca_cert_dir_path_ = rhs.ca_cert_dir_path_;
12247 server_certificate_verification_ = rhs.server_certificate_verification_;
12248 server_hostname_verification_ = rhs.server_hostname_verification_;
12252inline socket_t ClientImpl::create_client_socket(
Error &error)
const {
12264 if (it !=
addr_map_.end()) { ip = it->second; }
12275 auto sock = create_client_socket(error);
12287 std::chrono::time_point<std::chrono::steady_clock> ,
12316#ifdef CPPHTTPLIB_SSL_ENABLED
12317 assert(
socket.ssl ==
nullptr);
12325inline bool ClientImpl::read_response_line(
Stream &strm,
const Request &req,
12327 bool skip_100_continue)
const {
12328 std::array<char, 2048> buf{};
12330 detail::stream_line_reader line_reader(strm, buf.data(), buf.size());
12332 if (!line_reader.getline()) {
return false; }
12334#ifdef CPPHTTPLIB_ALLOW_LF_AS_LINE_TERMINATOR
12335 thread_local const std::regex re(
"(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r?\n");
12337 thread_local const std::regex re(
"(HTTP/1\\.[01]) (\\d{3})(?: (.*?))?\r\n");
12341 if (!std::regex_match(line_reader.ptr(), m, re)) {
12342 return req.
method ==
"CONNECT";
12344 res.
version = std::string(m[1]);
12345 res.
status = std::stoi(std::string(m[2]));
12346 res.
reason = std::string(m[3]);
12350 if (!line_reader.getline()) {
return false; }
12351 if (!line_reader.getline()) {
return false; }
12353 if (!std::regex_match(line_reader.ptr(), m, re)) {
return false; }
12354 res.
version = std::string(m[1]);
12355 res.
status = std::stoi(std::string(m[2]));
12356 res.
reason = std::string(m[3]);
12363 std::lock_guard<std::recursive_mutex> request_mutex_guard(
request_mutex_);
12364 auto ret = send_(req, res, error);
12367 ret = send_(req, res, error);
12383 auto is_alive =
false;
12387#ifdef CPPHTTPLIB_SSL_ENABLED
12388 if (is_alive && is_ssl()) {
12400 const bool shutdown_gracefully =
false;
12414 auto success =
true;
12442 auto se = detail::scope_exit([&]() {
12460 return handle_request(strm, req, res, close_connection, error);
12475 return send_(std::move(req2));
12481 auto ret =
send(req, *res, error);
12482#ifdef CPPHTTPLIB_SSL_ENABLED
12483 return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers),
12484 last_ssl_error_, last_backend_error_};
12486 return Result{ret ? std::move(res) : nullptr, error, std::move(req.headers)};
12490inline void ClientImpl::prepare_default_headers(Request &r,
bool for_stream,
12491 const std::string &ct) {
12494 if (!r.has_header(header.first)) { r.headers.insert(header); }
12497 if (!r.has_header(
"Host")) {
12499 r.headers.emplace(
"Host",
"localhost");
12506 if (!r.has_header(
"Accept")) { r.headers.emplace(
"Accept",
"*/*"); }
12508 if (!r.content_receiver) {
12509 if (!r.has_header(
"Accept-Encoding")) {
12510 std::string accept_encoding;
12511#ifdef CPPHTTPLIB_BROTLI_SUPPORT
12512 accept_encoding =
"br";
12514#ifdef CPPHTTPLIB_ZLIB_SUPPORT
12515 if (!accept_encoding.empty()) { accept_encoding +=
", "; }
12516 accept_encoding +=
"gzip, deflate";
12518#ifdef CPPHTTPLIB_ZSTD_SUPPORT
12519 if (!accept_encoding.empty()) { accept_encoding +=
", "; }
12520 accept_encoding +=
"zstd";
12522 r.set_header(
"Accept-Encoding", accept_encoding);
12525#ifndef CPPHTTPLIB_NO_DEFAULT_USER_AGENT
12526 if (!r.has_header(
"User-Agent")) {
12528 r.set_header(
"User-Agent", agent);
12533 if (!r.body.empty()) {
12534 if (!ct.empty() && !r.has_header(
"Content-Type")) {
12535 r.headers.emplace(
"Content-Type", ct);
12537 if (!r.has_header(
"Content-Length")) {
12538 r.headers.emplace(
"Content-Length", std::to_string(r.body.size()));
12543inline ClientImpl::StreamHandle
12546 const std::string &body,
12547 const std::string &content_type) {
12558 auto is_alive =
false;
12561#ifdef CPPHTTPLIB_SSL_ENABLED
12562 if (is_alive && is_ssl()) {
12582 auto success =
true;
12583 auto start_time = std::chrono::steady_clock::now();
12585 success, handle.
error)) {
12586 if (!success) { handle.
response.reset(); }
12592 transfer_socket_ownership_to_handle(handle);
12595#ifdef CPPHTTPLIB_SSL_ENABLED
12596 if (is_ssl() && handle.connection_->session) {
12598 handle.connection_->sock, handle.connection_->session,
12611 handle.stream_ = handle.socket_stream_.get();
12615 req.
path = query_path;
12619 prepare_default_headers(req,
true, content_type);
12621 auto &strm = *handle.stream_;
12634 if (!body.empty()) {
12635 if (strm.
write(body.data(), body.size()) < 0) {
12642 if (!read_response_line(strm, req, *handle.
response) ||
12649 handle.body_reader_.
stream = handle.stream_;
12652 if (handle.
response->has_header(
"Content-Length")) {
12653 bool is_invalid =
false;
12655 handle.
response->headers,
"Content-Length", 0, 0, is_invalid);
12665 auto transfer_encoding =
12666 handle.
response->get_header_value(
"Transfer-Encoding");
12667 handle.body_reader_.
chunked = (transfer_encoding ==
"chunked");
12669 auto content_encoding = handle.
response->get_header_value(
"Content-Encoding");
12670 if (!content_encoding.empty()) {
12680 if (decompressor_) {
return read_with_decompression(buf, len); }
12685 if (body_reader_.chunked_decoder) {
12686 if (!body_reader_.chunked_decoder->parse_trailers_into(
12701inline ssize_t ClientImpl::StreamHandle::read_with_decompression(
char *buf,
12703 if (decompress_offset_ < decompress_buffer_.size()) {
12704 auto available = decompress_buffer_.size() - decompress_offset_;
12705 auto to_copy = (std::min)(len, available);
12706 std::memcpy(buf, decompress_buffer_.data() + decompress_offset_, to_copy);
12707 decompress_offset_ += to_copy;
12708 decompressed_bytes_read_ += to_copy;
12709 return static_cast<ssize_t
>(to_copy);
12712 decompress_buffer_.clear();
12713 decompress_offset_ = 0;
12715 constexpr size_t kDecompressionBufferSize = 8192;
12716 char compressed_buf[kDecompressionBufferSize];
12720 sizeof(compressed_buf));
12722 if (n <= 0) {
return n; }
12724 bool decompress_ok = decompressor_->decompress(
12725 compressed_buf,
static_cast<size_t>(n),
12726 [
this](
const char *data,
size_t data_len) {
12727 decompress_buffer_.append(data, data_len);
12728 auto limit = body_reader_.payload_max_length;
12729 if (decompressed_bytes_read_ + decompress_buffer_.size() > limit) {
12735 if (!decompress_ok) {
12740 if (!decompress_buffer_.empty()) {
break; }
12743 auto to_copy = (std::min)(len, decompress_buffer_.size());
12744 std::memcpy(buf, decompress_buffer_.data(), to_copy);
12745 decompress_offset_ = to_copy;
12746 decompressed_bytes_read_ += to_copy;
12747 return static_cast<ssize_t
>(to_copy);
12757 const auto bufsiz = 128;
12758 char line_buf[bufsiz];
12761 if (!line_reader.
getline()) {
return; }
12774 size_t &out_chunk_offset,
12775 size_t &out_chunk_total) {
12780 if (!lr.
getline()) {
return -1; }
12782 char *endptr =
nullptr;
12783 unsigned long chunk_len = std::strtoul(lr.
ptr(), &endptr, 16);
12784 if (endptr == lr.
ptr()) {
return -1; }
12785 if (chunk_len == ULONG_MAX) {
return -1; }
12787 if (chunk_len == 0) {
12790 out_chunk_offset = 0;
12791 out_chunk_total = 0;
12801 auto n =
strm.read(buf, to_read);
12802 if (n <= 0) {
return -1; }
12808 out_chunk_offset = offset_before;
12813 if (!lr.
getline()) {
return -1; }
12814 if (std::strcmp(lr.
ptr(),
"\r\n") != 0) {
return -1; }
12821 const Headers &src_headers) {
12823 if (!lr.
getline()) {
return false; }
12830ClientImpl::transfer_socket_ownership_to_handle(StreamHandle &handle) {
12832#ifdef CPPHTTPLIB_SSL_ENABLED
12833 handle.connection_->session =
socket_.ssl;
12839inline bool ClientImpl::handle_request(Stream &strm, Request &req,
12840 Response &res,
bool close_connection,
12842 if (req.path.empty()) {
12848 auto req_save = req;
12854 req2.path =
"http://" +
12858 req = std::move(req2);
12859 req.path = req_save.path;
12864 if (!ret) {
return false; }
12866 if (res.get_header_value(
"Connection") ==
"close" ||
12867 (res.version ==
"HTTP/1.0" && res.reason !=
"Connection established")) {
12882 req = std::move(req_save);
12883 ret = redirect(req, res, error);
12886#ifdef CPPHTTPLIB_SSL_ENABLED
12889 req.authorization_count_ < 5) {
12891 const auto &username =
12892 is_proxy ? proxy_digest_auth_username_ : digest_auth_username_;
12893 const auto &password =
12894 is_proxy ? proxy_digest_auth_password_ : digest_auth_password_;
12896 if (!username.empty() && !password.empty()) {
12897 std::map<std::string, std::string> auth;
12899 Request new_req = req;
12900 new_req.authorization_count_ += 1;
12901 new_req.headers.erase(is_proxy ?
"Proxy-Authorization"
12902 :
"Authorization");
12903 new_req.headers.insert(detail::make_digest_authentication_header(
12905 username, password, is_proxy));
12909 ret =
send(new_req, new_res, error);
12910 if (ret) { res = std::move(new_res); }
12920 if (req.redirect_count_ == 0) {
12926 auto location = res.get_header_value(
"location");
12927 if (location.empty()) {
return false; }
12929 thread_local const std::regex re(
12930 R
"((?:(https?):)?(?://(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)?([^?#]*)(\?[^#]*)?(?:#.*)?)");
12933 if (!std::regex_match(location, m, re)) {
return false; }
12935 auto scheme = is_ssl() ?
"https" :
"http";
12937 auto next_scheme = m[1].str();
12938 auto next_host = m[2].str();
12939 if (next_host.empty()) { next_host = m[3].str(); }
12940 auto port_str = m[4].str();
12941 auto next_path = m[5].str();
12942 auto next_query = m[6].str();
12944 auto next_port =
port_;
12945 if (!port_str.empty()) {
12947 }
else if (!next_scheme.empty()) {
12948 next_port = next_scheme ==
"https" ? 443 : 80;
12951 if (next_scheme.empty()) { next_scheme = scheme; }
12952 if (next_host.empty()) { next_host =
host_; }
12953 if (next_path.empty()) { next_path =
"/"; }
12958 if (next_scheme == scheme && next_host ==
host_ && next_port ==
port_) {
12963 return create_redirect_client(next_scheme, next_host, next_port, req, res,
12964 path, location, error);
12968inline bool ClientImpl::create_redirect_client(
12969 const std::string &scheme,
const std::string &host,
int port,
Request &req,
12970 Response &res,
const std::string &path,
const std::string &location,
12973 auto need_ssl = (scheme ==
"https");
12977 auto headers_to_remove =
12978 std::vector<std::string>{
"Host",
"Proxy-Authorization",
"Authorization"};
12980 for (
const auto &header_name : headers_to_remove) {
12981 auto it = req.headers.find(header_name);
12982 while (it != req.headers.end()) {
12983 it = req.headers.erase(it);
12984 it = req.headers.find(header_name);
12990#ifdef CPPHTTPLIB_SSL_ENABLED
12992 SSLClient redirect_client(
host,
port);
12995 setup_redirect_client(redirect_client);
12997 redirect_client.enable_server_certificate_verification(
12998 server_certificate_verification_);
12999 redirect_client.enable_server_hostname_verification(
13000 server_hostname_verification_);
13003 if (!ca_cert_pem_.empty()) {
13004 redirect_client.load_ca_cert_store(ca_cert_pem_.c_str(),
13005 ca_cert_pem_.size());
13007 if (!ca_cert_file_path_.empty()) {
13008 redirect_client.set_ca_cert_path(ca_cert_file_path_, ca_cert_dir_path_);
13017 return detail::redirect(redirect_client, req, res, path, location, error);
13029 setup_redirect_client(redirect_client);
13032 return detail::redirect(redirect_client, req, res, path, location, error);
13038template <
typename ClientType>
13039inline void ClientImpl::setup_redirect_client(ClientType &client) {
13045 client.set_follow_location(
13071#ifdef CPPHTTPLIB_SSL_ENABLED
13072 if (!proxy_digest_auth_username_.empty()) {
13073 client.set_proxy_digest_auth(proxy_digest_auth_username_,
13074 proxy_digest_auth_password_);
13096 Error &error)
const {
13097 auto is_shutting_down = []() {
return false; };
13101 : std::unique_ptr<detail::compressor>();
13107 is_shutting_down, *compressor, error);
13115inline bool ClientImpl::write_request(
Stream &strm,
Request &req,
13116 bool close_connection,
Error &error,
13119 if (close_connection) {
13125 std::string ct_for_defaults;
13127 ct_for_defaults =
"text/plain";
13129 prepare_default_headers(req,
false, ct_for_defaults);
13131 if (req.
body.empty()) {
13141 req.
method ==
"PATCH") {
13156 if (!req.
has_header(
"Proxy-Authorization")) {
13170 if (!req.
has_header(
"Proxy-Authorization")) {
13178 detail::BufferStream bstrm;
13181 std::string path_part, query_part;
13182 auto query_pos = req.
path.find(
'?');
13183 if (query_pos != std::string::npos) {
13184 path_part = req.
path.substr(0, query_pos);
13185 query_part = req.
path.substr(query_pos + 1);
13187 path_part = req.
path;
13198 auto path_with_query =
13201 if (!query_part.empty()) {
13205 if (!normalized.empty()) { path_with_query +=
'?' + normalized; }
13214 if (!req.
params.empty()) {
13228 auto &data = bstrm.get_buffer();
13251 auto start = std::chrono::high_resolution_clock::now();
13257 auto sock = strm.
socket();
13266 if (!is_ssl() && strm.
is_readable()) {
return false; }
13268 auto now = std::chrono::high_resolution_clock::now();
13270 std::chrono::duration_cast<std::chrono::milliseconds>(now - start)
13276 std::this_thread::sleep_for(std::chrono::milliseconds(1));
13282 if (skip_body) {
return true; }
13284 return write_request_body(strm, req, error);
13287inline bool ClientImpl::write_request_body(
Stream &strm,
Request &req,
13289 if (req.body.empty()) {
13293 if (req.upload_progress) {
13294 auto body_size = req.body.size();
13295 size_t written = 0;
13296 auto data = req.body.data();
13298 while (written < body_size) {
13305 written += to_write;
13307 if (!req.upload_progress(written, body_size)) {
13324inline std::unique_ptr<Response>
13325ClientImpl::send_with_content_provider_and_receiver(
13326 Request &req,
const char *body,
size_t content_length,
13331 if (!content_type.empty()) { req.set_header(
"Content-Type", content_type); }
13335 : std::pair<std::unique_ptr<detail::compressor>, const char *>(
13338 if (enc.second) { req.set_header(
"Content-Encoding", enc.second); }
13340 if (enc.first && !content_provider_without_length) {
13341 auto &compressor = enc.first;
13343 if (content_provider) {
13346 DataSink data_sink;
13348 data_sink.write = [&](const char *data, size_t data_len) -> bool {
13350 auto last = offset + data_len == content_length;
13352 auto ret = compressor->compress(
13353 data, data_len, last,
13354 [&](const char *compressed_data, size_t compressed_data_len) {
13355 req.body.append(compressed_data, compressed_data_len);
13360 offset += data_len;
13368 while (ok && offset < content_length) {
13369 if (!content_provider(offset, content_length - offset, data_sink)) {
13370 error = Error::Canceled;
13371 output_error_log(error, &req);
13376 if (!compressor->compress(body, content_length, true,
13377 [&](const char *data, size_t data_len) {
13378 req.body.append(data, data_len);
13387 if (content_provider) {
13388 req.content_length_ = content_length;
13389 req.content_provider_ = std::move(content_provider);
13390 req.is_chunked_content_provider_ =
false;
13391 }
else if (content_provider_without_length) {
13392 req.content_length_ = 0;
13394 std::move(content_provider_without_length));
13395 req.is_chunked_content_provider_ =
true;
13396 req.set_header(
"Transfer-Encoding",
"chunked");
13398 req.body.assign(body, content_length);
13402 if (content_receiver) {
13403 req.content_receiver =
13404 [content_receiver](
const char *data,
size_t data_length,
13405 size_t ,
size_t ) {
13406 return content_receiver(data, data_length);
13411 return send(req, *res, error) ? std::move(res) : nullptr;
13414inline Result ClientImpl::send_with_content_provider_and_receiver(
13415 const std::string &method,
const std::string &path,
const Headers &headers,
13416 const char *body,
size_t content_length, ContentProvider content_provider,
13417 ContentProviderWithoutLength content_provider_without_length,
13418 const std::string &content_type, ContentReceiver content_receiver,
13419 UploadProgress progress) {
13421 req.method = method;
13422 req.headers = headers;
13424 req.upload_progress = std::move(progress);
13425 if (max_timeout_msec_ > 0) {
13426 req.start_time_ = std::chrono::steady_clock::now();
13429 auto error = Error::Success;
13431 auto res = send_with_content_provider_and_receiver(
13432 req, body, content_length, std::move(content_provider),
13433 std::move(content_provider_without_length), content_type,
13434 std::move(content_receiver), error);
13436#ifdef CPPHTTPLIB_SSL_ENABLED
13437 return Result{std::move(res), error, std::move(req.headers), last_ssl_error_,
13438 last_backend_error_};
13440 return Result{std::move(res), error, std::move(req.headers)};
13461 Response &res,
bool close_connection,
13472 auto expect_100_continue = req.
get_header_value(
"Expect") ==
"100-continue";
13475 auto write_request_success =
13476 write_request(strm, req, close_connection, error, expect_100_continue);
13478#ifdef CPPHTTPLIB_SSL_ENABLED
13479 if (is_ssl() && !expect_100_continue) {
13481 if (!is_proxy_enabled) {
13498 if (!write_request_body(strm, req, error)) {
return false; }
13499 expect_100_continue =
false;
13505 if (!read_response_line(strm, req, res, !expect_100_continue) ||
13507 if (write_request_success) { error =
Error::Read; }
13512 if (!write_request_success) {
return false; }
13515 if (expect_100_continue) {
13518 if (!write_request_body(strm, req, error)) {
return false; }
13523 if (!read_response_line(strm, req, res) ||
13535 req.
method !=
"CONNECT") {
13536 auto redirect = 300 < res.
status && res.
status < 400 &&
13551 [&](
const char *buf,
size_t n,
size_t off,
size_t len) {
13552 if (redirect) {
return true; }
13561 [&](
const char *buf,
size_t n,
size_t ,
13563 assert(res.
body.size() + n <= res.
body.max_size());
13569 res.
body.append(buf, n);
13573 auto progress = [&](
size_t current,
size_t total) {
13586 if (len > res.
body.max_size()) {
13591 res.
body.reserve(
static_cast<size_t>(len));
13598 ? (std::numeric_limits<size_t>::max)()
13601 std::move(progress), std::move(out),
13619 size_t cur_item = 0;
13620 size_t cur_start = 0;
13623 return [&, cur_item, cur_start](
size_t offset,
13625 if (!offset && !items.empty()) {
13628 }
else if (cur_item < provider_items.size()) {
13630 const auto &begin = detail::serialize_multipart_formdata_item_begin(
13631 provider_items[cur_item], boundary);
13632 offset += begin.size();
13633 cur_start = offset;
13638 auto has_data =
true;
13639 cur_sink.write = sink.write;
13640 cur_sink.done = [&]() { has_data =
false; };
13642 if (!provider_items[cur_item].provider(offset - cur_start, cur_sink)) {
13647 sink.os << detail::serialize_multipart_formdata_item_end();
13653 sink.os << detail::serialize_multipart_formdata_finish(boundary);
13660inline bool ClientImpl::process_socket(
13661 const Socket &socket,
13662 std::chrono::time_point<std::chrono::steady_clock> start_time,
13663 std::function<
bool(Stream &strm)> callback) {
13664 return detail::process_client_socket(
13665 socket.sock, read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
13666 write_timeout_usec_, max_timeout_msec_, start_time, std::move(callback));
13669inline bool ClientImpl::is_ssl()
const {
return false; }
13673 return Get(path,
Headers(), std::move(progress));
13679 if (params.empty()) {
return Get(path, headers); }
13682 return Get(path_with_query, headers, std::move(progress));
13693 req.
start_time_ = std::chrono::steady_clock::now();
13696 return send_(std::move(req));
13702 return Get(path,
Headers(),
nullptr, std::move(content_receiver),
13703 std::move(progress));
13709 return Get(path, headers,
nullptr, std::move(content_receiver),
13710 std::move(progress));
13717 return Get(path,
Headers(), std::move(response_handler),
13718 std::move(content_receiver), std::move(progress));
13731 [content_receiver](
const char *data,
size_t data_length,
13732 size_t ,
size_t ) {
13733 return content_receiver(data, data_length);
13737 req.
start_time_ = std::chrono::steady_clock::now();
13740 return send_(std::move(req));
13747 return Get(path, params, headers,
nullptr, std::move(content_receiver),
13748 std::move(progress));
13756 if (params.empty()) {
13757 return Get(path, headers, std::move(response_handler),
13758 std::move(content_receiver), std::move(progress));
13762 return Get(path_with_query, headers, std::move(response_handler),
13763 std::move(content_receiver), std::move(progress));
13777 req.
start_time_ = std::chrono::steady_clock::now();
13780 return send_(std::move(req));
13784 return Post(path, std::string(), std::string());
13789 return Post(path, headers,
nullptr, 0, std::string());
13793 size_t content_length,
13794 const std::string &content_type,
13796 return Post(path,
Headers(), body, content_length, content_type, progress);
13800 const std::string &content_type,
13802 return Post(path,
Headers(), body, content_type, progress);
13811 const std::string &content_type,
13813 return Post(path,
Headers(), content_length, std::move(content_provider),
13814 content_type, progress);
13819 const std::string &content_type,
13822 return Post(path,
Headers(), content_length, std::move(content_provider),
13823 content_type, std::move(content_receiver), progress);
13828 const std::string &content_type,
13830 return Post(path,
Headers(), std::move(content_provider), content_type,
13836 const std::string &content_type,
13839 return Post(path,
Headers(), std::move(content_provider), content_type,
13840 std::move(content_receiver), progress);
13846 return Post(path, headers, query,
"application/x-www-form-urlencoded");
13859 const auto &content_type =
13862 return Post(path, headers, content_length,
13864 content_type, progress);
13869 const std::string &boundary,
13875 const auto &content_type =
13878 return Post(path, headers, content_length,
13880 content_type, progress);
13884 const char *body,
size_t content_length,
13885 const std::string &content_type,
13887 return send_with_content_provider_and_receiver(
13888 "POST", path, headers, body, content_length,
nullptr,
nullptr,
13889 content_type,
nullptr, progress);
13893 const std::string &body,
13894 const std::string &content_type,
13896 return send_with_content_provider_and_receiver(
13897 "POST", path, headers, body.data(), body.size(),
nullptr,
nullptr,
13898 content_type,
nullptr, progress);
13902 size_t content_length,
13904 const std::string &content_type,
13906 return send_with_content_provider_and_receiver(
13907 "POST", path, headers,
nullptr, content_length,
13908 std::move(content_provider),
nullptr, content_type,
nullptr, progress);
13912 size_t content_length,
13914 const std::string &content_type,
13917 return send_with_content_provider_and_receiver(
13918 "POST", path, headers,
nullptr, content_length,
13919 std::move(content_provider),
nullptr, content_type,
13920 std::move(content_receiver), std::move(progress));
13925 const std::string &content_type,
13927 return send_with_content_provider_and_receiver(
13928 "POST", path, headers,
nullptr, 0,
nullptr, std::move(content_provider),
13929 content_type,
nullptr, progress);
13934 const std::string &content_type,
13937 return send_with_content_provider_and_receiver(
13938 "POST", path, headers,
nullptr, 0,
nullptr, std::move(content_provider),
13939 content_type, std::move(content_receiver), std::move(progress));
13947 const auto &content_type =
13949 return send_with_content_provider_and_receiver(
13950 "POST", path, headers,
nullptr, 0,
nullptr,
13951 get_multipart_content_provider(boundary, items, provider_items),
13952 content_type,
nullptr, progress);
13956 const std::string &body,
13957 const std::string &content_type,
13966 [content_receiver](
const char *data,
size_t data_length,
13967 size_t ,
size_t ) {
13968 return content_receiver(data, data_length);
13973 req.
start_time_ = std::chrono::steady_clock::now();
13976 if (!content_type.empty()) { req.
set_header(
"Content-Type", content_type); }
13978 return send_(std::move(req));
13982 return Put(path, std::string(), std::string());
13986 return Put(path, headers,
nullptr, 0, std::string());
13990 size_t content_length,
13991 const std::string &content_type,
13993 return Put(path,
Headers(), body, content_length, content_type, progress);
13997 const std::string &content_type,
13999 return Put(path,
Headers(), body, content_type, progress);
14008 const std::string &content_type,
14010 return Put(path,
Headers(), content_length, std::move(content_provider),
14011 content_type, progress);
14016 const std::string &content_type,
14019 return Put(path,
Headers(), content_length, std::move(content_provider),
14020 content_type, std::move(content_receiver), progress);
14025 const std::string &content_type,
14027 return Put(path,
Headers(), std::move(content_provider), content_type,
14033 const std::string &content_type,
14036 return Put(path,
Headers(), std::move(content_provider), content_type,
14037 std::move(content_receiver), progress);
14043 return Put(path, headers, query,
"application/x-www-form-urlencoded");
14049 return Put(path,
Headers(), items, progress);
14056 const auto &content_type =
14059 return Put(path, headers, content_length,
14061 content_type, progress);
14066 const std::string &boundary,
14072 const auto &content_type =
14075 return Put(path, headers, content_length,
14077 content_type, progress);
14081 const char *body,
size_t content_length,
14082 const std::string &content_type,
14084 return send_with_content_provider_and_receiver(
14085 "PUT", path, headers, body, content_length,
nullptr,
nullptr,
14086 content_type,
nullptr, progress);
14090 const std::string &body,
14091 const std::string &content_type,
14093 return send_with_content_provider_and_receiver(
14094 "PUT", path, headers, body.data(), body.size(),
nullptr,
nullptr,
14095 content_type,
nullptr, progress);
14099 size_t content_length,
14101 const std::string &content_type,
14103 return send_with_content_provider_and_receiver(
14104 "PUT", path, headers,
nullptr, content_length,
14105 std::move(content_provider),
nullptr, content_type,
nullptr, progress);
14109 size_t content_length,
14111 const std::string &content_type,
14114 return send_with_content_provider_and_receiver(
14115 "PUT", path, headers,
nullptr, content_length,
14116 std::move(content_provider),
nullptr, content_type,
14117 std::move(content_receiver), progress);
14122 const std::string &content_type,
14124 return send_with_content_provider_and_receiver(
14125 "PUT", path, headers,
nullptr, 0,
nullptr, std::move(content_provider),
14126 content_type,
nullptr, progress);
14131 const std::string &content_type,
14134 return send_with_content_provider_and_receiver(
14135 "PUT", path, headers,
nullptr, 0,
nullptr, std::move(content_provider),
14136 content_type, std::move(content_receiver), progress);
14144 const auto &content_type =
14146 return send_with_content_provider_and_receiver(
14147 "PUT", path, headers,
nullptr, 0,
nullptr,
14148 get_multipart_content_provider(boundary, items, provider_items),
14149 content_type,
nullptr, progress);
14153 const std::string &body,
14154 const std::string &content_type,
14163 [content_receiver](
const char *data,
size_t data_length,
14164 size_t ,
size_t ) {
14165 return content_receiver(data, data_length);
14170 req.
start_time_ = std::chrono::steady_clock::now();
14173 if (!content_type.empty()) { req.
set_header(
"Content-Type", content_type); }
14175 return send_(std::move(req));
14179 return Patch(path, std::string(), std::string());
14184 return Patch(path, headers,
nullptr, 0, std::string(), progress);
14188 size_t content_length,
14189 const std::string &content_type,
14191 return Patch(path,
Headers(), body, content_length, content_type, progress);
14195 const std::string &body,
14196 const std::string &content_type,
14198 return Patch(path,
Headers(), body, content_type, progress);
14207 const std::string &content_type,
14209 return Patch(path,
Headers(), content_length, std::move(content_provider),
14210 content_type, progress);
14215 const std::string &content_type,
14218 return Patch(path,
Headers(), content_length, std::move(content_provider),
14219 content_type, std::move(content_receiver), progress);
14224 const std::string &content_type,
14226 return Patch(path,
Headers(), std::move(content_provider), content_type,
14232 const std::string &content_type,
14235 return Patch(path,
Headers(), std::move(content_provider), content_type,
14236 std::move(content_receiver), progress);
14242 return Patch(path, headers, query,
"application/x-www-form-urlencoded");
14255 const auto &content_type =
14258 return Patch(path, headers, content_length,
14260 content_type, progress);
14265 const std::string &boundary,
14271 const auto &content_type =
14274 return Patch(path, headers, content_length,
14276 content_type, progress);
14280 const char *body,
size_t content_length,
14281 const std::string &content_type,
14283 return send_with_content_provider_and_receiver(
14284 "PATCH", path, headers, body, content_length,
nullptr,
nullptr,
14285 content_type,
nullptr, progress);
14289 const std::string &body,
14290 const std::string &content_type,
14292 return send_with_content_provider_and_receiver(
14293 "PATCH", path, headers, body.data(), body.size(),
nullptr,
nullptr,
14294 content_type,
nullptr, progress);
14298 size_t content_length,
14300 const std::string &content_type,
14302 return send_with_content_provider_and_receiver(
14303 "PATCH", path, headers,
nullptr, content_length,
14304 std::move(content_provider),
nullptr, content_type,
nullptr, progress);
14308 size_t content_length,
14310 const std::string &content_type,
14313 return send_with_content_provider_and_receiver(
14314 "PATCH", path, headers,
nullptr, content_length,
14315 std::move(content_provider),
nullptr, content_type,
14316 std::move(content_receiver), progress);
14321 const std::string &content_type,
14323 return send_with_content_provider_and_receiver(
14324 "PATCH", path, headers,
nullptr, 0,
nullptr, std::move(content_provider),
14325 content_type,
nullptr, progress);
14330 const std::string &content_type,
14333 return send_with_content_provider_and_receiver(
14334 "PATCH", path, headers,
nullptr, 0,
nullptr, std::move(content_provider),
14335 content_type, std::move(content_receiver), progress);
14343 const auto &content_type =
14345 return send_with_content_provider_and_receiver(
14346 "PATCH", path, headers,
nullptr, 0,
nullptr,
14347 get_multipart_content_provider(boundary, items, provider_items),
14348 content_type,
nullptr, progress);
14352 const std::string &body,
14353 const std::string &content_type,
14362 [content_receiver](
const char *data,
size_t data_length,
14363 size_t ,
size_t ) {
14364 return content_receiver(data, data_length);
14369 req.
start_time_ = std::chrono::steady_clock::now();
14372 if (!content_type.empty()) { req.
set_header(
"Content-Type", content_type); }
14374 return send_(std::move(req));
14379 return Delete(path,
Headers(), std::string(), std::string(), progress);
14385 return Delete(path, headers, std::string(), std::string(), progress);
14389 size_t content_length,
14390 const std::string &content_type,
14392 return Delete(path,
Headers(), body, content_length, content_type, progress);
14396 const std::string &body,
14397 const std::string &content_type,
14399 return Delete(path,
Headers(), body.data(), body.size(), content_type,
14405 const std::string &body,
14406 const std::string &content_type,
14408 return Delete(path, headers, body.data(), body.size(), content_type,
14421 return Delete(path, headers, query,
"application/x-www-form-urlencoded",
14426 const Headers &headers,
const char *body,
14427 size_t content_length,
14428 const std::string &content_type,
14436 req.
start_time_ = std::chrono::steady_clock::now();
14439 if (!content_type.empty()) { req.
set_header(
"Content-Type", content_type); }
14440 req.
body.assign(body, content_length);
14442 return send_(std::move(req));
14456 req.
start_time_ = std::chrono::steady_clock::now();
14459 return send_(std::move(req));
14516 const std::string &password) {
14541 std::function<ssize_t(
Stream &,
Headers &)>
const &writer) {
14576 const std::string &password) {
14585#ifdef CPPHTTPLIB_SSL_ENABLED
14586inline void ClientImpl::set_digest_auth(
const std::string &username,
14587 const std::string &password) {
14588 digest_auth_username_ = username;
14589 digest_auth_password_ = password;
14592inline void ClientImpl::set_ca_cert_path(
const std::string &ca_cert_file_path,
14593 const std::string &ca_cert_dir_path) {
14594 ca_cert_file_path_ = ca_cert_file_path;
14595 ca_cert_dir_path_ = ca_cert_dir_path;
14598inline void ClientImpl::set_proxy_digest_auth(
const std::string &username,
14599 const std::string &password) {
14600 proxy_digest_auth_username_ = username;
14601 proxy_digest_auth_password_ = password;
14604inline void ClientImpl::enable_server_certificate_verification(
bool enabled) {
14605 server_certificate_verification_ = enabled;
14608inline void ClientImpl::enable_server_hostname_verification(
bool enabled) {
14609 server_hostname_verification_ = enabled;
14614#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
14615inline X509_STORE *ClientImpl::create_ca_cert_store(
const char *ca_cert,
14616 std::size_t size)
const {
14617 auto mem = BIO_new_mem_buf(ca_cert,
static_cast<int>(size));
14618 auto se = detail::scope_exit([&] { BIO_free_all(mem); });
14619 if (!mem) {
return nullptr; }
14621 auto inf = PEM_X509_INFO_read_bio(mem,
nullptr,
nullptr,
nullptr);
14622 if (!inf) {
return nullptr; }
14624 auto cts = X509_STORE_new();
14626 for (
auto i = 0; i < static_cast<int>(sk_X509_INFO_num(inf)); i++) {
14627 auto itmp = sk_X509_INFO_value(inf, i);
14628 if (!itmp) {
continue; }
14630 if (itmp->x509) { X509_STORE_add_cert(cts, itmp->x509); }
14631 if (itmp->crl) { X509_STORE_add_crl(cts, itmp->crl); }
14635 sk_X509_INFO_pop_free(inf, X509_INFO_free);
14639inline void ClientImpl::set_server_certificate_verifier(
14658#ifdef CPPHTTPLIB_SSL_ENABLED
14660 tls::shutdown(session,
true);
14661 tls::free_session(session);
14674 :
Client(scheme_host_port, std::string(), std::string()) {}
14677 const std::string &client_cert_path,
14678 const std::string &client_key_path) {
14679 const static std::regex re(
14680 R
"((?:([a-z]+):\/\/)?(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?)");
14683 if (std::regex_match(scheme_host_port, m, re)) {
14684 auto scheme = m[1].str();
14686#ifdef CPPHTTPLIB_SSL_ENABLED
14687 if (!scheme.empty() && (scheme !=
"http" && scheme !=
"https")) {
14689 if (!scheme.empty() && scheme !=
"http") {
14691#ifndef CPPHTTPLIB_NO_EXCEPTIONS
14692 std::string msg =
"'" + scheme +
"' scheme is not supported.";
14693 throw std::invalid_argument(msg);
14698 auto is_ssl = scheme ==
"https";
14700 auto host = m[2].str();
14701 if (
host.empty()) {
host = m[3].str(); }
14703 auto port_str = m[4].str();
14704 auto port = is_ssl ? 443 : 80;
14708#ifdef CPPHTTPLIB_SSL_ENABLED
14721 client_cert_path, client_key_path);
14729 const std::string &client_cert_path,
14730 const std::string &client_key_path)
14732 client_key_path)) {}
14737 return cli_ !=
nullptr && cli_->is_valid();
14741 return cli_->Get(path, std::move(progress));
14745 return cli_->Get(path, headers, std::move(progress));
14750 return cli_->Get(path, std::move(content_receiver), std::move(progress));
14755 return cli_->Get(path, headers, std::move(content_receiver),
14756 std::move(progress));
14762 return cli_->Get(path, std::move(response_handler),
14763 std::move(content_receiver), std::move(progress));
14769 return cli_->Get(path, headers, std::move(response_handler),
14770 std::move(content_receiver), std::move(progress));
14774 return cli_->Get(path, params, headers, std::move(progress));
14780 return cli_->Get(path, params, headers, std::move(content_receiver),
14781 std::move(progress));
14788 return cli_->Get(path, params, headers, std::move(response_handler),
14789 std::move(content_receiver), std::move(progress));
14794 return cli_->Head(path, headers);
14799 return cli_->Post(path, headers);
14802 size_t content_length,
14803 const std::string &content_type,
14805 return cli_->Post(path, body, content_length, content_type, progress);
14808 const char *body,
size_t content_length,
14809 const std::string &content_type,
14811 return cli_->Post(path, headers, body, content_length, content_type,
14815 const std::string &content_type,
14817 return cli_->Post(path, body, content_type, progress);
14820 const std::string &body,
14821 const std::string &content_type,
14823 return cli_->Post(path, headers, body, content_type, progress);
14827 const std::string &content_type,
14829 return cli_->Post(path, content_length, std::move(content_provider),
14830 content_type, progress);
14834 const std::string &content_type,
14837 return cli_->Post(path, content_length, std::move(content_provider),
14838 content_type, std::move(content_receiver), progress);
14842 const std::string &content_type,
14844 return cli_->Post(path, std::move(content_provider), content_type, progress);
14848 const std::string &content_type,
14851 return cli_->Post(path, std::move(content_provider), content_type,
14852 std::move(content_receiver), progress);
14855 size_t content_length,
14857 const std::string &content_type,
14859 return cli_->Post(path, headers, content_length, std::move(content_provider),
14860 content_type, progress);
14863 size_t content_length,
14865 const std::string &content_type,
14868 return cli_->Post(path, headers, content_length, std::move(content_provider),
14869 content_type, std::move(content_receiver), progress);
14873 const std::string &content_type,
14875 return cli_->Post(path, headers, std::move(content_provider), content_type,
14880 const std::string &content_type,
14883 return cli_->Post(path, headers, std::move(content_provider), content_type,
14884 std::move(content_receiver), progress);
14887 return cli_->Post(path, params);
14891 return cli_->Post(path, headers, params);
14896 return cli_->Post(path, items, progress);
14901 return cli_->Post(path, headers, items, progress);
14905 const std::string &boundary,
14907 return cli_->Post(path, headers, items, boundary, progress);
14913 return cli_->Post(path, headers, items, provider_items, progress);
14916 const std::string &body,
14917 const std::string &content_type,
14920 return cli_->Post(path, headers, body, content_type,
14921 std::move(content_receiver), progress);
14926 return cli_->Put(path, headers);
14929 size_t content_length,
14930 const std::string &content_type,
14932 return cli_->Put(path, body, content_length, content_type, progress);
14935 const char *body,
size_t content_length,
14936 const std::string &content_type,
14938 return cli_->Put(path, headers, body, content_length, content_type, progress);
14941 const std::string &content_type,
14943 return cli_->Put(path, body, content_type, progress);
14946 const std::string &body,
14947 const std::string &content_type,
14949 return cli_->Put(path, headers, body, content_type, progress);
14953 const std::string &content_type,
14955 return cli_->Put(path, content_length, std::move(content_provider),
14956 content_type, progress);
14960 const std::string &content_type,
14963 return cli_->Put(path, content_length, std::move(content_provider),
14964 content_type, std::move(content_receiver), progress);
14968 const std::string &content_type,
14970 return cli_->Put(path, std::move(content_provider), content_type, progress);
14974 const std::string &content_type,
14977 return cli_->Put(path, std::move(content_provider), content_type,
14978 std::move(content_receiver), progress);
14981 size_t content_length,
14983 const std::string &content_type,
14985 return cli_->Put(path, headers, content_length, std::move(content_provider),
14986 content_type, progress);
14989 size_t content_length,
14991 const std::string &content_type,
14994 return cli_->Put(path, headers, content_length, std::move(content_provider),
14995 content_type, std::move(content_receiver), progress);
14999 const std::string &content_type,
15001 return cli_->Put(path, headers, std::move(content_provider), content_type,
15006 const std::string &content_type,
15009 return cli_->Put(path, headers, std::move(content_provider), content_type,
15010 std::move(content_receiver), progress);
15013 return cli_->Put(path, params);
15017 return cli_->Put(path, headers, params);
15022 return cli_->Put(path, items, progress);
15027 return cli_->Put(path, headers, items, progress);
15031 const std::string &boundary,
15033 return cli_->Put(path, headers, items, boundary, progress);
15039 return cli_->Put(path, headers, items, provider_items, progress);
15042 const std::string &body,
15043 const std::string &content_type,
15046 return cli_->Put(path, headers, body, content_type, content_receiver,
15051 return cli_->Patch(path);
15054 return cli_->Patch(path, headers);
15057 size_t content_length,
15058 const std::string &content_type,
15060 return cli_->Patch(path, body, content_length, content_type, progress);
15063 const char *body,
size_t content_length,
15064 const std::string &content_type,
15066 return cli_->Patch(path, headers, body, content_length, content_type,
15070 const std::string &content_type,
15072 return cli_->Patch(path, body, content_type, progress);
15075 const std::string &body,
15076 const std::string &content_type,
15078 return cli_->Patch(path, headers, body, content_type, progress);
15082 const std::string &content_type,
15084 return cli_->Patch(path, content_length, std::move(content_provider),
15085 content_type, progress);
15089 const std::string &content_type,
15092 return cli_->Patch(path, content_length, std::move(content_provider),
15093 content_type, std::move(content_receiver), progress);
15097 const std::string &content_type,
15099 return cli_->Patch(path, std::move(content_provider), content_type, progress);
15103 const std::string &content_type,
15106 return cli_->Patch(path, std::move(content_provider), content_type,
15107 std::move(content_receiver), progress);
15110 size_t content_length,
15112 const std::string &content_type,
15114 return cli_->Patch(path, headers, content_length, std::move(content_provider),
15115 content_type, progress);
15118 size_t content_length,
15120 const std::string &content_type,
15123 return cli_->Patch(path, headers, content_length, std::move(content_provider),
15124 content_type, std::move(content_receiver), progress);
15128 const std::string &content_type,
15130 return cli_->Patch(path, headers, std::move(content_provider), content_type,
15135 const std::string &content_type,
15138 return cli_->Patch(path, headers, std::move(content_provider), content_type,
15139 std::move(content_receiver), progress);
15142 return cli_->Patch(path, params);
15146 return cli_->Patch(path, headers, params);
15151 return cli_->Patch(path, items, progress);
15156 return cli_->Patch(path, headers, items, progress);
15160 const std::string &boundary,
15162 return cli_->Patch(path, headers, items, boundary, progress);
15168 return cli_->Patch(path, headers, items, provider_items, progress);
15171 const std::string &body,
15172 const std::string &content_type,
15175 return cli_->Patch(path, headers, body, content_type, content_receiver,
15181 return cli_->Delete(path, progress);
15185 return cli_->Delete(path, headers, progress);
15188 size_t content_length,
15189 const std::string &content_type,
15191 return cli_->Delete(path, body, content_length, content_type, progress);
15194 const char *body,
size_t content_length,
15195 const std::string &content_type,
15197 return cli_->Delete(path, headers, body, content_length, content_type,
15201 const std::string &content_type,
15203 return cli_->Delete(path, body, content_type, progress);
15206 const std::string &body,
15207 const std::string &content_type,
15209 return cli_->Delete(path, headers, body, content_type, progress);
15213 return cli_->Delete(path, params, progress);
15217 return cli_->Delete(path, headers, params, progress);
15221 return cli_->Options(path);
15224 return cli_->Options(path, headers);
15230 const std::string &body,
const std::string &content_type) {
15231 return cli_->open_stream(method, path, params, headers, body, content_type);
15235 return cli_->send(req, res, error);
15252 cli_->set_hostname_addr_map(std::move(addr_map));
15256 cli_->set_default_headers(std::move(headers));
15260 std::function<ssize_t(
Stream &,
Headers &)>
const &writer) {
15261 cli_->set_header_writer(writer);
15265 cli_->set_address_family(family);
15271 cli_->set_socket_options(std::move(socket_options));
15275 cli_->set_connection_timeout(sec, usec);
15279 cli_->set_read_timeout(sec, usec);
15283 cli_->set_write_timeout(sec, usec);
15287 const std::string &password) {
15288 cli_->set_basic_auth(username, password);
15291 cli_->set_bearer_token_auth(token);
15296 cli_->set_follow_location(on);
15301[[deprecated(
"Use set_path_encode() instead. "
15302 "This function will be removed by v1.0.0.")]]
15304 cli_->set_path_encode(on);
15312 cli_->set_payload_max_length(length);
15316 cli_->set_interface(intf);
15323 const std::string &password) {
15324 cli_->set_proxy_basic_auth(username, password);
15327 cli_->set_proxy_bearer_token_auth(token);
15331 cli_->set_logger(std::move(logger));
15335 cli_->set_error_logger(std::move(error_logger));
15342#ifdef CPPHTTPLIB_SSL_ENABLED
15345inline SSLServer::SSLServer(
const char *cert_path,
const char *private_key_path,
15346 const char *client_ca_cert_file_path,
15347 const char *client_ca_cert_dir_path,
15348 const char *private_key_password) {
15349 using namespace tls;
15351 ctx_ = create_server_context();
15352 if (!ctx_) {
return; }
15355 if (!set_server_cert_file(ctx_, cert_path, private_key_path,
15356 private_key_password)) {
15357 last_ssl_error_ =
static_cast<int>(get_error());
15358 free_context(ctx_);
15364 if (client_ca_cert_file_path || client_ca_cert_dir_path) {
15365 if (!set_client_ca_file(ctx_, client_ca_cert_file_path,
15366 client_ca_cert_dir_path)) {
15367 last_ssl_error_ =
static_cast<int>(get_error());
15368 free_context(ctx_);
15373 set_verify_client(ctx_,
true);
15377inline SSLServer::SSLServer(
const PemMemory &pem) {
15378 using namespace tls;
15379 ctx_ = create_server_context();
15381 if (!set_server_cert_pem(ctx_, pem.cert_pem, pem.key_pem,
15382 pem.private_key_password)) {
15383 last_ssl_error_ =
static_cast<int>(get_error());
15384 free_context(ctx_);
15386 }
else if (pem.client_ca_pem && pem.client_ca_pem_len > 0) {
15387 if (!load_ca_pem(ctx_, pem.client_ca_pem, pem.client_ca_pem_len)) {
15388 last_ssl_error_ =
static_cast<int>(get_error());
15389 free_context(ctx_);
15392 set_verify_client(ctx_,
true);
15398inline SSLServer::SSLServer(
const tls::ContextSetupCallback &setup_callback) {
15399 using namespace tls;
15400 ctx_ = create_server_context();
15402 if (!setup_callback(ctx_)) {
15403 free_context(ctx_);
15409inline SSLServer::~SSLServer() {
15410 if (ctx_) { tls::free_context(ctx_); }
15413inline bool SSLServer::is_valid()
const {
return ctx_ !=
nullptr; }
15415inline bool SSLServer::process_and_close_socket(
socket_t sock) {
15416 using namespace tls;
15419 session_t session =
nullptr;
15421 std::lock_guard<std::mutex> guard(ctx_mutex_);
15422 session = create_session(
static_cast<ctx_t
>(ctx_), sock);
15426 last_ssl_error_ =
static_cast<int>(get_error());
15433 bool handshake_done =
false;
15435 bool websocket_upgraded =
false;
15437 if (handshake_done) { shutdown(session, !websocket_upgraded && ret); }
15438 free_session(session);
15445 if (!accept_nonblocking(session, sock, read_timeout_sec_, read_timeout_usec_,
15447#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
15449 if (tls_err.code == ErrorCode::WantRead) {
15450 last_ssl_error_ = SSL_ERROR_WANT_READ;
15451 }
else if (tls_err.code == ErrorCode::WantWrite) {
15452 last_ssl_error_ = SSL_ERROR_WANT_WRITE;
15454 last_ssl_error_ = SSL_ERROR_SSL;
15457 last_ssl_error_ =
static_cast<int>(get_error());
15462 handshake_done =
true;
15464 std::string remote_addr;
15465 int remote_port = 0;
15468 std::string local_addr;
15469 int local_port = 0;
15472 ret = detail::process_server_socket_ssl(
15473 svr_sock_, session, sock, keep_alive_max_count_, keep_alive_timeout_sec_,
15474 read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
15475 write_timeout_usec_,
15476 [&](
Stream &strm,
bool close_connection,
bool &connection_closed) {
15477 return process_request(
15478 strm, remote_addr, remote_port, local_addr, local_port,
15479 close_connection, connection_closed,
15480 [&](
Request &req) { req.ssl = session; }, &websocket_upgraded);
15486inline bool SSLServer::update_certs_pem(
const char *cert_pem,
15487 const char *key_pem,
15488 const char *client_ca_pem,
15489 const char *password) {
15490 if (!ctx_) {
return false; }
15491 std::lock_guard<std::mutex> guard(ctx_mutex_);
15492 if (!tls::update_server_cert(ctx_, cert_pem, key_pem, password)) {
15495 if (client_ca_pem) {
15496 return tls::update_server_client_ca(ctx_, client_ca_pem);
15502inline SSLClient::~SSLClient() {
15503 if (ctx_) { tls::free_context(ctx_); }
15507 shutdown_ssl_impl(socket_,
true);
15510inline bool SSLClient::is_valid()
const {
return ctx_ !=
nullptr; }
15512inline void SSLClient::shutdown_ssl(Socket &socket,
bool shutdown_gracefully) {
15513 shutdown_ssl_impl(socket, shutdown_gracefully);
15516inline void SSLClient::shutdown_ssl_impl(Socket &socket,
15517 bool shutdown_gracefully) {
15519 assert(socket.ssl ==
nullptr);
15523 tls::shutdown(socket.ssl, shutdown_gracefully);
15525 std::lock_guard<std::mutex> guard(ctx_mutex_);
15526 tls::free_session(socket.ssl);
15528 socket.ssl =
nullptr;
15530 assert(socket.ssl ==
nullptr);
15533inline bool SSLClient::process_socket(
15534 const Socket &socket,
15535 std::chrono::time_point<std::chrono::steady_clock> start_time,
15536 std::function<
bool(
Stream &strm)> callback) {
15537 assert(socket.ssl);
15538 return detail::process_client_socket_ssl(
15539 socket.ssl, socket.sock, read_timeout_sec_, read_timeout_usec_,
15540 write_timeout_sec_, write_timeout_usec_, max_timeout_msec_, start_time,
15541 std::move(callback));
15544inline bool SSLClient::is_ssl()
const {
return true; }
15546inline bool SSLClient::create_and_connect_socket(Socket &socket,
Error &error) {
15554inline bool SSLClient::setup_proxy_connection(
15556 std::chrono::time_point<std::chrono::steady_clock> start_time,
15558 if (proxy_host_.empty() || proxy_port_ == -1) {
return true; }
15560 if (!connect_with_proxy(socket, start_time, res, success, error)) {
15564 if (!initialize_ssl(socket, error)) {
15574inline bool SSLClient::connect_with_proxy(
15576 std::chrono::time_point<std::chrono::steady_clock> start_time,
15581 socket.sock, read_timeout_sec_, read_timeout_usec_,
15582 write_timeout_sec_, write_timeout_usec_, max_timeout_msec_,
15583 start_time, [&](
Stream &strm) {
15585 req2.method =
"CONNECT";
15587 detail::make_host_and_port_string_always_port(host_, port_);
15588 if (max_timeout_msec_ > 0) {
15589 req2.start_time_ = std::chrono::steady_clock::now();
15591 return process_request(strm, req2, proxy_res,
false, error);
15595 shutdown_ssl(socket,
true);
15603 if (!proxy_digest_auth_username_.empty() &&
15604 !proxy_digest_auth_password_.empty()) {
15605 std::map<std::string, std::string> auth;
15609 shutdown_ssl(socket,
true);
15614 if (!ensure_socket_connection(socket, error)) {
15616 output_error_log(error,
nullptr);
15622 socket.sock, read_timeout_sec_, read_timeout_usec_,
15623 write_timeout_sec_, write_timeout_usec_, max_timeout_msec_,
15624 start_time, [&](
Stream &strm) {
15626 req3.method =
"CONNECT";
15627 req3.path = detail::make_host_and_port_string_always_port(
15629 req3.headers.insert(detail::make_digest_authentication_header(
15630 req3, auth, 1, detail::random_string(10),
15631 proxy_digest_auth_username_, proxy_digest_auth_password_,
15633 if (max_timeout_msec_ > 0) {
15634 req3.start_time_ = std::chrono::steady_clock::now();
15636 return process_request(strm, req3, proxy_res,
false, error);
15640 shutdown_ssl(socket,
true);
15653 if (proxy_res.status != StatusCode::OK_200) {
15654 error = Error::ProxyConnection;
15655 output_error_log(error,
nullptr);
15656 res = std::move(proxy_res);
15659 shutdown_ssl(socket,
true);
15668inline bool SSLClient::ensure_socket_connection(Socket &socket, Error &error) {
15669 if (!ClientImpl::ensure_socket_connection(socket, error)) {
return false; }
15671 if (!proxy_host_.empty() && proxy_port_ != -1) {
return true; }
15673 if (!initialize_ssl(socket, error)) {
15683inline SSLClient::SSLClient(
const std::string &host)
15684 : SSLClient(host, 443, std::string(), std::string()) {}
15686inline SSLClient::SSLClient(
const std::string &host,
int port)
15687 : SSLClient(host, port, std::string(), std::string()) {}
15689inline SSLClient::SSLClient(
const std::string &host,
int port,
15690 const std::string &client_cert_path,
15691 const std::string &client_key_path,
15692 const std::string &private_key_password)
15693 :
ClientImpl(host, port, client_cert_path, client_key_path) {
15694 ctx_ = tls::create_client_context();
15695 if (!ctx_) {
return; }
15697 tls::set_min_version(ctx_, tls::Version::TLS1_2);
15699 if (!client_cert_path.empty() && !client_key_path.empty()) {
15700 const char *password =
15701 private_key_password.empty() ? nullptr : private_key_password.c_str();
15702 if (!tls::set_client_cert_file(ctx_, client_cert_path.c_str(),
15703 client_key_path.c_str(), password)) {
15704 last_backend_error_ = tls::get_error();
15705 tls::free_context(ctx_);
15711inline SSLClient::SSLClient(
const std::string &host,
int port,
15712 const PemMemory &pem)
15714 ctx_ = tls::create_client_context();
15715 if (!ctx_) {
return; }
15717 tls::set_min_version(ctx_, tls::Version::TLS1_2);
15719 if (pem.cert_pem && pem.key_pem) {
15720 if (!tls::set_client_cert_pem(ctx_, pem.cert_pem, pem.key_pem,
15721 pem.private_key_password)) {
15722 last_backend_error_ = tls::get_error();
15723 tls::free_context(ctx_);
15729inline void SSLClient::set_ca_cert_store(tls::ca_store_t ca_cert_store) {
15730 if (ca_cert_store && ctx_) {
15732 tls::set_ca_store(ctx_, ca_cert_store);
15733 }
else if (ca_cert_store) {
15734 tls::free_ca_store(ca_cert_store);
15739SSLClient::set_server_certificate_verifier(tls::VerifyCallback verifier) {
15740 if (!ctx_) {
return; }
15741 tls::set_verify_callback(ctx_, verifier);
15744inline void SSLClient::set_session_verifier(
15746 session_verifier_ = std::move(verifier);
15749#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
15750inline void SSLClient::enable_windows_certificate_verification(
bool enabled) {
15751 enable_windows_cert_verification_ = enabled;
15755inline void SSLClient::load_ca_cert_store(
const char *ca_cert,
15756 std::size_t size) {
15757 if (ctx_ && ca_cert && size > 0) {
15758 ca_cert_pem_.assign(ca_cert, size);
15759 tls::load_ca_pem(ctx_, ca_cert, size);
15763inline bool SSLClient::load_certs() {
15766 std::call_once(initialize_cert_, [&]() {
15767 std::lock_guard<std::mutex> guard(ctx_mutex_);
15769 if (!ca_cert_file_path_.empty()) {
15770 if (!tls::load_ca_file(ctx_, ca_cert_file_path_.c_str())) {
15771 last_backend_error_ = tls::get_error();
15774 }
else if (!ca_cert_dir_path_.empty()) {
15775 if (!tls::load_ca_dir(ctx_, ca_cert_dir_path_.c_str())) {
15776 last_backend_error_ = tls::get_error();
15779 }
else if (ca_cert_pem_.empty()) {
15780 if (!tls::load_system_certs(ctx_)) {
15781 last_backend_error_ = tls::get_error();
15789inline bool SSLClient::initialize_ssl(Socket &socket,
Error &error) {
15790 using namespace tls;
15793 if (server_certificate_verification_) {
15794 if (!load_certs()) {
15796 output_error_log(error,
nullptr);
15801 bool is_ip = detail::is_ip_address(host_);
15803#if defined(CPPHTTPLIB_MBEDTLS_SUPPORT) || defined(CPPHTTPLIB_WOLFSSL_SUPPORT)
15808 if (is_ip && server_certificate_verification_) {
15809 set_verify_client(ctx_,
false);
15811 set_verify_client(ctx_, server_certificate_verification_);
15816 session_t session =
nullptr;
15818 std::lock_guard<std::mutex> guard(ctx_mutex_);
15819 session = create_session(ctx_, socket.sock);
15824 last_backend_error_ = get_error();
15829 bool success =
false;
15831 if (!success) { free_session(session); }
15838 if (!set_sni(session, host_.c_str())) {
15840 last_backend_error_ = get_error();
15847 if (!connect_nonblocking(session, socket.sock, connection_timeout_sec_,
15848 connection_timeout_usec_, &tls_err)) {
15849 last_ssl_error_ =
static_cast<int>(tls_err.code);
15850 last_backend_error_ = tls_err.backend_code;
15851 if (tls_err.code == ErrorCode::CertVerifyFailed) {
15853 }
else if (tls_err.code == ErrorCode::HostnameMismatch) {
15858 output_error_log(error,
nullptr);
15864 if (session_verifier_) { verification_status = session_verifier_(session); }
15867 last_backend_error_ = get_error();
15869 output_error_log(error,
nullptr);
15875 server_certificate_verification_) {
15876 verify_result_ = tls::get_verify_result(session);
15877 if (verify_result_ != 0) {
15878 last_backend_error_ =
static_cast<uint64_t
>(verify_result_);
15880 output_error_log(error,
nullptr);
15884 auto server_cert = get_peer_cert(session);
15885 if (!server_cert) {
15886 last_backend_error_ = get_error();
15888 output_error_log(error,
nullptr);
15898 if (server_hostname_verification_) {
15899 if (!verify_hostname(server_cert, host_.c_str())) {
15900 last_backend_error_ = hostname_mismatch_code();
15902 output_error_log(error,
nullptr);
15907#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
15913 if (enable_windows_cert_verification_ && ca_cert_file_path_.empty() &&
15914 ca_cert_dir_path_.empty() && ca_cert_pem_.empty()) {
15915 std::vector<unsigned char> der;
15916 if (get_cert_der(server_cert, der)) {
15917 uint64_t wincrypt_error = 0;
15918 if (!detail::verify_cert_with_windows_schannel(
15919 der, host_, server_hostname_verification_, wincrypt_error)) {
15920 last_backend_error_ = wincrypt_error;
15922 output_error_log(error,
nullptr);
15931 socket.ssl = session;
15935inline void Client::set_digest_auth(
const std::string &username,
15936 const std::string &password) {
15937 cli_->set_digest_auth(username, password);
15940inline void Client::set_proxy_digest_auth(
const std::string &username,
15941 const std::string &password) {
15942 cli_->set_proxy_digest_auth(username, password);
15945inline void Client::enable_server_certificate_verification(
bool enabled) {
15946 cli_->enable_server_certificate_verification(enabled);
15949inline void Client::enable_server_hostname_verification(
bool enabled) {
15950 cli_->enable_server_hostname_verification(enabled);
15953#ifdef CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE
15954inline void Client::enable_windows_certificate_verification(
bool enabled) {
15956 static_cast<SSLClient &
>(*cli_).enable_windows_certificate_verification(
15962inline void Client::set_ca_cert_path(
const std::string &ca_cert_file_path,
15963 const std::string &ca_cert_dir_path) {
15964 cli_->set_ca_cert_path(ca_cert_file_path, ca_cert_dir_path);
15967inline void Client::set_ca_cert_store(tls::ca_store_t ca_cert_store) {
15969 static_cast<SSLClient &
>(*cli_).set_ca_cert_store(ca_cert_store);
15970 }
else if (ca_cert_store) {
15971 tls::free_ca_store(ca_cert_store);
15975inline void Client::load_ca_cert_store(
const char *ca_cert, std::size_t size) {
15976 set_ca_cert_store(tls::create_ca_store(ca_cert, size));
15980Client::set_server_certificate_verifier(tls::VerifyCallback verifier) {
15982 static_cast<SSLClient &
>(*cli_).set_server_certificate_verifier(
15983 std::move(verifier));
15987inline void Client::set_session_verifier(
15990 static_cast<SSLClient &
>(*cli_).set_session_verifier(std::move(verifier));
15994inline tls::ctx_t Client::tls_context()
const {
15995 if (is_ssl_) {
return static_cast<SSLClient &
>(*cli_).tls_context(); }
16005#ifdef CPPHTTPLIB_SSL_ENABLED
16010inline PeerCert get_peer_cert_from_session(const_session_t session) {
16011 return PeerCert(get_peer_cert(session));
16016inline VerifyCallback &get_verify_callback() {
16017 static thread_local VerifyCallback callback;
16021inline VerifyCallback &get_mbedtls_verify_callback() {
16022 static thread_local VerifyCallback callback;
16027inline bool is_ipv4_address(
const std::string &str) {
16029 for (
char c : str) {
16032 }
else if (!isdigit(
static_cast<unsigned char>(c))) {
16040inline bool parse_ipv4(
const std::string &str,
unsigned char *out) {
16041 const char *p = str.c_str();
16042 for (
int i = 0; i < 4; i++) {
16044 if (*p !=
'.') {
return false; }
16049 while (*p >=
'0' && *p <=
'9') {
16050 val = val * 10 + (*p -
'0');
16051 if (val > 255) {
return false; }
16055 if (digits == 0) {
return false; }
16057 if (digits > 1 && *(p - digits) ==
'0') {
return false; }
16058 out[i] =
static_cast<unsigned char>(val);
16065template <
typename Callback>
16066inline bool enumerate_windows_system_certs(Callback cb) {
16067 bool loaded =
false;
16068 static const wchar_t *store_names[] = {L
"ROOT", L
"CA"};
16069 for (
auto store_name : store_names) {
16070 HCERTSTORE hStore = CertOpenSystemStoreW(0, store_name);
16072 PCCERT_CONTEXT pContext =
nullptr;
16073 while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) !=
16075 if (cb(pContext->pbCertEncoded, pContext->cbCertEncoded)) {
16079 CertCloseStore(hStore, 0);
16086#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
16088template <
typename Callback>
16089inline bool enumerate_macos_keychain_certs(Callback cb) {
16090 bool loaded =
false;
16091 CFArrayRef certs =
nullptr;
16092 OSStatus status = SecTrustCopyAnchorCertificates(&certs);
16093 if (status == errSecSuccess && certs) {
16094 CFIndex count = CFArrayGetCount(certs);
16095 for (CFIndex i = 0; i < count; i++) {
16096 SecCertificateRef cert =
16097 (SecCertificateRef)CFArrayGetValueAtIndex(certs, i);
16098 CFDataRef data = SecCertificateCopyData(cert);
16100 if (cb(CFDataGetBytePtr(data),
16101 static_cast<size_t>(CFDataGetLength(data)))) {
16113#if !defined(_WIN32) && !(defined(__APPLE__) && \
16114 defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN))
16116inline const char **system_ca_paths() {
16117 static const char *paths[] = {
16118 "/etc/ssl/certs/ca-certificates.crt",
16119 "/etc/pki/tls/certs/ca-bundle.crt",
16120 "/etc/ssl/ca-bundle.pem",
16121 "/etc/pki/tls/cacert.pem",
16122 "/etc/ssl/cert.pem",
16128inline const char **system_ca_dirs() {
16129 static const char *dirs[] = {
"/etc/ssl/certs",
16130 "/etc/pki/tls/certs",
16131 "/usr/share/ca-certificates",
16139inline bool set_client_ca_file(ctx_t ctx,
const char *ca_file,
16140 const char *ca_dir) {
16141 if (!ctx) {
return false; }
16143 bool success =
true;
16144 if (ca_file && *ca_file) {
16145 if (!load_ca_file(ctx, ca_file)) { success =
false; }
16147 if (ca_dir && *ca_dir) {
16148 if (!load_ca_dir(ctx, ca_dir)) { success =
false; }
16151#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
16153 if (ca_file && *ca_file) {
16154 auto list = SSL_load_client_CA_file(ca_file);
16155 if (list) { SSL_CTX_set_client_CA_list(
static_cast<SSL_CTX *
>(ctx), list); }
16162inline bool set_server_cert_pem(ctx_t ctx,
const char *cert,
const char *key,
16163 const char *password) {
16164 return set_client_cert_pem(ctx, cert, key, password);
16167inline bool set_server_cert_file(ctx_t ctx,
const char *cert_path,
16168 const char *key_path,
const char *password) {
16169 return set_client_cert_file(ctx, cert_path, key_path, password);
16173inline PeerCert::PeerCert() =
default;
16175inline PeerCert::PeerCert(cert_t cert) : cert_(cert) {}
16177inline PeerCert::PeerCert(PeerCert &&other) noexcept : cert_(other.cert_) {
16178 other.cert_ =
nullptr;
16181inline PeerCert &PeerCert::operator=(PeerCert &&other)
noexcept {
16182 if (
this != &other) {
16183 if (cert_) { free_cert(cert_); }
16184 cert_ = other.cert_;
16185 other.cert_ =
nullptr;
16190inline PeerCert::~PeerCert() {
16191 if (cert_) { free_cert(cert_); }
16194inline PeerCert::operator bool()
const {
return cert_ !=
nullptr; }
16196inline std::string PeerCert::subject_cn()
const {
16197 return cert_ ? get_cert_subject_cn(cert_) : std::string();
16200inline std::string PeerCert::issuer_name()
const {
16201 return cert_ ? get_cert_issuer_name(cert_) : std::string();
16204inline bool PeerCert::check_hostname(
const char *hostname)
const {
16205 return cert_ ? verify_hostname(cert_, hostname) : false;
16208inline std::vector<SanEntry> PeerCert::sans()
const {
16209 std::vector<SanEntry> result;
16210 if (cert_) { get_cert_sans(cert_, result); }
16214inline bool PeerCert::validity(time_t ¬_before, time_t ¬_after)
const {
16215 return cert_ ? get_cert_validity(cert_, not_before, not_after) : false;
16218inline std::string PeerCert::serial()
const {
16219 return cert_ ? get_cert_serial(cert_) : std::string();
16223inline std::string VerifyContext::subject_cn()
const {
16224 return cert ? get_cert_subject_cn(cert) : std::string();
16227inline std::string VerifyContext::issuer_name()
const {
16228 return cert ? get_cert_issuer_name(cert) : std::string();
16231inline bool VerifyContext::check_hostname(
const char *hostname)
const {
16232 return cert ? verify_hostname(cert, hostname) : false;
16235inline std::vector<SanEntry> VerifyContext::sans()
const {
16236 std::vector<SanEntry> result;
16237 if (cert) { get_cert_sans(cert, result); }
16241inline bool VerifyContext::validity(time_t ¬_before,
16242 time_t ¬_after)
const {
16243 return cert ? get_cert_validity(cert, not_before, not_after) : false;
16246inline std::string VerifyContext::serial()
const {
16247 return cert ? get_cert_serial(cert) : std::string();
16251inline std::string TlsError::verify_error_to_string(
long error_code) {
16252 return verify_error_string(error_code);
16258inline tls::PeerCert Request::peer_cert()
const {
16259 return tls::get_peer_cert_from_session(ssl);
16263inline std::string Request::sni()
const {
16264 if (!ssl) {
return std::string(); }
16265 const char *s = tls::get_sni(ssl);
16266 return s ? std::string(s) : std::string();
16275#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
16276inline SSL_CTX *Client::ssl_context()
const {
16277 if (is_ssl_) {
return static_cast<SSLClient &
>(*cli_).ssl_context(); }
16281inline void Client::set_server_certificate_verifier(
16283 cli_->set_server_certificate_verifier(verifier);
16286inline long Client::get_verify_result()
const {
16287 if (is_ssl_) {
return static_cast<SSLClient &
>(*cli_).get_verify_result(); }
16296#ifdef CPPHTTPLIB_OPENSSL_SUPPORT
16302inline std::string x509_to_pem(X509 *cert) {
16303 if (!cert)
return {};
16304 BIO *bio = BIO_new(BIO_s_mem());
16305 if (!bio)
return {};
16306 if (PEM_write_bio_X509(bio, cert) != 1) {
16310 char *data =
nullptr;
16311 long len = BIO_get_mem_data(bio, &data);
16312 std::string pem(data,
static_cast<size_t>(len));
16317inline std::string evp_pkey_to_pem(EVP_PKEY *key) {
16318 if (!key)
return {};
16319 BIO *bio = BIO_new(BIO_s_mem());
16320 if (!bio)
return {};
16321 if (PEM_write_bio_PrivateKey(bio, key,
nullptr,
nullptr, 0,
nullptr,
16326 char *data =
nullptr;
16327 long len = BIO_get_mem_data(bio, &data);
16328 std::string pem(data,
static_cast<size_t>(len));
16333inline std::string x509_store_to_pem(X509_STORE *store) {
16334 if (!store)
return {};
16336 auto objs = X509_STORE_get0_objects(store);
16337 if (!objs)
return {};
16338 auto count = sk_X509_OBJECT_num(objs);
16339 for (
decltype(count) i = 0; i < count; i++) {
16340 auto obj = sk_X509_OBJECT_value(objs, i);
16341 if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
16342 auto cert = X509_OBJECT_get0_X509(obj);
16343 if (cert) { pem += x509_to_pem(cert); }
16350inline ErrorCode map_ssl_error(
int ssl_error,
int &out_errno) {
16351 switch (ssl_error) {
16352 case SSL_ERROR_NONE:
return ErrorCode::Success;
16353 case SSL_ERROR_WANT_READ:
return ErrorCode::WantRead;
16354 case SSL_ERROR_WANT_WRITE:
return ErrorCode::WantWrite;
16355 case SSL_ERROR_ZERO_RETURN:
return ErrorCode::PeerClosed;
16356 case SSL_ERROR_SYSCALL: out_errno = errno;
return ErrorCode::SyscallError;
16357 case SSL_ERROR_SSL:
16358 default:
return ErrorCode::Fatal;
16365inline STACK_OF(X509_NAME) *
16366 create_client_ca_list_from_pem(
const char *ca_pem) {
16367 if (!ca_pem) {
return nullptr; }
16369 auto ca_list = sk_X509_NAME_new_null();
16370 if (!ca_list) {
return nullptr; }
16372 BIO *bio = BIO_new_mem_buf(ca_pem, -1);
16374 sk_X509_NAME_pop_free(ca_list, X509_NAME_free);
16378 X509 *cert =
nullptr;
16379 while ((cert = PEM_read_bio_X509(bio,
nullptr,
nullptr,
nullptr)) !=
16381 X509_NAME *name = X509_get_subject_name(cert);
16382 if (name) { sk_X509_NAME_push(ca_list, X509_NAME_dup(name)); }
16393inline STACK_OF(X509_NAME) *
16394 extract_client_ca_list_from_store(X509_STORE *store) {
16395 if (!store) {
return nullptr; }
16397 auto ca_list = sk_X509_NAME_new_null();
16398 if (!ca_list) {
return nullptr; }
16400 auto objs = X509_STORE_get0_objects(store);
16402 sk_X509_NAME_free(ca_list);
16406 auto count = sk_X509_OBJECT_num(objs);
16407 for (
decltype(count) i = 0; i < count; i++) {
16408 auto obj = sk_X509_OBJECT_value(objs, i);
16409 if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
16410 auto cert = X509_OBJECT_get0_X509(obj);
16412 auto subject = X509_get_subject_name(cert);
16414 auto name_dup = X509_NAME_dup(subject);
16415 if (name_dup) { sk_X509_NAME_push(ca_list, name_dup); }
16421 if (sk_X509_NAME_num(ca_list) == 0) {
16422 sk_X509_NAME_free(ca_list);
16430inline int openssl_verify_callback(
int preverify_ok, X509_STORE_CTX *ctx) {
16431 auto &callback = get_verify_callback();
16432 if (!callback) {
return preverify_ok; }
16435 auto ssl =
static_cast<SSL *
>(
16436 X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
16437 if (!ssl) {
return preverify_ok; }
16440 auto cert = X509_STORE_CTX_get_current_cert(ctx);
16441 int depth = X509_STORE_CTX_get_error_depth(ctx);
16442 int error = X509_STORE_CTX_get_error(ctx);
16445 VerifyContext verify_ctx;
16446 verify_ctx.session =
static_cast<session_t
>(ssl);
16447 verify_ctx.cert =
static_cast<cert_t
>(cert);
16448 verify_ctx.depth = depth;
16449 verify_ctx.preverify_ok = (preverify_ok != 0);
16450 verify_ctx.error_code = error;
16451 verify_ctx.error_string =
16452 (error != X509_V_OK) ? X509_verify_cert_error_string(error) :
nullptr;
16454 return callback(verify_ctx) ? 1 : 0;
16459inline ctx_t create_client_context() {
16460 SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
16463 SSL_CTX_clear_mode(ctx, SSL_MODE_AUTO_RETRY);
16465 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
16467 return static_cast<ctx_t
>(ctx);
16470inline void free_context(ctx_t ctx) {
16471 if (ctx) { SSL_CTX_free(
static_cast<SSL_CTX *
>(ctx)); }
16474inline bool set_min_version(ctx_t ctx, Version version) {
16475 if (!ctx)
return false;
16476 return SSL_CTX_set_min_proto_version(
static_cast<SSL_CTX *
>(ctx),
16477 static_cast<int>(version)) == 1;
16480inline bool load_ca_pem(ctx_t ctx,
const char *pem,
size_t len) {
16481 if (!ctx || !pem || len == 0)
return false;
16483 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
16484 auto store = SSL_CTX_get_cert_store(ssl_ctx);
16485 if (!store)
return false;
16487 auto bio = BIO_new_mem_buf(pem,
static_cast<int>(len));
16488 if (!bio)
return false;
16491 X509 *cert =
nullptr;
16492 while ((cert = PEM_read_bio_X509(bio,
nullptr,
nullptr,
nullptr)) !=
16494 if (X509_STORE_add_cert(store, cert) != 1) {
16496 auto err = ERR_peek_last_error();
16497 if (ERR_GET_REASON(err) != X509_R_CERT_ALREADY_IN_HASH_TABLE) {
16511inline bool load_ca_file(ctx_t ctx,
const char *file_path) {
16512 if (!ctx || !file_path)
return false;
16513 return SSL_CTX_load_verify_locations(
static_cast<SSL_CTX *
>(ctx), file_path,
16517inline bool load_ca_dir(ctx_t ctx,
const char *dir_path) {
16518 if (!ctx || !dir_path)
return false;
16519 return SSL_CTX_load_verify_locations(
static_cast<SSL_CTX *
>(ctx),
nullptr,
16523inline bool load_system_certs(ctx_t ctx) {
16524 if (!ctx)
return false;
16525 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
16529 auto store = SSL_CTX_get_cert_store(ssl_ctx);
16530 if (!store)
return false;
16532 bool loaded_any =
false;
16533 static const wchar_t *store_names[] = {L
"ROOT", L
"CA"};
16534 for (
auto store_name : store_names) {
16535 auto hStore = CertOpenSystemStoreW(NULL, store_name);
16536 if (!hStore)
continue;
16538 PCCERT_CONTEXT pContext =
nullptr;
16539 while ((pContext = CertEnumCertificatesInStore(hStore, pContext)) !=
16541 const unsigned char *data = pContext->pbCertEncoded;
16542 auto x509 = d2i_X509(
nullptr, &data, pContext->cbCertEncoded);
16544 if (X509_STORE_add_cert(store, x509) == 1) { loaded_any =
true; }
16548 CertCloseStore(hStore, 0);
16552#elif defined(__APPLE__)
16553#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN
16555 auto store = SSL_CTX_get_cert_store(ssl_ctx);
16556 if (!store)
return false;
16558 CFArrayRef certs =
nullptr;
16559 if (SecTrustCopyAnchorCertificates(&certs) != errSecSuccess || !certs) {
16560 return SSL_CTX_set_default_verify_paths(ssl_ctx) == 1;
16563 bool loaded_any =
false;
16564 auto count = CFArrayGetCount(certs);
16565 for (CFIndex i = 0; i < count; i++) {
16566 auto cert =
reinterpret_cast<SecCertificateRef
>(
16567 const_cast<void *
>(CFArrayGetValueAtIndex(certs, i)));
16568 CFDataRef der = SecCertificateCopyData(cert);
16570 const unsigned char *data = CFDataGetBytePtr(der);
16571 auto x509 = d2i_X509(
nullptr, &data, CFDataGetLength(der));
16573 if (X509_STORE_add_cert(store, x509) == 1) { loaded_any =
true; }
16580 return loaded_any || SSL_CTX_set_default_verify_paths(ssl_ctx) == 1;
16582 return SSL_CTX_set_default_verify_paths(ssl_ctx) == 1;
16587 return SSL_CTX_set_default_verify_paths(ssl_ctx) == 1;
16591inline bool set_client_cert_pem(ctx_t ctx,
const char *cert,
const char *key,
16592 const char *password) {
16593 if (!ctx || !cert || !key)
return false;
16595 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
16598 auto cert_bio = BIO_new_mem_buf(cert, -1);
16599 if (!cert_bio)
return false;
16601 auto x509 = PEM_read_bio_X509(cert_bio,
nullptr,
nullptr,
nullptr);
16602 BIO_free(cert_bio);
16603 if (!x509)
return false;
16605 auto cert_ok = SSL_CTX_use_certificate(ssl_ctx, x509) == 1;
16607 if (!cert_ok)
return false;
16610 auto key_bio = BIO_new_mem_buf(key, -1);
16611 if (!key_bio)
return false;
16613 auto pkey = PEM_read_bio_PrivateKey(key_bio,
nullptr,
nullptr,
16614 password ?
const_cast<char *
>(password)
16617 if (!pkey)
return false;
16619 auto key_ok = SSL_CTX_use_PrivateKey(ssl_ctx, pkey) == 1;
16620 EVP_PKEY_free(pkey);
16622 return key_ok && SSL_CTX_check_private_key(ssl_ctx) == 1;
16625inline bool set_client_cert_file(ctx_t ctx,
const char *cert_path,
16626 const char *key_path,
const char *password) {
16627 if (!ctx || !cert_path || !key_path)
return false;
16629 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
16631 if (password && password[0] !=
'\0') {
16632 SSL_CTX_set_default_passwd_cb_userdata(
16633 ssl_ctx,
reinterpret_cast<void *
>(
const_cast<char *
>(password)));
16636 return SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_path) == 1 &&
16637 SSL_CTX_use_PrivateKey_file(ssl_ctx, key_path, SSL_FILETYPE_PEM) == 1;
16640inline ctx_t create_server_context() {
16641 SSL_CTX *ctx = SSL_CTX_new(TLS_server_method());
16643 SSL_CTX_set_options(ctx, SSL_OP_NO_COMPRESSION |
16644 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
16645 SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION);
16647 return static_cast<ctx_t
>(ctx);
16650inline void set_verify_client(ctx_t ctx,
bool require) {
16652 SSL_CTX_set_verify(
static_cast<SSL_CTX *
>(ctx),
16654 ? (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
16659inline session_t create_session(ctx_t ctx,
socket_t sock) {
16662 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
16663 SSL *ssl = SSL_new(ssl_ctx);
16664 if (!ssl)
return nullptr;
16667 SSL_clear_mode(ssl, SSL_MODE_AUTO_RETRY);
16669 auto bio = BIO_new_socket(
static_cast<int>(sock), BIO_NOCLOSE);
16675 SSL_set_bio(ssl, bio, bio);
16676 return static_cast<session_t
>(ssl);
16679inline void free_session(session_t session) {
16680 if (session) { SSL_free(
static_cast<SSL *
>(session)); }
16683inline bool set_sni(session_t session,
const char *hostname) {
16684 if (!session || !hostname)
return false;
16686 auto ssl =
static_cast<SSL *
>(session);
16689#if defined(OPENSSL_IS_BORINGSSL)
16690 return SSL_set_tlsext_host_name(ssl, hostname) == 1;
16693 return SSL_ctrl(ssl, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name,
16694 static_cast<void *
>(
const_cast<char *
>(hostname))) == 1;
16698inline bool set_hostname(session_t session,
const char *hostname) {
16699 if (!session || !hostname)
return false;
16701 auto ssl =
static_cast<SSL *
>(session);
16704 if (!set_sni(session, hostname)) {
return false; }
16707 auto param = SSL_get0_param(ssl);
16708 if (!param)
return false;
16710 X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
16711 if (X509_VERIFY_PARAM_set1_host(param, hostname, 0) != 1) {
return false; }
16713 SSL_set_verify(ssl, SSL_VERIFY_PEER,
nullptr);
16717inline TlsError connect(session_t session) {
16718 if (!session) {
return TlsError(); }
16720 auto ssl =
static_cast<SSL *
>(session);
16721 auto ret = SSL_connect(ssl);
16725 err.code = ErrorCode::Success;
16727 auto ssl_err = SSL_get_error(ssl, ret);
16728 err.code = impl::map_ssl_error(ssl_err, err.sys_errno);
16729 err.backend_code = ERR_get_error();
16734inline TlsError accept(session_t session) {
16735 if (!session) {
return TlsError(); }
16737 auto ssl =
static_cast<SSL *
>(session);
16738 auto ret = SSL_accept(ssl);
16742 err.code = ErrorCode::Success;
16744 auto ssl_err = SSL_get_error(ssl, ret);
16745 err.code = impl::map_ssl_error(ssl_err, err.sys_errno);
16746 err.backend_code = ERR_get_error();
16751inline bool connect_nonblocking(session_t session,
socket_t sock,
16752 time_t timeout_sec, time_t timeout_usec,
16755 if (err) { err->code = ErrorCode::Fatal; }
16759 auto ssl =
static_cast<SSL *
>(session);
16760 auto bio = SSL_get_rbio(ssl);
16763 detail::set_nonblocking(sock,
true);
16764 if (bio) { BIO_set_nbio(bio, 1); }
16766 auto cleanup = detail::scope_exit([&]() {
16768 if (bio) { BIO_set_nbio(bio, 0); }
16769 detail::set_nonblocking(sock,
false);
16773 while ((res = SSL_connect(ssl)) != 1) {
16774 auto ssl_err = SSL_get_error(ssl, res);
16776 case SSL_ERROR_WANT_READ:
16777 if (detail::select_read(sock, timeout_sec, timeout_usec) > 0) {
16781 case SSL_ERROR_WANT_WRITE:
16782 if (detail::select_write(sock, timeout_sec, timeout_usec) > 0) {
16789 err->code = impl::map_ssl_error(ssl_err, err->sys_errno);
16790 err->backend_code = ERR_get_error();
16794 if (err) { err->code = ErrorCode::Success; }
16798inline bool accept_nonblocking(session_t session,
socket_t sock,
16799 time_t timeout_sec, time_t timeout_usec,
16802 if (err) { err->code = ErrorCode::Fatal; }
16806 auto ssl =
static_cast<SSL *
>(session);
16807 auto bio = SSL_get_rbio(ssl);
16810 detail::set_nonblocking(sock,
true);
16811 if (bio) { BIO_set_nbio(bio, 1); }
16813 auto cleanup = detail::scope_exit([&]() {
16815 if (bio) { BIO_set_nbio(bio, 0); }
16816 detail::set_nonblocking(sock,
false);
16820 while ((res = SSL_accept(ssl)) != 1) {
16821 auto ssl_err = SSL_get_error(ssl, res);
16823 case SSL_ERROR_WANT_READ:
16824 if (detail::select_read(sock, timeout_sec, timeout_usec) > 0) {
16828 case SSL_ERROR_WANT_WRITE:
16829 if (detail::select_write(sock, timeout_sec, timeout_usec) > 0) {
16836 err->code = impl::map_ssl_error(ssl_err, err->sys_errno);
16837 err->backend_code = ERR_get_error();
16841 if (err) { err->code = ErrorCode::Success; }
16845inline ssize_t read(session_t session,
void *buf,
size_t len, TlsError &err) {
16846 if (!session || !buf) {
16847 err.code = ErrorCode::Fatal;
16851 auto ssl =
static_cast<SSL *
>(session);
16852 constexpr auto max_len =
16853 static_cast<size_t>((std::numeric_limits<int>::max)());
16854 if (len > max_len) { len = max_len; }
16855 auto ret = SSL_read(ssl, buf,
static_cast<int>(len));
16858 err.code = ErrorCode::Success;
16862 auto ssl_err = SSL_get_error(ssl, ret);
16863 err.code = impl::map_ssl_error(ssl_err, err.sys_errno);
16864 if (err.code == ErrorCode::Fatal) { err.backend_code = ERR_get_error(); }
16868inline ssize_t write(session_t session,
const void *buf,
size_t len,
16870 if (!session || !buf) {
16871 err.code = ErrorCode::Fatal;
16875 auto ssl =
static_cast<SSL *
>(session);
16876 auto ret = SSL_write(ssl, buf,
static_cast<int>(len));
16879 err.code = ErrorCode::Success;
16883 auto ssl_err = SSL_get_error(ssl, ret);
16884 err.code = impl::map_ssl_error(ssl_err, err.sys_errno);
16885 if (err.code == ErrorCode::Fatal) { err.backend_code = ERR_get_error(); }
16889inline int pending(const_session_t session) {
16890 if (!session)
return 0;
16891 return SSL_pending(
static_cast<SSL *
>(
const_cast<void *
>(session)));
16894inline void shutdown(session_t session,
bool graceful) {
16895 if (!session)
return;
16897 auto ssl =
static_cast<SSL *
>(session);
16900 if (SSL_shutdown(ssl) == 0) {
16907inline bool is_peer_closed(session_t session,
socket_t sock) {
16908 if (!session)
return true;
16911 detail::set_nonblocking(sock,
true);
16912 auto se = detail::scope_exit([&]() { detail::set_nonblocking(sock,
false); });
16914 auto ssl =
static_cast<SSL *
>(session);
16916 auto ret = SSL_peek(ssl, &buf, 1);
16917 if (ret > 0)
return false;
16919 auto err = SSL_get_error(ssl, ret);
16920 return err == SSL_ERROR_ZERO_RETURN;
16923inline cert_t get_peer_cert(const_session_t session) {
16924 if (!session)
return nullptr;
16925 return static_cast<cert_t
>(SSL_get1_peer_certificate(
16926 static_cast<SSL *
>(
const_cast<void *
>(session))));
16929inline void free_cert(cert_t cert) {
16930 if (cert) { X509_free(
static_cast<X509 *
>(cert)); }
16933inline bool verify_hostname(cert_t cert,
const char *hostname) {
16934 if (!cert || !hostname)
return false;
16936 auto x509 =
static_cast<X509 *
>(cert);
16939 if (detail::is_ip_address(hostname)) {
16940 return X509_check_ip_asc(x509, hostname, 0) == 1;
16942 return X509_check_host(x509, hostname, strlen(hostname), 0,
nullptr) == 1;
16945inline uint64_t hostname_mismatch_code() {
16946 return static_cast<uint64_t
>(X509_V_ERR_HOSTNAME_MISMATCH);
16949inline long get_verify_result(const_session_t session) {
16950 if (!session)
return X509_V_ERR_UNSPECIFIED;
16951 return SSL_get_verify_result(
static_cast<SSL *
>(
const_cast<void *
>(session)));
16954inline std::string get_cert_subject_cn(cert_t cert) {
16955 if (!cert)
return "";
16956 auto x509 =
static_cast<X509 *
>(cert);
16957 auto subject_name = X509_get_subject_name(x509);
16958 if (!subject_name)
return "";
16962 X509_NAME_get_text_by_NID(subject_name, NID_commonName, buf,
sizeof(buf));
16963 if (len < 0)
return "";
16964 return std::string(buf,
static_cast<size_t>(len));
16967inline std::string get_cert_issuer_name(cert_t cert) {
16968 if (!cert)
return "";
16969 auto x509 =
static_cast<X509 *
>(cert);
16970 auto issuer_name = X509_get_issuer_name(x509);
16971 if (!issuer_name)
return "";
16974 X509_NAME_oneline(issuer_name, buf,
sizeof(buf));
16975 return std::string(buf);
16978inline bool get_cert_sans(cert_t cert, std::vector<SanEntry> &sans) {
16980 if (!cert)
return false;
16981 auto x509 =
static_cast<X509 *
>(cert);
16983 auto names =
static_cast<GENERAL_NAMES *
>(
16984 X509_get_ext_d2i(x509, NID_subject_alt_name,
nullptr,
nullptr));
16985 if (!names)
return true;
16987 auto count = sk_GENERAL_NAME_num(names);
16988 for (
decltype(count) i = 0; i < count; i++) {
16989 auto gen = sk_GENERAL_NAME_value(names, i);
16990 if (!gen)
continue;
16993 switch (gen->type) {
16995 entry.type = SanType::DNS;
16996 if (gen->d.dNSName) {
16997 entry.value = std::string(
16998 reinterpret_cast<const char *
>(
16999 ASN1_STRING_get0_data(gen->d.dNSName)),
17000 static_cast<size_t>(ASN1_STRING_length(gen->d.dNSName)));
17004 entry.type = SanType::IP;
17005 if (gen->d.iPAddress) {
17006 auto data = ASN1_STRING_get0_data(gen->d.iPAddress);
17007 auto len = ASN1_STRING_length(gen->d.iPAddress);
17010 char buf[INET_ADDRSTRLEN];
17011 inet_ntop(AF_INET, data, buf,
sizeof(buf));
17013 }
else if (len == 16) {
17015 char buf[INET6_ADDRSTRLEN];
17016 inet_ntop(AF_INET6, data, buf,
sizeof(buf));
17022 entry.type = SanType::EMAIL;
17023 if (gen->d.rfc822Name) {
17024 entry.value = std::string(
17025 reinterpret_cast<const char *
>(
17026 ASN1_STRING_get0_data(gen->d.rfc822Name)),
17027 static_cast<size_t>(ASN1_STRING_length(gen->d.rfc822Name)));
17031 entry.type = SanType::URI;
17032 if (gen->d.uniformResourceIdentifier) {
17033 entry.value = std::string(
17034 reinterpret_cast<const char *
>(
17035 ASN1_STRING_get0_data(gen->d.uniformResourceIdentifier)),
17036 static_cast<size_t>(
17037 ASN1_STRING_length(gen->d.uniformResourceIdentifier)));
17040 default: entry.type = SanType::OTHER;
break;
17043 if (!entry.value.empty()) { sans.push_back(std::move(entry)); }
17046 GENERAL_NAMES_free(names);
17050inline bool get_cert_validity(cert_t cert, time_t ¬_before,
17051 time_t ¬_after) {
17052 if (!cert)
return false;
17053 auto x509 =
static_cast<X509 *
>(cert);
17055 auto nb = X509_get0_notBefore(x509);
17056 auto na = X509_get0_notAfter(x509);
17057 if (!nb || !na)
return false;
17059 ASN1_TIME *epoch = ASN1_TIME_new();
17060 if (!epoch)
return false;
17061 auto se = detail::scope_exit([&] { ASN1_TIME_free(epoch); });
17063 if (!ASN1_TIME_set(epoch, 0))
return false;
17067 if (!ASN1_TIME_diff(&pday, &psec, epoch, nb))
return false;
17068 not_before = 86400 * (time_t)pday + psec;
17070 if (!ASN1_TIME_diff(&pday, &psec, epoch, na))
return false;
17071 not_after = 86400 * (time_t)pday + psec;
17076inline std::string get_cert_serial(cert_t cert) {
17077 if (!cert)
return "";
17078 auto x509 =
static_cast<X509 *
>(cert);
17080 auto serial = X509_get_serialNumber(x509);
17081 if (!serial)
return "";
17083 auto bn = ASN1_INTEGER_to_BN(serial,
nullptr);
17084 if (!bn)
return "";
17086 auto hex = BN_bn2hex(bn);
17088 if (!hex)
return "";
17090 std::string result(hex);
17095inline bool get_cert_der(cert_t cert, std::vector<unsigned char> &der) {
17096 if (!cert)
return false;
17097 auto x509 =
static_cast<X509 *
>(cert);
17098 auto len = i2d_X509(x509,
nullptr);
17099 if (len < 0)
return false;
17100 der.resize(
static_cast<size_t>(len));
17101 auto p = der.data();
17102 i2d_X509(x509, &p);
17106inline const char *get_sni(const_session_t session) {
17107 if (!session)
return nullptr;
17108 auto ssl =
static_cast<SSL *
>(
const_cast<void *
>(session));
17109 return SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name);
17112inline uint64_t peek_error() {
return ERR_peek_last_error(); }
17114inline uint64_t get_error() {
return ERR_get_error(); }
17116inline std::string error_string(uint64_t code) {
17118 ERR_error_string_n(
static_cast<unsigned long>(code), buf,
sizeof(buf));
17119 return std::string(buf);
17122inline ca_store_t create_ca_store(
const char *pem,
size_t len) {
17123 auto mem = BIO_new_mem_buf(pem,
static_cast<int>(len));
17124 if (!mem) {
return nullptr; }
17125 auto mem_guard = detail::scope_exit([&] { BIO_free_all(mem); });
17127 auto inf = PEM_X509_INFO_read_bio(mem,
nullptr,
nullptr,
nullptr);
17128 if (!inf) {
return nullptr; }
17130 auto store = X509_STORE_new();
17132 for (
auto i = 0; i < static_cast<int>(sk_X509_INFO_num(inf)); i++) {
17133 auto itmp = sk_X509_INFO_value(inf, i);
17134 if (!itmp) {
continue; }
17135 if (itmp->x509) { X509_STORE_add_cert(store, itmp->x509); }
17136 if (itmp->crl) { X509_STORE_add_crl(store, itmp->crl); }
17140 sk_X509_INFO_pop_free(inf, X509_INFO_free);
17141 return static_cast<ca_store_t
>(store);
17144inline void free_ca_store(ca_store_t store) {
17145 if (store) { X509_STORE_free(
static_cast<X509_STORE *
>(store)); }
17148inline bool set_ca_store(ctx_t ctx, ca_store_t store) {
17149 if (!ctx || !store) {
return false; }
17150 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
17151 auto x509_store =
static_cast<X509_STORE *
>(store);
17154 if (SSL_CTX_get_cert_store(ssl_ctx) == x509_store) {
return true; }
17157 SSL_CTX_set_cert_store(ssl_ctx, x509_store);
17161inline size_t get_ca_certs(ctx_t ctx, std::vector<cert_t> &certs) {
17163 if (!ctx) {
return 0; }
17164 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
17166 auto store = SSL_CTX_get_cert_store(ssl_ctx);
17167 if (!store) {
return 0; }
17169 auto objs = X509_STORE_get0_objects(store);
17170 if (!objs) {
return 0; }
17172 auto count = sk_X509_OBJECT_num(objs);
17173 for (
decltype(count) i = 0; i < count; i++) {
17174 auto obj = sk_X509_OBJECT_value(objs, i);
17175 if (!obj) {
continue; }
17176 if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
17177 auto x509 = X509_OBJECT_get0_X509(obj);
17181 certs.push_back(
static_cast<cert_t
>(x509));
17185 return certs.size();
17188inline std::vector<std::string> get_ca_names(ctx_t ctx) {
17189 std::vector<std::string> names;
17190 if (!ctx) {
return names; }
17191 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
17193 auto store = SSL_CTX_get_cert_store(ssl_ctx);
17194 if (!store) {
return names; }
17196 auto objs = X509_STORE_get0_objects(store);
17197 if (!objs) {
return names; }
17199 auto count = sk_X509_OBJECT_num(objs);
17200 for (
decltype(count) i = 0; i < count; i++) {
17201 auto obj = sk_X509_OBJECT_value(objs, i);
17202 if (!obj) {
continue; }
17203 if (X509_OBJECT_get_type(obj) == X509_LU_X509) {
17204 auto x509 = X509_OBJECT_get0_X509(obj);
17206 auto subject = X509_get_subject_name(x509);
17209 X509_NAME_oneline(subject, buf,
sizeof(buf));
17210 names.push_back(buf);
17218inline bool update_server_cert(ctx_t ctx,
const char *cert_pem,
17219 const char *key_pem,
const char *password) {
17220 if (!ctx || !cert_pem || !key_pem) {
return false; }
17221 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
17224 auto cert_bio = BIO_new_mem_buf(cert_pem, -1);
17225 if (!cert_bio) {
return false; }
17226 auto cert = PEM_read_bio_X509(cert_bio,
nullptr,
nullptr,
nullptr);
17227 BIO_free(cert_bio);
17228 if (!cert) {
return false; }
17231 auto key_bio = BIO_new_mem_buf(key_pem, -1);
17236 auto key = PEM_read_bio_PrivateKey(key_bio,
nullptr,
nullptr,
17237 password ?
const_cast<char *
>(password)
17246 auto ret = SSL_CTX_use_certificate(ssl_ctx, cert) == 1 &&
17247 SSL_CTX_use_PrivateKey(ssl_ctx, key) == 1;
17250 EVP_PKEY_free(key);
17254inline bool update_server_client_ca(ctx_t ctx,
const char *ca_pem) {
17255 if (!ctx || !ca_pem) {
return false; }
17256 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
17259 auto store = create_ca_store(ca_pem, strlen(ca_pem));
17260 if (!store) {
return false; }
17263 SSL_CTX_set_cert_store(ssl_ctx,
static_cast<X509_STORE *
>(store));
17266 auto ca_list = impl::create_client_ca_list_from_pem(ca_pem);
17269 SSL_CTX_set_client_CA_list(ssl_ctx, ca_list);
17275inline bool set_verify_callback(ctx_t ctx, VerifyCallback callback) {
17276 if (!ctx) {
return false; }
17277 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx);
17279 impl::get_verify_callback() = std::move(callback);
17281 if (impl::get_verify_callback()) {
17282 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER, impl::openssl_verify_callback);
17284 SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_PEER,
nullptr);
17289inline long get_verify_error(const_session_t session) {
17290 if (!session) {
return -1; }
17291 auto ssl =
static_cast<SSL *
>(
const_cast<void *
>(session));
17292 return SSL_get_verify_result(ssl);
17295inline std::string verify_error_string(
long error_code) {
17296 if (error_code == X509_V_OK) {
return ""; }
17297 const char *str = X509_verify_cert_error_string(
static_cast<int>(error_code));
17298 return str ? str :
"unknown error";
17304inline ctx_t create_server_context_from_x509(X509 *cert, EVP_PKEY *key,
17305 X509_STORE *client_ca_store,
17308 auto cert_pem = x509_to_pem(cert);
17309 auto key_pem = evp_pkey_to_pem(key);
17310 if (cert_pem.empty() || key_pem.empty()) {
17311 out_error =
static_cast<int>(ERR_get_error());
17315 auto ctx = create_server_context();
17317 out_error =
static_cast<int>(get_error());
17321 if (!set_server_cert_pem(ctx, cert_pem.c_str(), key_pem.c_str(),
nullptr)) {
17322 out_error =
static_cast<int>(get_error());
17327 if (client_ca_store) {
17329 SSL_CTX_set_cert_store(
static_cast<SSL_CTX *
>(ctx), client_ca_store);
17333 auto ca_list = extract_client_ca_list_from_store(client_ca_store);
17335 SSL_CTX_set_client_CA_list(
static_cast<SSL_CTX *
>(ctx), ca_list);
17338 set_verify_client(ctx,
true);
17344inline void update_server_certs_from_x509(ctx_t ctx, X509 *cert, EVP_PKEY *key,
17345 X509_STORE *client_ca_store) {
17346 auto cert_pem = x509_to_pem(cert);
17347 auto key_pem = evp_pkey_to_pem(key);
17349 if (!cert_pem.empty() && !key_pem.empty()) {
17350 update_server_cert(ctx, cert_pem.c_str(), key_pem.c_str(),
nullptr);
17353 if (client_ca_store) {
17354 auto ca_pem = x509_store_to_pem(client_ca_store);
17355 if (!ca_pem.empty()) { update_server_client_ca(ctx, ca_pem.c_str()); }
17356 X509_STORE_free(client_ca_store);
17360inline ctx_t create_client_context_from_x509(X509 *cert, EVP_PKEY *key,
17361 const char *password,
17362 uint64_t &out_error) {
17364 auto ctx = create_client_context();
17366 out_error = get_error();
17371 auto cert_pem = x509_to_pem(cert);
17372 auto key_pem = evp_pkey_to_pem(key);
17373 if (cert_pem.empty() || key_pem.empty()) {
17374 out_error = ERR_get_error();
17378 if (!set_client_cert_pem(ctx, cert_pem.c_str(), key_pem.c_str(),
17380 out_error = get_error();
17396inline void ClientImpl::set_ca_cert_store(X509_STORE *ca_cert_store) {
17397 if (ca_cert_store) {
17398 ca_cert_pem_ = tls::impl::x509_store_to_pem(ca_cert_store);
17402inline SSLServer::SSLServer(X509 *cert, EVP_PKEY *private_key,
17403 X509_STORE *client_ca_cert_store) {
17404 ctx_ = tls::impl::create_server_context_from_x509(
17405 cert, private_key, client_ca_cert_store, last_ssl_error_);
17408inline SSLServer::SSLServer(
17409 const std::function<
bool(SSL_CTX &ssl_ctx)> &setup_ssl_ctx_callback) {
17411 ctx_ = tls::create_server_context();
17414 auto ssl_ctx =
static_cast<SSL_CTX *
>(ctx_);
17415 if (!setup_ssl_ctx_callback(*ssl_ctx)) {
17416 tls::free_context(ctx_);
17422inline SSL_CTX *SSLServer::ssl_context()
const {
17423 return static_cast<SSL_CTX *
>(ctx_);
17426inline void SSLServer::update_certs(X509 *cert, EVP_PKEY *private_key,
17427 X509_STORE *client_ca_cert_store) {
17428 std::lock_guard<std::mutex> guard(ctx_mutex_);
17429 tls::impl::update_server_certs_from_x509(ctx_, cert, private_key,
17430 client_ca_cert_store);
17433inline SSLClient::SSLClient(
const std::string &host,
int port,
17434 X509 *client_cert, EVP_PKEY *client_key,
17435 const std::string &private_key_password)
17436 : ClientImpl(host, port) {
17437 const char *password =
17438 private_key_password.empty() ?
nullptr : private_key_password.c_str();
17439 ctx_ = tls::impl::create_client_context_from_x509(
17440 client_cert, client_key, password, last_backend_error_);
17443inline long SSLClient::get_verify_result()
const {
return verify_result_; }
17445inline void SSLClient::set_server_certificate_verifier(
17449 std::move(verifier));
17450 session_verifier_ = [v](tls::session_t session) {
17451 return (*v)(
static_cast<SSL *
>(session));
17455inline SSL_CTX *SSLClient::ssl_context()
const {
17456 return static_cast<SSL_CTX *
>(ctx_);
17459inline bool SSLClient::verify_host(X509 *server_cert)
const {
17481 return verify_host_with_subject_alt_name(server_cert) ||
17482 verify_host_with_common_name(server_cert);
17486SSLClient::verify_host_with_subject_alt_name(X509 *server_cert)
const {
17489 auto type = GEN_DNS;
17491 struct in6_addr addr6 = {};
17492 struct in_addr addr = {};
17493 size_t addr_len = 0;
17496 if (inet_pton(AF_INET6, host_.c_str(), &addr6)) {
17498 addr_len =
sizeof(
struct in6_addr);
17499 }
else if (inet_pton(AF_INET, host_.c_str(), &addr)) {
17501 addr_len =
sizeof(
struct in_addr);
17505 auto alt_names =
static_cast<const struct stack_st_GENERAL_NAME *
>(
17506 X509_get_ext_d2i(server_cert, NID_subject_alt_name,
nullptr,
nullptr));
17509 auto dsn_matched =
false;
17510 auto ip_matched =
false;
17512 auto count = sk_GENERAL_NAME_num(alt_names);
17514 for (
decltype(count) i = 0; i < count && !dsn_matched; i++) {
17515 auto val = sk_GENERAL_NAME_value(alt_names, i);
17516 if (!val || val->type != type) {
continue; }
17519 reinterpret_cast<const char *
>(ASN1_STRING_get0_data(val->d.ia5));
17520 if (name ==
nullptr) {
continue; }
17522 auto name_len =
static_cast<size_t>(ASN1_STRING_length(val->d.ia5));
17527 detail::match_hostname(std::string(name, name_len), host_);
17531 if (!memcmp(&addr6, name, addr_len) || !memcmp(&addr, name, addr_len)) {
17538 if (dsn_matched || ip_matched) { ret =
true; }
17541 GENERAL_NAMES_free(
const_cast<STACK_OF(GENERAL_NAME) *
>(
17542 reinterpret_cast<const STACK_OF(GENERAL_NAME) *
>(alt_names)));
17546inline bool SSLClient::verify_host_with_common_name(X509 *server_cert)
const {
17547 const auto subject_name = X509_get_subject_name(server_cert);
17549 if (subject_name !=
nullptr) {
17551 auto name_len = X509_NAME_get_text_by_NID(subject_name, NID_commonName,
17552 name,
sizeof(name));
17554 if (name_len != -1) {
17555 return detail::match_hostname(
17556 std::string(name,
static_cast<size_t>(name_len)), host_);
17573#ifdef CPPHTTPLIB_MBEDTLS_SUPPORT
17579struct MbedTlsSession {
17580 mbedtls_ssl_context ssl;
17582 std::string hostname;
17583 std::string sni_hostname;
17585 MbedTlsSession() { mbedtls_ssl_init(&ssl); }
17587 ~MbedTlsSession() { mbedtls_ssl_free(&ssl); }
17589 MbedTlsSession(
const MbedTlsSession &) =
delete;
17590 MbedTlsSession &operator=(
const MbedTlsSession &) =
delete;
17595inline int &mbedtls_last_error() {
17596 static thread_local int err = 0;
17601inline ErrorCode map_mbedtls_error(
int ret,
int &out_errno) {
17602 if (ret == 0) {
return ErrorCode::Success; }
17603 if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
return ErrorCode::WantRead; }
17604 if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
return ErrorCode::WantWrite; }
17605 if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
17606 return ErrorCode::PeerClosed;
17608 if (ret == MBEDTLS_ERR_NET_CONN_RESET || ret == MBEDTLS_ERR_NET_SEND_FAILED ||
17609 ret == MBEDTLS_ERR_NET_RECV_FAILED) {
17611 return ErrorCode::SyscallError;
17613 if (ret == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) {
17614 return ErrorCode::CertVerifyFailed;
17616 return ErrorCode::Fatal;
17620inline int mbedtls_net_send_cb(
void *ctx,
const unsigned char *buf,
17622 auto sock = *
static_cast<socket_t *
>(ctx);
17625 send(sock,
reinterpret_cast<const char *
>(buf),
static_cast<int>(len), 0);
17626 if (ret == SOCKET_ERROR) {
17627 int err = WSAGetLastError();
17628 if (err == WSAEWOULDBLOCK) {
return MBEDTLS_ERR_SSL_WANT_WRITE; }
17629 return MBEDTLS_ERR_NET_SEND_FAILED;
17632 auto ret = send(sock, buf, len, 0);
17634 if (errno == EAGAIN || errno == EWOULDBLOCK) {
17635 return MBEDTLS_ERR_SSL_WANT_WRITE;
17637 return MBEDTLS_ERR_NET_SEND_FAILED;
17640 return static_cast<int>(ret);
17644inline int mbedtls_net_recv_cb(
void *ctx,
unsigned char *buf,
size_t len) {
17645 auto sock = *
static_cast<socket_t *
>(ctx);
17648 recv(sock,
reinterpret_cast<char *
>(buf),
static_cast<int>(len), 0);
17649 if (ret == SOCKET_ERROR) {
17650 int err = WSAGetLastError();
17651 if (err == WSAEWOULDBLOCK) {
return MBEDTLS_ERR_SSL_WANT_READ; }
17652 return MBEDTLS_ERR_NET_RECV_FAILED;
17655 auto ret = recv(sock, buf, len, 0);
17657 if (errno == EAGAIN || errno == EWOULDBLOCK) {
17658 return MBEDTLS_ERR_SSL_WANT_READ;
17660 return MBEDTLS_ERR_NET_RECV_FAILED;
17663 if (ret == 0) {
return MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY; }
17664 return static_cast<int>(ret);
17668inline MbedTlsContext::MbedTlsContext() {
17669 mbedtls_ssl_config_init(&conf);
17670 mbedtls_entropy_init(&entropy);
17671 mbedtls_ctr_drbg_init(&ctr_drbg);
17672 mbedtls_x509_crt_init(&ca_chain);
17673 mbedtls_x509_crt_init(&own_cert);
17674 mbedtls_pk_init(&own_key);
17677inline MbedTlsContext::~MbedTlsContext() {
17678 mbedtls_pk_free(&own_key);
17679 mbedtls_x509_crt_free(&own_cert);
17680 mbedtls_x509_crt_free(&ca_chain);
17681 mbedtls_ctr_drbg_free(&ctr_drbg);
17682 mbedtls_entropy_free(&entropy);
17683 mbedtls_ssl_config_free(&conf);
17689inline std::string &mbedpending_sni() {
17690 static thread_local std::string sni;
17695inline int mbedtls_sni_callback(
void *p_ctx, mbedtls_ssl_context *ssl,
17696 const unsigned char *name,
size_t name_len) {
17702 if (name && name_len > 0) {
17703 mbedpending_sni().assign(
reinterpret_cast<const char *
>(name), name_len);
17705 mbedpending_sni().clear();
17710inline int mbedtls_verify_callback(
void *data, mbedtls_x509_crt *crt,
17711 int cert_depth, uint32_t *flags);
17714inline int mbedtls_verify_callback(
void *data, mbedtls_x509_crt *crt,
17715 int cert_depth, uint32_t *flags) {
17716 auto &callback = get_verify_callback();
17717 if (!callback) {
return 0; }
17720 auto *session =
static_cast<MbedTlsSession *
>(data);
17723 VerifyContext verify_ctx;
17724 verify_ctx.session =
static_cast<session_t
>(session);
17725 verify_ctx.cert =
static_cast<cert_t
>(crt);
17726 verify_ctx.depth = cert_depth;
17727 verify_ctx.preverify_ok = (*flags == 0);
17728 verify_ctx.error_code =
static_cast<long>(*flags);
17731 static thread_local char error_buf[256];
17733 mbedtls_x509_crt_verify_info(error_buf,
sizeof(error_buf),
"", *flags);
17734 verify_ctx.error_string = error_buf;
17736 verify_ctx.error_string =
nullptr;
17739 bool accepted = callback(verify_ctx);
17745 return MBEDTLS_ERR_X509_CERT_VERIFY_FAILED;
17750inline ctx_t create_client_context() {
17751 auto ctx =
new (std::nothrow) impl::MbedTlsContext();
17752 if (!ctx) {
return nullptr; }
17754 ctx->is_server =
false;
17757 const char *pers =
"httplib_client";
17758 int ret = mbedtls_ctr_drbg_seed(
17759 &ctx->ctr_drbg, mbedtls_entropy_func, &ctx->entropy,
17760 reinterpret_cast<const unsigned char *
>(pers), strlen(pers));
17762 impl::mbedtls_last_error() = ret;
17768 ret = mbedtls_ssl_config_defaults(&ctx->conf, MBEDTLS_SSL_IS_CLIENT,
17769 MBEDTLS_SSL_TRANSPORT_STREAM,
17770 MBEDTLS_SSL_PRESET_DEFAULT);
17772 impl::mbedtls_last_error() = ret;
17778 mbedtls_ssl_conf_rng(&ctx->conf, mbedtls_ctr_drbg_random, &ctx->ctr_drbg);
17781 mbedtls_ssl_conf_authmode(&ctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
17784#ifdef CPPHTTPLIB_MBEDTLS_V3
17785 mbedtls_ssl_conf_min_tls_version(&ctx->conf, MBEDTLS_SSL_VERSION_TLS1_2);
17787 mbedtls_ssl_conf_min_version(&ctx->conf, MBEDTLS_SSL_MAJOR_VERSION_3,
17788 MBEDTLS_SSL_MINOR_VERSION_3);
17791 return static_cast<ctx_t
>(ctx);
17794inline ctx_t create_server_context() {
17795 auto ctx =
new (std::nothrow) impl::MbedTlsContext();
17796 if (!ctx) {
return nullptr; }
17798 ctx->is_server =
true;
17801 const char *pers =
"httplib_server";
17802 int ret = mbedtls_ctr_drbg_seed(
17803 &ctx->ctr_drbg, mbedtls_entropy_func, &ctx->entropy,
17804 reinterpret_cast<const unsigned char *
>(pers), strlen(pers));
17806 impl::mbedtls_last_error() = ret;
17812 ret = mbedtls_ssl_config_defaults(&ctx->conf, MBEDTLS_SSL_IS_SERVER,
17813 MBEDTLS_SSL_TRANSPORT_STREAM,
17814 MBEDTLS_SSL_PRESET_DEFAULT);
17816 impl::mbedtls_last_error() = ret;
17822 mbedtls_ssl_conf_rng(&ctx->conf, mbedtls_ctr_drbg_random, &ctx->ctr_drbg);
17825 mbedtls_ssl_conf_authmode(&ctx->conf, MBEDTLS_SSL_VERIFY_NONE);
17828#ifdef CPPHTTPLIB_MBEDTLS_V3
17829 mbedtls_ssl_conf_min_tls_version(&ctx->conf, MBEDTLS_SSL_VERSION_TLS1_2);
17831 mbedtls_ssl_conf_min_version(&ctx->conf, MBEDTLS_SSL_MAJOR_VERSION_3,
17832 MBEDTLS_SSL_MINOR_VERSION_3);
17836 mbedtls_ssl_conf_sni(&ctx->conf, impl::mbedtls_sni_callback,
nullptr);
17838 return static_cast<ctx_t
>(ctx);
17841inline void free_context(ctx_t ctx) {
17842 if (ctx) {
delete static_cast<impl::MbedTlsContext *
>(ctx); }
17845inline bool set_min_version(ctx_t ctx, Version version) {
17846 if (!ctx) {
return false; }
17847 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
17849#ifdef CPPHTTPLIB_MBEDTLS_V3
17851 mbedtls_ssl_protocol_version min_ver = MBEDTLS_SSL_VERSION_TLS1_2;
17852 if (version >= Version::TLS1_3) {
17853#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
17854 min_ver = MBEDTLS_SSL_VERSION_TLS1_3;
17857 mbedtls_ssl_conf_min_tls_version(&mctx->conf, min_ver);
17860 int major = MBEDTLS_SSL_MAJOR_VERSION_3;
17861 int minor = MBEDTLS_SSL_MINOR_VERSION_3;
17862 if (version >= Version::TLS1_3) {
17863#if defined(MBEDTLS_SSL_PROTO_TLS1_3)
17864 minor = MBEDTLS_SSL_MINOR_VERSION_4;
17866 minor = MBEDTLS_SSL_MINOR_VERSION_3;
17869 mbedtls_ssl_conf_min_version(&mctx->conf, major, minor);
17874inline bool load_ca_pem(ctx_t ctx,
const char *pem,
size_t len) {
17875 if (!ctx || !pem) {
return false; }
17876 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
17880 std::string pem_str(pem, len);
17881 int ret = mbedtls_x509_crt_parse(
17882 &mctx->ca_chain,
reinterpret_cast<const unsigned char *
>(pem_str.c_str()),
17883 pem_str.size() + 1);
17885 impl::mbedtls_last_error() = ret;
17889 mbedtls_ssl_conf_ca_chain(&mctx->conf, &mctx->ca_chain,
nullptr);
17893inline bool load_ca_file(ctx_t ctx,
const char *file_path) {
17894 if (!ctx || !file_path) {
return false; }
17895 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
17897 int ret = mbedtls_x509_crt_parse_file(&mctx->ca_chain, file_path);
17899 impl::mbedtls_last_error() = ret;
17903 mbedtls_ssl_conf_ca_chain(&mctx->conf, &mctx->ca_chain,
nullptr);
17907inline bool load_ca_dir(ctx_t ctx,
const char *dir_path) {
17908 if (!ctx || !dir_path) {
return false; }
17909 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
17911 int ret = mbedtls_x509_crt_parse_path(&mctx->ca_chain, dir_path);
17913 impl::mbedtls_last_error() = ret;
17917 mbedtls_ssl_conf_ca_chain(&mctx->conf, &mctx->ca_chain,
nullptr);
17921inline bool load_system_certs(ctx_t ctx) {
17922 if (!ctx) {
return false; }
17923 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
17924 bool loaded =
false;
17927 loaded = impl::enumerate_windows_system_certs(
17928 [&](
const unsigned char *data,
size_t len) {
17929 return mbedtls_x509_crt_parse_der(&mctx->ca_chain, data, len) == 0;
17931#elif defined(__APPLE__) && defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN)
17932 loaded = impl::enumerate_macos_keychain_certs(
17933 [&](
const unsigned char *data,
size_t len) {
17934 return mbedtls_x509_crt_parse_der(&mctx->ca_chain, data, len) == 0;
17937 for (
auto path = impl::system_ca_paths(); *path; ++path) {
17938 if (mbedtls_x509_crt_parse_file(&mctx->ca_chain, *path) >= 0) {
17945 for (
auto dir = impl::system_ca_dirs(); *dir; ++dir) {
17946 if (mbedtls_x509_crt_parse_path(&mctx->ca_chain, *dir) >= 0) {
17955 mbedtls_ssl_conf_ca_chain(&mctx->conf, &mctx->ca_chain,
nullptr);
17960inline bool set_client_cert_pem(ctx_t ctx,
const char *cert,
const char *key,
17961 const char *password) {
17962 if (!ctx || !cert || !key) {
return false; }
17963 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
17966 std::string cert_str(cert);
17967 int ret = mbedtls_x509_crt_parse(
17969 reinterpret_cast<const unsigned char *
>(cert_str.c_str()),
17970 cert_str.size() + 1);
17972 impl::mbedtls_last_error() = ret;
17977 std::string key_str(key);
17978 const unsigned char *pwd =
17979 password ?
reinterpret_cast<const unsigned char *
>(password) : nullptr;
17980 size_t pwd_len = password ? strlen(password) : 0;
17982#ifdef CPPHTTPLIB_MBEDTLS_V3
17983 ret = mbedtls_pk_parse_key(
17984 &mctx->own_key,
reinterpret_cast<const unsigned char *
>(key_str.c_str()),
17985 key_str.size() + 1, pwd, pwd_len, mbedtls_ctr_drbg_random,
17988 ret = mbedtls_pk_parse_key(
17989 &mctx->own_key,
reinterpret_cast<const unsigned char *
>(key_str.c_str()),
17990 key_str.size() + 1, pwd, pwd_len);
17993 impl::mbedtls_last_error() = ret;
17998#ifdef CPPHTTPLIB_MBEDTLS_V3
17999 ret = mbedtls_pk_check_pair(&mctx->own_cert.pk, &mctx->own_key,
18000 mbedtls_ctr_drbg_random, &mctx->ctr_drbg);
18002 ret = mbedtls_pk_check_pair(&mctx->own_cert.pk, &mctx->own_key);
18005 impl::mbedtls_last_error() = ret;
18009 ret = mbedtls_ssl_conf_own_cert(&mctx->conf, &mctx->own_cert, &mctx->own_key);
18011 impl::mbedtls_last_error() = ret;
18018inline bool set_client_cert_file(ctx_t ctx,
const char *cert_path,
18019 const char *key_path,
const char *password) {
18020 if (!ctx || !cert_path || !key_path) {
return false; }
18021 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18024 int ret = mbedtls_x509_crt_parse_file(&mctx->own_cert, cert_path);
18026 impl::mbedtls_last_error() = ret;
18031#ifdef CPPHTTPLIB_MBEDTLS_V3
18032 ret = mbedtls_pk_parse_keyfile(&mctx->own_key, key_path, password,
18033 mbedtls_ctr_drbg_random, &mctx->ctr_drbg);
18035 ret = mbedtls_pk_parse_keyfile(&mctx->own_key, key_path, password);
18038 impl::mbedtls_last_error() = ret;
18043#ifdef CPPHTTPLIB_MBEDTLS_V3
18044 ret = mbedtls_pk_check_pair(&mctx->own_cert.pk, &mctx->own_key,
18045 mbedtls_ctr_drbg_random, &mctx->ctr_drbg);
18047 ret = mbedtls_pk_check_pair(&mctx->own_cert.pk, &mctx->own_key);
18050 impl::mbedtls_last_error() = ret;
18054 ret = mbedtls_ssl_conf_own_cert(&mctx->conf, &mctx->own_cert, &mctx->own_key);
18056 impl::mbedtls_last_error() = ret;
18063inline void set_verify_client(ctx_t ctx,
bool require) {
18064 if (!ctx) {
return; }
18065 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18066 mctx->verify_client = require;
18068 mbedtls_ssl_conf_authmode(&mctx->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
18072 mbedtls_ssl_conf_authmode(&mctx->conf, mctx->has_verify_callback
18073 ? MBEDTLS_SSL_VERIFY_OPTIONAL
18074 : MBEDTLS_SSL_VERIFY_NONE);
18078inline session_t create_session(ctx_t ctx,
socket_t sock) {
18080 auto mctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18082 auto session =
new (std::nothrow) impl::MbedTlsSession();
18083 if (!session) {
return nullptr; }
18085 session->sock = sock;
18087 int ret = mbedtls_ssl_setup(&session->ssl, &mctx->conf);
18089 impl::mbedtls_last_error() = ret;
18095 mbedtls_ssl_set_bio(&session->ssl, &session->sock, impl::mbedtls_net_send_cb,
18096 impl::mbedtls_net_recv_cb,
nullptr);
18100 if (mctx->has_verify_callback) {
18101 mbedtls_ssl_set_verify(&session->ssl, impl::mbedtls_verify_callback,
18105 return static_cast<session_t
>(session);
18108inline void free_session(session_t session) {
18109 if (session) {
delete static_cast<impl::MbedTlsSession *
>(session); }
18112inline bool set_sni(session_t session,
const char *hostname) {
18113 if (!session || !hostname) {
return false; }
18114 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18116 int ret = mbedtls_ssl_set_hostname(&msession->ssl, hostname);
18118 impl::mbedtls_last_error() = ret;
18122 msession->hostname = hostname;
18126inline bool set_hostname(session_t session,
const char *hostname) {
18128 return set_sni(session, hostname);
18131inline TlsError connect(session_t session) {
18134 err.code = ErrorCode::Fatal;
18138 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18139 int ret = mbedtls_ssl_handshake(&msession->ssl);
18142 err.code = ErrorCode::Success;
18144 err.code = impl::map_mbedtls_error(ret, err.sys_errno);
18145 err.backend_code =
static_cast<uint64_t
>(-ret);
18146 impl::mbedtls_last_error() = ret;
18152inline TlsError accept(session_t session) {
18154 auto result = connect(session);
18157 if (result.code == ErrorCode::Success && session) {
18158 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18159 msession->sni_hostname = std::move(impl::mbedpending_sni());
18160 impl::mbedpending_sni().clear();
18166inline bool connect_nonblocking(session_t session,
socket_t sock,
18167 time_t timeout_sec, time_t timeout_usec,
18170 if (err) { err->code = ErrorCode::Fatal; }
18174 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18177 detail::set_nonblocking(sock,
true);
18179 detail::scope_exit([&]() { detail::set_nonblocking(sock,
false); });
18182 while ((ret = mbedtls_ssl_handshake(&msession->ssl)) != 0) {
18183 if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
18184 if (detail::select_read(sock, timeout_sec, timeout_usec) > 0) {
18187 }
else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
18188 if (detail::select_write(sock, timeout_sec, timeout_usec) > 0) {
18195 err->code = impl::map_mbedtls_error(ret, err->sys_errno);
18196 err->backend_code =
static_cast<uint64_t
>(-ret);
18198 impl::mbedtls_last_error() = ret;
18202 if (err) { err->code = ErrorCode::Success; }
18206inline bool accept_nonblocking(session_t session,
socket_t sock,
18207 time_t timeout_sec, time_t timeout_usec,
18211 connect_nonblocking(session, sock, timeout_sec, timeout_usec, err);
18214 if (result && session) {
18215 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18216 msession->sni_hostname = std::move(impl::mbedpending_sni());
18217 impl::mbedpending_sni().clear();
18223inline ssize_t read(session_t session,
void *buf,
size_t len, TlsError &err) {
18224 if (!session || !buf) {
18225 err.code = ErrorCode::Fatal;
18229 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18231 mbedtls_ssl_read(&msession->ssl,
static_cast<unsigned char *
>(buf), len);
18234 err.code = ErrorCode::Success;
18235 return static_cast<ssize_t
>(ret);
18239 err.code = ErrorCode::PeerClosed;
18243 err.code = impl::map_mbedtls_error(ret, err.sys_errno);
18244 err.backend_code =
static_cast<uint64_t
>(-ret);
18245 impl::mbedtls_last_error() = ret;
18249inline ssize_t write(session_t session,
const void *buf,
size_t len,
18251 if (!session || !buf) {
18252 err.code = ErrorCode::Fatal;
18256 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18257 int ret = mbedtls_ssl_write(&msession->ssl,
18258 static_cast<const unsigned char *
>(buf), len);
18261 err.code = ErrorCode::Success;
18262 return static_cast<ssize_t
>(ret);
18266 err.code = ErrorCode::PeerClosed;
18270 err.code = impl::map_mbedtls_error(ret, err.sys_errno);
18271 err.backend_code =
static_cast<uint64_t
>(-ret);
18272 impl::mbedtls_last_error() = ret;
18276inline int pending(const_session_t session) {
18277 if (!session) {
return 0; }
18279 static_cast<impl::MbedTlsSession *
>(
const_cast<void *
>(session));
18280 return static_cast<int>(mbedtls_ssl_get_bytes_avail(&msession->ssl));
18283inline void shutdown(session_t session,
bool graceful) {
18284 if (!session) {
return; }
18285 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18291 while ((ret = mbedtls_ssl_close_notify(&msession->ssl)) != 0 &&
18293 if (ret != MBEDTLS_ERR_SSL_WANT_READ &&
18294 ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
18302inline bool is_peer_closed(session_t session,
socket_t sock) {
18304 auto msession =
static_cast<impl::MbedTlsSession *
>(session);
18308 if (mbedtls_ssl_get_bytes_avail(&msession->ssl) > 0) {
return false; }
18311 detail::set_nonblocking(sock,
true);
18313 detail::scope_exit([&]() { detail::set_nonblocking(sock,
false); });
18320 int ret = mbedtls_ssl_read(&msession->ssl, &buf, 1);
18323 if (ret > 0 || ret == MBEDTLS_ERR_SSL_WANT_READ) {
return false; }
18326 return ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY ||
18327 ret == MBEDTLS_ERR_NET_CONN_RESET || ret == 0;
18330inline cert_t get_peer_cert(const_session_t session) {
18331 if (!session) {
return nullptr; }
18333 static_cast<impl::MbedTlsSession *
>(
const_cast<void *
>(session));
18338 const mbedtls_x509_crt *cert = mbedtls_ssl_get_peer_cert(&msession->ssl);
18339 return const_cast<mbedtls_x509_crt *
>(cert);
18342inline void free_cert(cert_t cert) {
18349inline bool verify_hostname(cert_t cert,
const char *hostname) {
18350 if (!cert || !hostname) {
return false; }
18351 auto mcert =
static_cast<const mbedtls_x509_crt *
>(cert);
18352 std::string host_str(hostname);
18355 bool is_ip = impl::is_ipv4_address(host_str);
18356 unsigned char ip_bytes[4];
18357 if (is_ip) { impl::parse_ipv4(host_str, ip_bytes); }
18363 const mbedtls_x509_sequence *san = &mcert->subject_alt_names;
18364 while (san !=
nullptr && san->buf.p !=
nullptr && san->buf.len > 0) {
18365 const unsigned char *p = san->buf.p;
18366 size_t len = san->buf.len;
18370 if (len == 4 && memcmp(p, ip_bytes, 4) == 0) {
return true; }
18374 bool is_dns = len > 0;
18375 for (
size_t i = 0; i < len && is_dns; i++) {
18376 if (p[i] < 32 || p[i] > 126) { is_dns =
false; }
18379 std::string san_name(
reinterpret_cast<const char *
>(p), len);
18380 if (detail::match_hostname(san_name, host_str)) {
return true; }
18388 int ret = mbedtls_x509_dn_gets(cn,
sizeof(cn), &mcert->subject);
18390 std::string cn_str(cn);
18393 size_t cn_pos = cn_str.find(
"CN=");
18394 if (cn_pos != std::string::npos) {
18395 size_t start = cn_pos + 3;
18396 size_t end = cn_str.find(
',', start);
18397 std::string cn_value =
18398 cn_str.substr(start, end == std::string::npos ? end : end - start);
18400 if (detail::match_hostname(cn_value, host_str)) {
return true; }
18407inline uint64_t hostname_mismatch_code() {
18408 return static_cast<uint64_t
>(MBEDTLS_X509_BADCERT_CN_MISMATCH);
18411inline long get_verify_result(const_session_t session) {
18412 if (!session) {
return -1; }
18414 static_cast<impl::MbedTlsSession *
>(
const_cast<void *
>(session));
18415 uint32_t flags = mbedtls_ssl_get_verify_result(&msession->ssl);
18417 return flags == 0 ? 0 :
static_cast<long>(flags);
18420inline std::string get_cert_subject_cn(cert_t cert) {
18421 if (!cert)
return "";
18422 auto x509 =
static_cast<mbedtls_x509_crt *
>(cert);
18425 const mbedtls_x509_name *name = &x509->subject;
18426 while (name !=
nullptr) {
18427 if (MBEDTLS_OID_CMP(MBEDTLS_OID_AT_CN, &name->oid) == 0) {
18428 return std::string(
reinterpret_cast<const char *
>(name->val.p),
18436inline std::string get_cert_issuer_name(cert_t cert) {
18437 if (!cert)
return "";
18438 auto x509 =
static_cast<mbedtls_x509_crt *
>(cert);
18442 int ret = mbedtls_x509_dn_gets(buf,
sizeof(buf), &x509->issuer);
18443 if (ret < 0)
return "";
18444 return std::string(buf);
18447inline bool get_cert_sans(cert_t cert, std::vector<SanEntry> &sans) {
18449 if (!cert)
return false;
18450 auto x509 =
static_cast<mbedtls_x509_crt *
>(cert);
18453 const mbedtls_x509_sequence *cur = &x509->subject_alt_names;
18454 while (cur !=
nullptr) {
18455 if (cur->buf.len > 0) {
18458 const unsigned char *p = cur->buf.p;
18459 size_t len = cur->buf.len;
18462 unsigned char tag = *p;
18467 if (len > 0 && *p < 0x80) {
18468 size_t value_len = *p;
18472 if (value_len <= len) {
18475 switch (tag & 0x1F) {
18477 entry.type = SanType::DNS;
18479 std::string(
reinterpret_cast<const char *
>(p), value_len);
18482 entry.type = SanType::IP;
18483 if (value_len == 4) {
18486 snprintf(buf,
sizeof(buf),
"%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
18488 }
else if (value_len == 16) {
18491 snprintf(buf,
sizeof(buf),
18492 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
18493 "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
18494 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
18495 p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
18500 entry.type = SanType::EMAIL;
18502 std::string(
reinterpret_cast<const char *
>(p), value_len);
18505 entry.type = SanType::URI;
18507 std::string(
reinterpret_cast<const char *
>(p), value_len);
18509 default: entry.type = SanType::OTHER;
break;
18512 if (!entry.value.empty()) { sans.push_back(std::move(entry)); }
18521inline bool get_cert_validity(cert_t cert, time_t ¬_before,
18522 time_t ¬_after) {
18523 if (!cert)
return false;
18524 auto x509 =
static_cast<mbedtls_x509_crt *
>(cert);
18527 auto to_time_t = [](
const mbedtls_x509_time &t) -> time_t {
18528 struct tm tm_time = {};
18529 tm_time.tm_year = t.year - 1900;
18530 tm_time.tm_mon = t.mon - 1;
18531 tm_time.tm_mday = t.day;
18532 tm_time.tm_hour = t.hour;
18533 tm_time.tm_min = t.min;
18534 tm_time.tm_sec = t.sec;
18536 return _mkgmtime(&tm_time);
18538 return timegm(&tm_time);
18542 not_before = to_time_t(x509->valid_from);
18543 not_after = to_time_t(x509->valid_to);
18547inline std::string get_cert_serial(cert_t cert) {
18548 if (!cert)
return "";
18549 auto x509 =
static_cast<mbedtls_x509_crt *
>(cert);
18552 std::string result;
18553 result.reserve(x509->serial.len * 2);
18554 for (
size_t i = 0; i < x509->serial.len; i++) {
18556 snprintf(hex,
sizeof(hex),
"%02X", x509->serial.p[i]);
18562inline bool get_cert_der(cert_t cert, std::vector<unsigned char> &der) {
18563 if (!cert)
return false;
18564 auto crt =
static_cast<mbedtls_x509_crt *
>(cert);
18565 if (!crt->raw.p || crt->raw.len == 0)
return false;
18566 der.assign(crt->raw.p, crt->raw.p + crt->raw.len);
18570inline const char *get_sni(const_session_t session) {
18571 if (!session)
return nullptr;
18572 auto msession =
static_cast<const impl::MbedTlsSession *
>(session);
18575 if (!msession->sni_hostname.empty()) {
18576 return msession->sni_hostname.c_str();
18580 if (!msession->hostname.empty()) {
return msession->hostname.c_str(); }
18585inline uint64_t peek_error() {
18587 return static_cast<uint64_t
>(-impl::mbedtls_last_error());
18590inline uint64_t get_error() {
18592 uint64_t err =
static_cast<uint64_t
>(-impl::mbedtls_last_error());
18593 impl::mbedtls_last_error() = 0;
18597inline std::string error_string(uint64_t code) {
18599 mbedtls_strerror(-
static_cast<int>(code), buf,
sizeof(buf));
18600 return std::string(buf);
18603inline ca_store_t create_ca_store(
const char *pem,
size_t len) {
18604 auto *ca_chain =
new (std::nothrow) mbedtls_x509_crt;
18605 if (!ca_chain) {
return nullptr; }
18607 mbedtls_x509_crt_init(ca_chain);
18610 int ret = mbedtls_x509_crt_parse(ca_chain,
18611 reinterpret_cast<const unsigned char *
>(pem),
18615 ret = mbedtls_x509_crt_parse(
18616 ca_chain,
reinterpret_cast<const unsigned char *
>(pem), len);
18618 mbedtls_x509_crt_free(ca_chain);
18624 return static_cast<ca_store_t
>(ca_chain);
18627inline void free_ca_store(ca_store_t store) {
18629 auto *ca_chain =
static_cast<mbedtls_x509_crt *
>(store);
18630 mbedtls_x509_crt_free(ca_chain);
18635inline bool set_ca_store(ctx_t ctx, ca_store_t store) {
18636 if (!ctx || !store) {
return false; }
18637 auto *mbed_ctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18638 auto *ca_chain =
static_cast<mbedtls_x509_crt *
>(store);
18641 mbedtls_x509_crt_free(&mbed_ctx->ca_chain);
18642 mbedtls_x509_crt_init(&mbed_ctx->ca_chain);
18646 mbedtls_x509_crt *src = ca_chain;
18647 while (src !=
nullptr) {
18648 int ret = mbedtls_x509_crt_parse_der(&mbed_ctx->ca_chain, src->raw.p,
18650 if (ret != 0) {
return false; }
18655 mbedtls_ssl_conf_ca_chain(&mbed_ctx->conf, &mbed_ctx->ca_chain,
nullptr);
18659inline size_t get_ca_certs(ctx_t ctx, std::vector<cert_t> &certs) {
18661 if (!ctx) {
return 0; }
18662 auto *mbed_ctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18665 mbedtls_x509_crt *cert = &mbed_ctx->ca_chain;
18666 while (cert !=
nullptr && cert->raw.len > 0) {
18668 auto *copy =
new mbedtls_x509_crt;
18669 mbedtls_x509_crt_init(copy);
18670 int ret = mbedtls_x509_crt_parse_der(copy, cert->raw.p, cert->raw.len);
18672 certs.push_back(
static_cast<cert_t
>(copy));
18674 mbedtls_x509_crt_free(copy);
18679 return certs.size();
18682inline std::vector<std::string> get_ca_names(ctx_t ctx) {
18683 std::vector<std::string> names;
18684 if (!ctx) {
return names; }
18685 auto *mbed_ctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18688 mbedtls_x509_crt *cert = &mbed_ctx->ca_chain;
18689 while (cert !=
nullptr && cert->raw.len > 0) {
18691 int ret = mbedtls_x509_dn_gets(buf,
sizeof(buf), &cert->subject);
18692 if (ret > 0) { names.push_back(buf); }
18698inline bool update_server_cert(ctx_t ctx,
const char *cert_pem,
18699 const char *key_pem,
const char *password) {
18700 if (!ctx || !cert_pem || !key_pem) {
return false; }
18701 auto *mbed_ctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18704 mbedtls_x509_crt_free(&mbed_ctx->own_cert);
18705 mbedtls_pk_free(&mbed_ctx->own_key);
18706 mbedtls_x509_crt_init(&mbed_ctx->own_cert);
18707 mbedtls_pk_init(&mbed_ctx->own_key);
18710 int ret = mbedtls_x509_crt_parse(
18711 &mbed_ctx->own_cert,
reinterpret_cast<const unsigned char *
>(cert_pem),
18712 strlen(cert_pem) + 1);
18714 impl::mbedtls_last_error() = ret;
18719#ifdef CPPHTTPLIB_MBEDTLS_V3
18720 ret = mbedtls_pk_parse_key(
18721 &mbed_ctx->own_key,
reinterpret_cast<const unsigned char *
>(key_pem),
18722 strlen(key_pem) + 1,
18723 password ?
reinterpret_cast<const unsigned char *
>(password) :
nullptr,
18724 password ? strlen(password) : 0, mbedtls_ctr_drbg_random,
18725 &mbed_ctx->ctr_drbg);
18727 ret = mbedtls_pk_parse_key(
18728 &mbed_ctx->own_key,
reinterpret_cast<const unsigned char *
>(key_pem),
18729 strlen(key_pem) + 1,
18730 password ?
reinterpret_cast<const unsigned char *
>(password) :
nullptr,
18731 password ? strlen(password) : 0);
18734 impl::mbedtls_last_error() = ret;
18739 ret = mbedtls_ssl_conf_own_cert(&mbed_ctx->conf, &mbed_ctx->own_cert,
18740 &mbed_ctx->own_key);
18742 impl::mbedtls_last_error() = ret;
18749inline bool update_server_client_ca(ctx_t ctx,
const char *ca_pem) {
18750 if (!ctx || !ca_pem) {
return false; }
18751 auto *mbed_ctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18754 mbedtls_x509_crt_free(&mbed_ctx->ca_chain);
18755 mbedtls_x509_crt_init(&mbed_ctx->ca_chain);
18758 int ret = mbedtls_x509_crt_parse(
18759 &mbed_ctx->ca_chain,
reinterpret_cast<const unsigned char *
>(ca_pem),
18760 strlen(ca_pem) + 1);
18762 impl::mbedtls_last_error() = ret;
18767 mbedtls_ssl_conf_ca_chain(&mbed_ctx->conf, &mbed_ctx->ca_chain,
nullptr);
18771inline bool set_verify_callback(ctx_t ctx, VerifyCallback callback) {
18772 if (!ctx) {
return false; }
18773 auto *mbed_ctx =
static_cast<impl::MbedTlsContext *
>(ctx);
18775 impl::get_verify_callback() = std::move(callback);
18776 mbed_ctx->has_verify_callback =
18777 static_cast<bool>(impl::get_verify_callback());
18779 if (mbed_ctx->has_verify_callback) {
18782 mbedtls_ssl_conf_authmode(&mbed_ctx->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
18783 mbedtls_ssl_conf_verify(&mbed_ctx->conf, impl::mbedtls_verify_callback,
18786 mbedtls_ssl_conf_verify(&mbed_ctx->conf,
nullptr,
nullptr);
18791inline long get_verify_error(const_session_t session) {
18792 if (!session) {
return -1; }
18794 static_cast<impl::MbedTlsSession *
>(
const_cast<void *
>(session));
18795 return static_cast<long>(mbedtls_ssl_get_verify_result(&msession->ssl));
18798inline std::string verify_error_string(
long error_code) {
18799 if (error_code == 0) {
return ""; }
18801 mbedtls_x509_crt_verify_info(buf,
sizeof(buf),
"",
18802 static_cast<uint32_t
>(error_code));
18804 std::string result(buf);
18805 while (!result.empty() && (result.back() ==
'\n' || result.back() ==
' ')) {
18823#ifdef CPPHTTPLIB_WOLFSSL_SUPPORT
18829struct WolfSSLSession {
18830 WOLFSSL *ssl =
nullptr;
18832 std::string hostname;
18833 std::string sni_hostname;
18835 WolfSSLSession() =
default;
18837 ~WolfSSLSession() {
18838 if (ssl) { wolfSSL_free(ssl); }
18841 WolfSSLSession(
const WolfSSLSession &) =
delete;
18842 WolfSSLSession &operator=(
const WolfSSLSession &) =
delete;
18846inline uint64_t &wolfssl_last_error() {
18847 static thread_local uint64_t err = 0;
18854inline ErrorCode map_wolfssl_error(WOLFSSL *ssl,
int ssl_error,
18856 switch (ssl_error) {
18857 case SSL_ERROR_NONE:
return ErrorCode::Success;
18858 case SSL_ERROR_WANT_READ:
return ErrorCode::WantRead;
18859 case SSL_ERROR_WANT_WRITE:
return ErrorCode::WantWrite;
18860 case SSL_ERROR_ZERO_RETURN:
return ErrorCode::PeerClosed;
18861 case SSL_ERROR_SYSCALL: out_errno = errno;
return ErrorCode::SyscallError;
18866 int low_err = ssl_error;
18867 if (low_err == DOMAIN_NAME_MISMATCH) {
18868 return ErrorCode::HostnameMismatch;
18872 long vr = wolfSSL_get_verify_result(ssl);
18873 if (vr != 0) {
return ErrorCode::CertVerifyFailed; }
18875 return ErrorCode::Fatal;
18880inline WolfSSLContext::WolfSSLContext() { wolfSSL_Init(); }
18882inline WolfSSLContext::~WolfSSLContext() {
18883 if (ctx) { wolfSSL_CTX_free(ctx); }
18887inline std::string &wolfssl_pending_sni() {
18888 static thread_local std::string sni;
18893inline int wolfssl_sni_callback(WOLFSSL *ssl,
int *ret,
void *exArg) {
18897 void *name_data =
nullptr;
18898 unsigned short name_len =
18899 wolfSSL_SNI_GetRequest(ssl, WOLFSSL_SNI_HOST_NAME, &name_data);
18901 if (name_data && name_len > 0) {
18902 wolfssl_pending_sni().assign(
static_cast<const char *
>(name_data),
18905 wolfssl_pending_sni().clear();
18911inline int wolfssl_verify_callback(
int preverify_ok,
18912 WOLFSSL_X509_STORE_CTX *x509_ctx) {
18913 auto &callback = get_verify_callback();
18914 if (!callback) {
return preverify_ok; }
18916 WOLFSSL_X509 *cert = wolfSSL_X509_STORE_CTX_get_current_cert(x509_ctx);
18917 int depth = wolfSSL_X509_STORE_CTX_get_error_depth(x509_ctx);
18918 int err = wolfSSL_X509_STORE_CTX_get_error(x509_ctx);
18921 WOLFSSL *ssl =
static_cast<WOLFSSL *
>(wolfSSL_X509_STORE_CTX_get_ex_data(
18922 x509_ctx, wolfSSL_get_ex_data_X509_STORE_CTX_idx()));
18924 VerifyContext verify_ctx;
18925 verify_ctx.session =
static_cast<session_t
>(ssl);
18926 verify_ctx.cert =
static_cast<cert_t
>(cert);
18927 verify_ctx.depth = depth;
18928 verify_ctx.preverify_ok = (preverify_ok != 0);
18929 verify_ctx.error_code =
static_cast<long>(err);
18932 verify_ctx.error_string = wolfSSL_X509_verify_cert_error_string(err);
18934 verify_ctx.error_string =
nullptr;
18937 bool accepted = callback(verify_ctx);
18938 return accepted ? 1 : 0;
18941inline void set_wolfssl_password_cb(WOLFSSL_CTX *ctx,
const char *password) {
18942 wolfSSL_CTX_set_default_passwd_cb_userdata(ctx,
const_cast<char *
>(password));
18943 wolfSSL_CTX_set_default_passwd_cb(
18944 ctx, [](
char *buf,
int size,
int ,
void *userdata) ->
int {
18945 auto *pwd =
static_cast<const char *
>(userdata);
18946 if (!pwd)
return 0;
18947 auto len =
static_cast<int>(strlen(pwd));
18948 if (len > size) len = size;
18949 memcpy(buf, pwd,
static_cast<size_t>(len));
18956inline ctx_t create_client_context() {
18957 auto ctx =
new (std::nothrow) impl::WolfSSLContext();
18958 if (!ctx) {
return nullptr; }
18960 ctx->is_server =
false;
18962 WOLFSSL_METHOD *method = wolfTLSv1_2_client_method();
18968 ctx->ctx = wolfSSL_CTX_new(method);
18975 wolfSSL_CTX_set_verify(ctx->ctx, SSL_VERIFY_PEER,
nullptr);
18977 return static_cast<ctx_t
>(ctx);
18980inline ctx_t create_server_context() {
18981 auto ctx =
new (std::nothrow) impl::WolfSSLContext();
18982 if (!ctx) {
return nullptr; }
18984 ctx->is_server =
true;
18986 WOLFSSL_METHOD *method = wolfTLSv1_2_server_method();
18992 ctx->ctx = wolfSSL_CTX_new(method);
18999 wolfSSL_CTX_set_verify(ctx->ctx, SSL_VERIFY_NONE,
nullptr);
19002 wolfSSL_CTX_SNI_SetOptions(ctx->ctx, WOLFSSL_SNI_HOST_NAME,
19003 WOLFSSL_SNI_CONTINUE_ON_MISMATCH);
19004 wolfSSL_CTX_set_servername_callback(ctx->ctx, impl::wolfssl_sni_callback);
19006 return static_cast<ctx_t
>(ctx);
19009inline void free_context(ctx_t ctx) {
19010 if (ctx) {
delete static_cast<impl::WolfSSLContext *
>(ctx); }
19013inline bool set_min_version(ctx_t ctx, Version version) {
19014 if (!ctx) {
return false; }
19015 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19017 int min_ver = WOLFSSL_TLSV1_2;
19018 if (version >= Version::TLS1_3) { min_ver = WOLFSSL_TLSV1_3; }
19020 return wolfSSL_CTX_SetMinVersion(wctx->ctx, min_ver) == WOLFSSL_SUCCESS;
19023inline bool load_ca_pem(ctx_t ctx,
const char *pem,
size_t len) {
19024 if (!ctx || !pem) {
return false; }
19025 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19027 int ret = wolfSSL_CTX_load_verify_buffer(
19028 wctx->ctx,
reinterpret_cast<const unsigned char *
>(pem),
19029 static_cast<long>(len), SSL_FILETYPE_PEM);
19030 if (ret != SSL_SUCCESS) {
19031 impl::wolfssl_last_error() =
19032 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19035 wctx->ca_pem_data_.append(pem, len);
19039inline bool load_ca_file(ctx_t ctx,
const char *file_path) {
19040 if (!ctx || !file_path) {
return false; }
19041 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19043 int ret = wolfSSL_CTX_load_verify_locations(wctx->ctx, file_path,
nullptr);
19044 if (ret != SSL_SUCCESS) {
19045 impl::wolfssl_last_error() =
19046 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19052inline bool load_ca_dir(ctx_t ctx,
const char *dir_path) {
19053 if (!ctx || !dir_path) {
return false; }
19054 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19056 int ret = wolfSSL_CTX_load_verify_locations(wctx->ctx,
nullptr, dir_path);
19065inline bool load_system_certs(ctx_t ctx) {
19066 if (!ctx) {
return false; }
19067 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19068 bool loaded =
false;
19071 loaded = impl::enumerate_windows_system_certs(
19072 [&](
const unsigned char *data,
size_t len) {
19073 return wolfSSL_CTX_load_verify_buffer(wctx->ctx, data,
19074 static_cast<long>(len),
19075 SSL_FILETYPE_ASN1) == SSL_SUCCESS;
19077#elif defined(__APPLE__) && defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN)
19078 loaded = impl::enumerate_macos_keychain_certs(
19079 [&](
const unsigned char *data,
size_t len) {
19080 return wolfSSL_CTX_load_verify_buffer(wctx->ctx, data,
19081 static_cast<long>(len),
19082 SSL_FILETYPE_ASN1) == SSL_SUCCESS;
19085 for (
auto path = impl::system_ca_paths(); *path; ++path) {
19086 if (wolfSSL_CTX_load_verify_locations(wctx->ctx, *path,
nullptr) ==
19094 for (
auto dir = impl::system_ca_dirs(); *dir; ++dir) {
19095 if (wolfSSL_CTX_load_verify_locations(wctx->ctx,
nullptr, *dir) ==
19107inline bool set_client_cert_pem(ctx_t ctx,
const char *cert,
const char *key,
19108 const char *password) {
19109 if (!ctx || !cert || !key) {
return false; }
19110 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19113 int ret = wolfSSL_CTX_use_certificate_buffer(
19114 wctx->ctx,
reinterpret_cast<const unsigned char *
>(cert),
19115 static_cast<long>(strlen(cert)), SSL_FILETYPE_PEM);
19116 if (ret != SSL_SUCCESS) {
19117 impl::wolfssl_last_error() =
19118 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19123 if (password) { impl::set_wolfssl_password_cb(wctx->ctx, password); }
19126 ret = wolfSSL_CTX_use_PrivateKey_buffer(
19127 wctx->ctx,
reinterpret_cast<const unsigned char *
>(key),
19128 static_cast<long>(strlen(key)), SSL_FILETYPE_PEM);
19129 if (ret != SSL_SUCCESS) {
19130 impl::wolfssl_last_error() =
19131 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19136 return wolfSSL_CTX_check_private_key(wctx->ctx) == SSL_SUCCESS;
19139inline bool set_client_cert_file(ctx_t ctx,
const char *cert_path,
19140 const char *key_path,
const char *password) {
19141 if (!ctx || !cert_path || !key_path) {
return false; }
19142 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19146 wolfSSL_CTX_use_certificate_file(wctx->ctx, cert_path, SSL_FILETYPE_PEM);
19147 if (ret != SSL_SUCCESS) {
19148 impl::wolfssl_last_error() =
19149 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19154 if (password) { impl::set_wolfssl_password_cb(wctx->ctx, password); }
19157 ret = wolfSSL_CTX_use_PrivateKey_file(wctx->ctx, key_path, SSL_FILETYPE_PEM);
19158 if (ret != SSL_SUCCESS) {
19159 impl::wolfssl_last_error() =
19160 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19165 return wolfSSL_CTX_check_private_key(wctx->ctx) == SSL_SUCCESS;
19168inline void set_verify_client(ctx_t ctx,
bool require) {
19169 if (!ctx) {
return; }
19170 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19171 wctx->verify_client = require;
19173 wolfSSL_CTX_set_verify(
19174 wctx->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
19175 wctx->has_verify_callback ? impl::wolfssl_verify_callback :
nullptr);
19177 if (wctx->has_verify_callback) {
19178 wolfSSL_CTX_set_verify(wctx->ctx, SSL_VERIFY_PEER,
19179 impl::wolfssl_verify_callback);
19181 wolfSSL_CTX_set_verify(wctx->ctx, SSL_VERIFY_NONE,
nullptr);
19186inline session_t create_session(ctx_t ctx,
socket_t sock) {
19188 auto wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19190 auto session =
new (std::nothrow) impl::WolfSSLSession();
19191 if (!session) {
return nullptr; }
19193 session->sock = sock;
19194 session->ssl = wolfSSL_new(wctx->ctx);
19195 if (!session->ssl) {
19196 impl::wolfssl_last_error() =
19197 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19202 wolfSSL_set_fd(session->ssl,
static_cast<int>(sock));
19204 return static_cast<session_t
>(session);
19207inline void free_session(session_t session) {
19208 if (session) {
delete static_cast<impl::WolfSSLSession *
>(session); }
19211inline bool set_sni(session_t session,
const char *hostname) {
19212 if (!session || !hostname) {
return false; }
19213 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19215 int ret = wolfSSL_UseSNI(wsession->ssl, WOLFSSL_SNI_HOST_NAME, hostname,
19216 static_cast<word16
>(strlen(hostname)));
19217 if (ret != WOLFSSL_SUCCESS) {
19218 impl::wolfssl_last_error() =
19219 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19224 wolfSSL_check_domain_name(wsession->ssl, hostname);
19226 wsession->hostname = hostname;
19230inline bool set_hostname(session_t session,
const char *hostname) {
19232 return set_sni(session, hostname);
19235inline TlsError connect(session_t session) {
19238 err.code = ErrorCode::Fatal;
19242 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19243 int ret = wolfSSL_connect(wsession->ssl);
19245 if (ret == SSL_SUCCESS) {
19246 err.code = ErrorCode::Success;
19248 int ssl_error = wolfSSL_get_error(wsession->ssl, ret);
19249 err.code = impl::map_wolfssl_error(wsession->ssl, ssl_error, err.sys_errno);
19250 err.backend_code =
static_cast<uint64_t
>(ssl_error);
19251 impl::wolfssl_last_error() = err.backend_code;
19257inline TlsError accept(session_t session) {
19260 err.code = ErrorCode::Fatal;
19264 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19265 int ret = wolfSSL_accept(wsession->ssl);
19267 if (ret == SSL_SUCCESS) {
19268 err.code = ErrorCode::Success;
19270 wsession->sni_hostname = std::move(impl::wolfssl_pending_sni());
19271 impl::wolfssl_pending_sni().clear();
19273 int ssl_error = wolfSSL_get_error(wsession->ssl, ret);
19274 err.code = impl::map_wolfssl_error(wsession->ssl, ssl_error, err.sys_errno);
19275 err.backend_code =
static_cast<uint64_t
>(ssl_error);
19276 impl::wolfssl_last_error() = err.backend_code;
19282inline bool connect_nonblocking(session_t session,
socket_t sock,
19283 time_t timeout_sec, time_t timeout_usec,
19286 if (err) { err->code = ErrorCode::Fatal; }
19290 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19293 detail::set_nonblocking(sock,
true);
19295 detail::scope_exit([&]() { detail::set_nonblocking(sock,
false); });
19298 while ((ret = wolfSSL_connect(wsession->ssl)) != SSL_SUCCESS) {
19299 int ssl_error = wolfSSL_get_error(wsession->ssl, ret);
19300 if (ssl_error == SSL_ERROR_WANT_READ) {
19301 if (detail::select_read(sock, timeout_sec, timeout_usec) > 0) {
19304 }
else if (ssl_error == SSL_ERROR_WANT_WRITE) {
19305 if (detail::select_write(sock, timeout_sec, timeout_usec) > 0) {
19313 impl::map_wolfssl_error(wsession->ssl, ssl_error, err->sys_errno);
19314 err->backend_code =
static_cast<uint64_t
>(ssl_error);
19316 impl::wolfssl_last_error() =
static_cast<uint64_t
>(ssl_error);
19320 if (err) { err->code = ErrorCode::Success; }
19324inline bool accept_nonblocking(session_t session,
socket_t sock,
19325 time_t timeout_sec, time_t timeout_usec,
19328 if (err) { err->code = ErrorCode::Fatal; }
19332 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19335 detail::set_nonblocking(sock,
true);
19337 detail::scope_exit([&]() { detail::set_nonblocking(sock,
false); });
19340 while ((ret = wolfSSL_accept(wsession->ssl)) != SSL_SUCCESS) {
19341 int ssl_error = wolfSSL_get_error(wsession->ssl, ret);
19342 if (ssl_error == SSL_ERROR_WANT_READ) {
19343 if (detail::select_read(sock, timeout_sec, timeout_usec) > 0) {
19346 }
else if (ssl_error == SSL_ERROR_WANT_WRITE) {
19347 if (detail::select_write(sock, timeout_sec, timeout_usec) > 0) {
19355 impl::map_wolfssl_error(wsession->ssl, ssl_error, err->sys_errno);
19356 err->backend_code =
static_cast<uint64_t
>(ssl_error);
19358 impl::wolfssl_last_error() =
static_cast<uint64_t
>(ssl_error);
19362 if (err) { err->code = ErrorCode::Success; }
19365 wsession->sni_hostname = std::move(impl::wolfssl_pending_sni());
19366 impl::wolfssl_pending_sni().clear();
19371inline ssize_t read(session_t session,
void *buf,
size_t len, TlsError &err) {
19372 if (!session || !buf) {
19373 err.code = ErrorCode::Fatal;
19377 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19378 int ret = wolfSSL_read(wsession->ssl, buf,
static_cast<int>(len));
19381 err.code = ErrorCode::Success;
19382 return static_cast<ssize_t
>(ret);
19386 err.code = ErrorCode::PeerClosed;
19390 int ssl_error = wolfSSL_get_error(wsession->ssl, ret);
19391 err.code = impl::map_wolfssl_error(wsession->ssl, ssl_error, err.sys_errno);
19392 err.backend_code =
static_cast<uint64_t
>(ssl_error);
19393 impl::wolfssl_last_error() = err.backend_code;
19397inline ssize_t write(session_t session,
const void *buf,
size_t len,
19399 if (!session || !buf) {
19400 err.code = ErrorCode::Fatal;
19404 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19405 int ret = wolfSSL_write(wsession->ssl, buf,
static_cast<int>(len));
19408 err.code = ErrorCode::Success;
19409 return static_cast<ssize_t
>(ret);
19416 err.code = ErrorCode::PeerClosed;
19420 int ssl_error = wolfSSL_get_error(wsession->ssl, ret);
19421 err.code = impl::map_wolfssl_error(wsession->ssl, ssl_error, err.sys_errno);
19422 err.backend_code =
static_cast<uint64_t
>(ssl_error);
19423 impl::wolfssl_last_error() = err.backend_code;
19427inline int pending(const_session_t session) {
19428 if (!session) {
return 0; }
19430 static_cast<impl::WolfSSLSession *
>(
const_cast<void *
>(session));
19431 return wolfSSL_pending(wsession->ssl);
19434inline void shutdown(session_t session,
bool graceful) {
19435 if (!session) {
return; }
19436 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19441 while ((ret = wolfSSL_shutdown(wsession->ssl)) != SSL_SUCCESS &&
19443 int ssl_error = wolfSSL_get_error(wsession->ssl, ret);
19444 if (ssl_error != SSL_ERROR_WANT_READ &&
19445 ssl_error != SSL_ERROR_WANT_WRITE) {
19451 wolfSSL_shutdown(wsession->ssl);
19455inline bool is_peer_closed(session_t session,
socket_t sock) {
19457 auto wsession =
static_cast<impl::WolfSSLSession *
>(session);
19460 if (wolfSSL_pending(wsession->ssl) > 0) {
return false; }
19463 detail::set_nonblocking(sock,
true);
19465 detail::scope_exit([&]() { detail::set_nonblocking(sock,
false); });
19469 int ret = wolfSSL_peek(wsession->ssl, &buf, 1);
19472 if (ret > 0) {
return false; }
19474 int ssl_error = wolfSSL_get_error(wsession->ssl, ret);
19475 if (ssl_error == SSL_ERROR_WANT_READ) {
return false; }
19477 return ssl_error == SSL_ERROR_ZERO_RETURN || ssl_error == SSL_ERROR_SYSCALL ||
19481inline cert_t get_peer_cert(const_session_t session) {
19482 if (!session) {
return nullptr; }
19484 static_cast<impl::WolfSSLSession *
>(
const_cast<void *
>(session));
19486 WOLFSSL_X509 *cert = wolfSSL_get_peer_certificate(wsession->ssl);
19487 return static_cast<cert_t
>(cert);
19490inline void free_cert(cert_t cert) {
19491 if (cert) { wolfSSL_X509_free(
static_cast<WOLFSSL_X509 *
>(cert)); }
19494inline bool verify_hostname(cert_t cert,
const char *hostname) {
19495 if (!cert || !hostname) {
return false; }
19496 auto x509 =
static_cast<WOLFSSL_X509 *
>(cert);
19497 std::string host_str(hostname);
19500 bool is_ip = impl::is_ipv4_address(host_str);
19501 unsigned char ip_bytes[4];
19502 if (is_ip) { impl::parse_ipv4(host_str, ip_bytes); }
19505 auto *san_names =
static_cast<WOLF_STACK_OF(WOLFSSL_GENERAL_NAME) *
>(
19506 wolfSSL_X509_get_ext_d2i(x509, NID_subject_alt_name,
nullptr,
nullptr));
19509 int san_count = wolfSSL_sk_num(san_names);
19510 for (
int i = 0; i < san_count; i++) {
19512 static_cast<WOLFSSL_GENERAL_NAME *
>(wolfSSL_sk_value(san_names, i));
19513 if (!names)
continue;
19515 if (!is_ip && names->type == WOLFSSL_GEN_DNS) {
19517 unsigned char *dns_name =
nullptr;
19518 int dns_len = wolfSSL_ASN1_STRING_to_UTF8(&dns_name, names->d.dNSName);
19519 if (dns_name && dns_len > 0) {
19520 std::string san_name(
reinterpret_cast<char *
>(dns_name),
19521 static_cast<size_t>(dns_len));
19522 XFREE(dns_name,
nullptr, DYNAMIC_TYPE_OPENSSL);
19523 if (detail::match_hostname(san_name, host_str)) {
19524 wolfSSL_sk_free(san_names);
19528 }
else if (is_ip && names->type == WOLFSSL_GEN_IPADD) {
19530 unsigned char *ip_data = wolfSSL_ASN1_STRING_data(names->d.iPAddress);
19531 int ip_len = wolfSSL_ASN1_STRING_length(names->d.iPAddress);
19532 if (ip_data && ip_len == 4 && memcmp(ip_data, ip_bytes, 4) == 0) {
19533 wolfSSL_sk_free(san_names);
19538 wolfSSL_sk_free(san_names);
19542 WOLFSSL_X509_NAME *subject = wolfSSL_X509_get_subject_name(x509);
19545 int cn_len = wolfSSL_X509_NAME_get_text_by_NID(subject, NID_commonName, cn,
19548 std::string cn_str(cn,
static_cast<size_t>(cn_len));
19549 if (detail::match_hostname(cn_str, host_str)) {
return true; }
19556inline uint64_t hostname_mismatch_code() {
19557 return static_cast<uint64_t
>(DOMAIN_NAME_MISMATCH);
19560inline long get_verify_result(const_session_t session) {
19561 if (!session) {
return -1; }
19563 static_cast<impl::WolfSSLSession *
>(
const_cast<void *
>(session));
19564 long result = wolfSSL_get_verify_result(wsession->ssl);
19568inline std::string get_cert_subject_cn(cert_t cert) {
19569 if (!cert)
return "";
19570 auto x509 =
static_cast<WOLFSSL_X509 *
>(cert);
19572 WOLFSSL_X509_NAME *subject = wolfSSL_X509_get_subject_name(x509);
19573 if (!subject)
return "";
19576 int cn_len = wolfSSL_X509_NAME_get_text_by_NID(subject, NID_commonName, cn,
19578 if (cn_len <= 0)
return "";
19579 return std::string(cn,
static_cast<size_t>(cn_len));
19582inline std::string get_cert_issuer_name(cert_t cert) {
19583 if (!cert)
return "";
19584 auto x509 =
static_cast<WOLFSSL_X509 *
>(cert);
19586 WOLFSSL_X509_NAME *issuer = wolfSSL_X509_get_issuer_name(x509);
19587 if (!issuer)
return "";
19589 char *name_str = wolfSSL_X509_NAME_oneline(issuer,
nullptr, 0);
19590 if (!name_str)
return "";
19592 std::string result(name_str);
19593 XFREE(name_str,
nullptr, DYNAMIC_TYPE_OPENSSL);
19597inline bool get_cert_sans(cert_t cert, std::vector<SanEntry> &sans) {
19599 if (!cert)
return false;
19600 auto x509 =
static_cast<WOLFSSL_X509 *
>(cert);
19602 auto *san_names =
static_cast<WOLF_STACK_OF(WOLFSSL_GENERAL_NAME) *
>(
19603 wolfSSL_X509_get_ext_d2i(x509, NID_subject_alt_name,
nullptr,
nullptr));
19604 if (!san_names)
return true;
19606 int count = wolfSSL_sk_num(san_names);
19607 for (
int i = 0; i < count; i++) {
19609 static_cast<WOLFSSL_GENERAL_NAME *
>(wolfSSL_sk_value(san_names, i));
19610 if (!name)
continue;
19613 switch (name->type) {
19614 case WOLFSSL_GEN_DNS: {
19615 entry.type = SanType::DNS;
19616 unsigned char *dns_name =
nullptr;
19617 int dns_len = wolfSSL_ASN1_STRING_to_UTF8(&dns_name, name->d.dNSName);
19618 if (dns_name && dns_len > 0) {
19619 entry.value = std::string(
reinterpret_cast<char *
>(dns_name),
19620 static_cast<size_t>(dns_len));
19621 XFREE(dns_name,
nullptr, DYNAMIC_TYPE_OPENSSL);
19625 case WOLFSSL_GEN_IPADD: {
19626 entry.type = SanType::IP;
19627 unsigned char *ip_data = wolfSSL_ASN1_STRING_data(name->d.iPAddress);
19628 int ip_len = wolfSSL_ASN1_STRING_length(name->d.iPAddress);
19629 if (ip_data && ip_len == 4) {
19631 snprintf(buf,
sizeof(buf),
"%d.%d.%d.%d", ip_data[0], ip_data[1],
19632 ip_data[2], ip_data[3]);
19634 }
else if (ip_data && ip_len == 16) {
19636 snprintf(buf,
sizeof(buf),
19637 "%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
19638 "%02x%02x:%02x%02x:%02x%02x:%02x%02x",
19639 ip_data[0], ip_data[1], ip_data[2], ip_data[3], ip_data[4],
19640 ip_data[5], ip_data[6], ip_data[7], ip_data[8], ip_data[9],
19641 ip_data[10], ip_data[11], ip_data[12], ip_data[13],
19642 ip_data[14], ip_data[15]);
19647 case WOLFSSL_GEN_EMAIL:
19648 entry.type = SanType::EMAIL;
19650 unsigned char *email =
nullptr;
19651 int email_len = wolfSSL_ASN1_STRING_to_UTF8(&email, name->d.rfc822Name);
19652 if (email && email_len > 0) {
19653 entry.value = std::string(
reinterpret_cast<char *
>(email),
19654 static_cast<size_t>(email_len));
19655 XFREE(email,
nullptr, DYNAMIC_TYPE_OPENSSL);
19659 case WOLFSSL_GEN_URI:
19660 entry.type = SanType::URI;
19662 unsigned char *uri =
nullptr;
19663 int uri_len = wolfSSL_ASN1_STRING_to_UTF8(
19664 &uri, name->d.uniformResourceIdentifier);
19665 if (uri && uri_len > 0) {
19666 entry.value = std::string(
reinterpret_cast<char *
>(uri),
19667 static_cast<size_t>(uri_len));
19668 XFREE(uri,
nullptr, DYNAMIC_TYPE_OPENSSL);
19672 default: entry.type = SanType::OTHER;
break;
19675 if (!entry.value.empty()) { sans.push_back(std::move(entry)); }
19677 wolfSSL_sk_free(san_names);
19681inline bool get_cert_validity(cert_t cert, time_t ¬_before,
19682 time_t ¬_after) {
19683 if (!cert)
return false;
19684 auto x509 =
static_cast<WOLFSSL_X509 *
>(cert);
19686 const WOLFSSL_ASN1_TIME *nb = wolfSSL_X509_get_notBefore(x509);
19687 const WOLFSSL_ASN1_TIME *na = wolfSSL_X509_get_notAfter(x509);
19689 if (!nb || !na)
return false;
19692 struct tm tm_nb = {}, tm_na = {};
19693 if (wolfSSL_ASN1_TIME_to_tm(nb, &tm_nb) != WOLFSSL_SUCCESS)
return false;
19694 if (wolfSSL_ASN1_TIME_to_tm(na, &tm_na) != WOLFSSL_SUCCESS)
return false;
19697 not_before = _mkgmtime(&tm_nb);
19698 not_after = _mkgmtime(&tm_na);
19700 not_before = timegm(&tm_nb);
19701 not_after = timegm(&tm_na);
19706inline std::string get_cert_serial(cert_t cert) {
19707 if (!cert)
return "";
19708 auto x509 =
static_cast<WOLFSSL_X509 *
>(cert);
19710 WOLFSSL_ASN1_INTEGER *serial_asn1 = wolfSSL_X509_get_serialNumber(x509);
19711 if (!serial_asn1)
return "";
19714 int len = serial_asn1->length;
19715 unsigned char *data = serial_asn1->data;
19716 if (!data || len <= 0)
return "";
19718 std::string result;
19719 result.reserve(
static_cast<size_t>(len) * 2);
19720 for (
int i = 0; i < len; i++) {
19722 snprintf(hex,
sizeof(hex),
"%02X", data[i]);
19728inline bool get_cert_der(cert_t cert, std::vector<unsigned char> &der) {
19729 if (!cert)
return false;
19730 auto x509 =
static_cast<WOLFSSL_X509 *
>(cert);
19733 const unsigned char *der_data = wolfSSL_X509_get_der(x509, &der_len);
19734 if (!der_data || der_len <= 0)
return false;
19736 der.assign(der_data, der_data + der_len);
19740inline const char *get_sni(const_session_t session) {
19741 if (!session)
return nullptr;
19742 auto wsession =
static_cast<const impl::WolfSSLSession *
>(session);
19745 if (!wsession->sni_hostname.empty()) {
19746 return wsession->sni_hostname.c_str();
19750 if (!wsession->hostname.empty()) {
return wsession->hostname.c_str(); }
19755inline uint64_t peek_error() {
19756 return static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19759inline uint64_t get_error() {
19760 uint64_t err = impl::wolfssl_last_error();
19761 impl::wolfssl_last_error() = 0;
19765inline std::string error_string(uint64_t code) {
19767 wolfSSL_ERR_error_string(
static_cast<unsigned long>(code), buf);
19768 return std::string(buf);
19771inline ca_store_t create_ca_store(
const char *pem,
size_t len) {
19772 if (!pem || len == 0) {
return nullptr; }
19774 WOLFSSL_CTX *tmp_ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
19775 if (!tmp_ctx) {
return nullptr; }
19776 int ret = wolfSSL_CTX_load_verify_buffer(
19777 tmp_ctx,
reinterpret_cast<const unsigned char *
>(pem),
19778 static_cast<long>(len), SSL_FILETYPE_PEM);
19779 wolfSSL_CTX_free(tmp_ctx);
19780 if (ret != SSL_SUCCESS) {
return nullptr; }
19781 return static_cast<ca_store_t
>(
19782 new impl::WolfSSLCAStore{std::string(pem, len)});
19785inline void free_ca_store(ca_store_t store) {
19786 delete static_cast<impl::WolfSSLCAStore *
>(store);
19789inline bool set_ca_store(ctx_t ctx, ca_store_t store) {
19790 if (!ctx || !store) {
return false; }
19791 auto *wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19792 auto *ca =
static_cast<impl::WolfSSLCAStore *
>(store);
19793 int ret = wolfSSL_CTX_load_verify_buffer(
19794 wctx->ctx,
reinterpret_cast<const unsigned char *
>(ca->pem_data.data()),
19795 static_cast<long>(ca->pem_data.size()), SSL_FILETYPE_PEM);
19796 if (ret == SSL_SUCCESS) { wctx->ca_pem_data_ += ca->pem_data; }
19797 return ret == SSL_SUCCESS;
19800inline size_t get_ca_certs(ctx_t ctx, std::vector<cert_t> &certs) {
19802 if (!ctx) {
return 0; }
19803 auto *wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19804 if (wctx->ca_pem_data_.empty()) {
return 0; }
19806 const std::string &pem = wctx->ca_pem_data_;
19807 const std::string begin_marker =
"-----BEGIN CERTIFICATE-----";
19808 const std::string end_marker =
"-----END CERTIFICATE-----";
19810 while ((pos = pem.find(begin_marker, pos)) != std::string::npos) {
19811 size_t end_pos = pem.find(end_marker, pos);
19812 if (end_pos == std::string::npos) {
break; }
19813 end_pos += end_marker.size();
19814 std::string cert_pem = pem.substr(pos, end_pos - pos);
19815 WOLFSSL_X509 *x509 = wolfSSL_X509_load_certificate_buffer(
19816 reinterpret_cast<const unsigned char *
>(cert_pem.data()),
19817 static_cast<int>(cert_pem.size()), WOLFSSL_FILETYPE_PEM);
19818 if (x509) { certs.push_back(
static_cast<cert_t
>(x509)); }
19821 return certs.size();
19824inline std::vector<std::string> get_ca_names(ctx_t ctx) {
19825 std::vector<std::string> names;
19826 if (!ctx) {
return names; }
19827 auto *wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19828 if (wctx->ca_pem_data_.empty()) {
return names; }
19830 const std::string &pem = wctx->ca_pem_data_;
19831 const std::string begin_marker =
"-----BEGIN CERTIFICATE-----";
19832 const std::string end_marker =
"-----END CERTIFICATE-----";
19834 while ((pos = pem.find(begin_marker, pos)) != std::string::npos) {
19835 size_t end_pos = pem.find(end_marker, pos);
19836 if (end_pos == std::string::npos) {
break; }
19837 end_pos += end_marker.size();
19838 std::string cert_pem = pem.substr(pos, end_pos - pos);
19839 WOLFSSL_X509 *x509 = wolfSSL_X509_load_certificate_buffer(
19840 reinterpret_cast<const unsigned char *
>(cert_pem.data()),
19841 static_cast<int>(cert_pem.size()), WOLFSSL_FILETYPE_PEM);
19843 WOLFSSL_X509_NAME *subject = wolfSSL_X509_get_subject_name(x509);
19845 char *name_str = wolfSSL_X509_NAME_oneline(subject,
nullptr, 0);
19847 names.push_back(name_str);
19848 XFREE(name_str,
nullptr, DYNAMIC_TYPE_OPENSSL);
19851 wolfSSL_X509_free(x509);
19858inline bool update_server_cert(ctx_t ctx,
const char *cert_pem,
19859 const char *key_pem,
const char *password) {
19860 if (!ctx || !cert_pem || !key_pem) {
return false; }
19861 auto *wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19864 int ret = wolfSSL_CTX_use_certificate_buffer(
19865 wctx->ctx,
reinterpret_cast<const unsigned char *
>(cert_pem),
19866 static_cast<long>(strlen(cert_pem)), SSL_FILETYPE_PEM);
19867 if (ret != SSL_SUCCESS) {
19868 impl::wolfssl_last_error() =
19869 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19874 if (password) { impl::set_wolfssl_password_cb(wctx->ctx, password); }
19877 ret = wolfSSL_CTX_use_PrivateKey_buffer(
19878 wctx->ctx,
reinterpret_cast<const unsigned char *
>(key_pem),
19879 static_cast<long>(strlen(key_pem)), SSL_FILETYPE_PEM);
19880 if (ret != SSL_SUCCESS) {
19881 impl::wolfssl_last_error() =
19882 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19889inline bool update_server_client_ca(ctx_t ctx,
const char *ca_pem) {
19890 if (!ctx || !ca_pem) {
return false; }
19891 auto *wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19893 int ret = wolfSSL_CTX_load_verify_buffer(
19894 wctx->ctx,
reinterpret_cast<const unsigned char *
>(ca_pem),
19895 static_cast<long>(strlen(ca_pem)), SSL_FILETYPE_PEM);
19896 if (ret != SSL_SUCCESS) {
19897 impl::wolfssl_last_error() =
19898 static_cast<uint64_t
>(wolfSSL_ERR_peek_last_error());
19904inline bool set_verify_callback(ctx_t ctx, VerifyCallback callback) {
19905 if (!ctx) {
return false; }
19906 auto *wctx =
static_cast<impl::WolfSSLContext *
>(ctx);
19908 impl::get_verify_callback() = std::move(callback);
19909 wctx->has_verify_callback =
static_cast<bool>(impl::get_verify_callback());
19911 if (wctx->has_verify_callback) {
19912 wolfSSL_CTX_set_verify(wctx->ctx, SSL_VERIFY_PEER,
19913 impl::wolfssl_verify_callback);
19915 wolfSSL_CTX_set_verify(
19917 wctx->verify_client
19918 ? (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
19925inline long get_verify_error(const_session_t session) {
19926 if (!session) {
return -1; }
19928 static_cast<impl::WolfSSLSession *
>(
const_cast<void *
>(session));
19929 return wolfSSL_get_verify_result(wsession->ssl);
19932inline std::string verify_error_string(
long error_code) {
19933 if (error_code == 0) {
return ""; }
19935 wolfSSL_X509_verify_cert_error_string(
static_cast<int>(error_code));
19936 return str ? std::string(str) : std::string();
19946inline bool WebSocket::send_frame(
Opcode op,
const char *data,
size_t len,
19948 std::lock_guard<std::mutex> lock(write_mutex_);
19949 if (closed_) {
return false; }
19956 std::string payload;
19967 std::lock_guard<std::mutex> lock(write_mutex_);
19969 payload.size(),
true, !is_server_);
19974 if (!closed_.exchange(
true)) {
19976 std::lock_guard<std::mutex> lock(write_mutex_);
19978 payload.size(),
true, !is_server_);
19985 msg = std::move(payload);
19991 std::string cont_payload;
19994 strm_, cont_opcode, cont_payload, cont_fin, is_server_,
20000 std::lock_guard<std::mutex> lock(write_mutex_);
20002 strm_,
Opcode::Pong, cont_payload.data(), cont_payload.size(),
20003 true, !is_server_);
20008 if (!closed_.exchange(
true)) {
20009 std::lock_guard<std::mutex> lock(write_mutex_);
20012 cont_payload.size(),
true, !is_server_);
20021 msg += cont_payload;
20026 if (cont_fin) {
break; }
20036 default: closed_ =
true;
return Fail;
20043 return send_frame(
Opcode::Text, data.data(), data.size());
20051 if (closed_.exchange(
true)) {
return; }
20052 ping_cv_.notify_all();
20053 std::string payload;
20054 auto code =
static_cast<uint16_t
>(status);
20055 payload.push_back(
static_cast<char>((code >> 8) & 0xFF));
20056 payload.push_back(
static_cast<char>(code & 0xFF));
20059 payload += reason.substr(0, 123);
20061 std::lock_guard<std::mutex> lock(write_mutex_);
20063 payload.size(),
true, !is_server_);
20080 std::lock_guard<std::mutex> lock(ping_mutex_);
20083 ping_cv_.notify_all();
20084 if (ping_thread_.joinable()) { ping_thread_.join(); }
20087inline void WebSocket::start_heartbeat() {
20088 if (ping_interval_sec_ == 0) {
return; }
20089 ping_thread_ = std::thread([
this]() {
20090 std::unique_lock<std::mutex> lock(ping_mutex_);
20092 ping_cv_.wait_for(lock, std::chrono::seconds(ping_interval_sec_));
20093 if (closed_) {
break; }
20110 const std::string &scheme_host_port_path,
const Headers &headers)
20111 : headers_(headers) {
20112 const static std::regex re(
20113 R
"(([a-z]+):\/\/(?:\[([a-fA-F\d:]+)\]|([^:/?#]+))(?::(\d+))?(\/.*))");
20116 if (std::regex_match(scheme_host_port_path, m, re)) {
20117 auto scheme = m[1].str();
20119#ifdef CPPHTTPLIB_SSL_ENABLED
20120 if (scheme !=
"ws" && scheme !=
"wss") {
20122 if (scheme !=
"ws") {
20124#ifndef CPPHTTPLIB_NO_EXCEPTIONS
20125 std::string msg =
"'" + scheme +
"' scheme is not supported.";
20126 throw std::invalid_argument(msg);
20131 auto is_ssl = scheme ==
"wss";
20133 host_ = m[2].str();
20134 if (host_.empty()) { host_ = m[3].str(); }
20136 auto port_str = m[4].str();
20137 port_ = is_ssl ? 443 : 80;
20140 path_ = m[5].str();
20142#ifdef CPPHTTPLIB_SSL_ENABLED
20145 if (is_ssl) {
return; }
20156inline void WebSocketClient::shutdown_and_close() {
20157#ifdef CPPHTTPLIB_SSL_ENABLED
20159 if (tls_session_) {
20160 tls::shutdown(tls_session_,
true);
20161 tls::free_session(tls_session_);
20162 tls_session_ =
nullptr;
20165 tls::free_context(tls_ctx_);
20166 tls_ctx_ =
nullptr;
20170 if (ws_ && ws_->is_open()) { ws_->close(); }
20179inline bool WebSocketClient::create_stream(std::unique_ptr<Stream> &strm) {
20180#ifdef CPPHTTPLIB_SSL_ENABLED
20182 if (!detail::setup_client_tls_session(
20183 host_, tls_ctx_, tls_session_, sock_,
20184 server_certificate_verification_, ca_cert_file_path_,
20185 ca_cert_store_, read_timeout_sec_, read_timeout_usec_)) {
20189 strm = std::unique_ptr<Stream>(
new detail::SSLSocketStream(
20190 sock_, tls_session_, read_timeout_sec_, read_timeout_usec_,
20191 write_timeout_sec_, write_timeout_usec_));
20195 strm = std::unique_ptr<Stream>(
20196 new detail::SocketStream(sock_, read_timeout_sec_, read_timeout_usec_,
20197 write_timeout_sec_, write_timeout_usec_));
20202 if (!is_valid_) {
return false; }
20203 shutdown_and_close();
20207 host_, std::string(), port_, address_family_, tcp_nodelay_, ipv6_v6only_,
20208 socket_options_, connection_timeout_sec_, connection_timeout_usec_,
20209 read_timeout_sec_, read_timeout_usec_, write_timeout_sec_,
20210 write_timeout_usec_, interface_, error);
20214 std::unique_ptr<Stream> strm;
20215 if (!create_stream(strm)) {
20216 shutdown_and_close();
20220 std::string selected_subprotocol;
20222 selected_subprotocol)) {
20223 shutdown_and_close();
20226 subprotocol_ = std::move(selected_subprotocol);
20231 ws_ = std::unique_ptr<WebSocket>(
20232 new WebSocket(std::move(strm), req,
false, websocket_ping_interval_sec_));
20237 if (!ws_) {
return Fail; }
20238 return ws_->read(msg);
20242 if (!ws_) {
return false; }
20243 return ws_->send(data);
20247 if (!ws_) {
return false; }
20248 return ws_->send(data, len);
20252 const std::string &reason) {
20253 if (ws_) { ws_->close(status, reason); }
20259 return subprotocol_;
20263 read_timeout_sec_ = sec;
20264 read_timeout_usec_ = usec;
20268 write_timeout_sec_ = sec;
20269 write_timeout_usec_ = usec;
20273 websocket_ping_interval_sec_ = sec;
20279 address_family_ = family;
20285 socket_options_ = std::move(socket_options);
20289 connection_timeout_sec_ = sec;
20290 connection_timeout_usec_ = usec;
20297#ifdef CPPHTTPLIB_SSL_ENABLED
20299inline void WebSocketClient::set_ca_cert_path(
const std::string &path) {
20300 ca_cert_file_path_ = path;
20303inline void WebSocketClient::set_ca_cert_store(tls::ca_store_t store) {
20304 ca_cert_store_ = store;
20308WebSocketClient::enable_server_certificate_verification(
bool enabled) {
20309 server_certificate_verification_ = enabled;
Definition httplib.h:1971
void set_proxy_basic_auth(const std::string &username, const std::string &password)
Definition httplib.h:14575
void set_socket_options(SocketOptions socket_options)
Definition httplib.h:14553
time_t write_timeout_sec_
Definition httplib.h:2264
std::string host() const
Definition httplib.h:14485
virtual bool ensure_socket_connection(Socket &socket, Error &error)
Definition httplib.h:12281
bool decompress_
Definition httplib.h:2283
void set_basic_auth(const std::string &username, const std::string &password)
Definition httplib.h:14515
time_t read_timeout_sec_
Definition httplib.h:2262
void set_error_logger(ErrorLogger error_logger)
Definition httplib.h:14649
size_t socket_requests_in_flight_
Definition httplib.h:2242
void close_socket(Socket &socket)
Definition httplib.h:12305
std::string proxy_bearer_token_auth_token_
Definition httplib.h:2295
bool write_content_with_provider(Stream &strm, const Request &req, Error &error) const
Definition httplib.h:13094
void set_decompress(bool on)
Definition httplib.h:14559
socket_t socket() const
Definition httplib.h:14494
void set_proxy(const std::string &host, int port)
Definition httplib.h:14570
Socket socket_
Definition httplib.h:2237
void set_interface(const std::string &intf)
Definition httplib.h:14566
time_t connection_timeout_sec_
Definition httplib.h:2260
bool follow_location_
Definition httplib.h:2273
Result Patch(const std::string &path)
Definition httplib.h:14178
void stop()
Definition httplib.h:14462
bool tcp_nodelay_
Definition httplib.h:2278
const std::string host_
Definition httplib.h:2233
time_t max_timeout_msec_
Definition httplib.h:2266
time_t read_timeout_usec_
Definition httplib.h:2263
std::string proxy_host_
Definition httplib.h:2290
Result Delete(const std::string &path, DownloadProgress progress=nullptr)
Definition httplib.h:14377
void set_tcp_nodelay(bool on)
Definition httplib.h:14549
void set_proxy_bearer_token_auth(const std::string &token)
Definition httplib.h:14581
std::string basic_auth_password_
Definition httplib.h:2269
bool send(Request &req, Response &res, Error &error)
Definition httplib.h:12362
size_t payload_max_length_
Definition httplib.h:2285
virtual bool setup_proxy_connection(Socket &socket, std::chrono::time_point< std::chrono::steady_clock > start_time, Response &res, bool &success, Error &error)
Definition httplib.h:12285
virtual void shutdown_ssl(Socket &socket, bool shutdown_gracefully)
Definition httplib.h:12292
void set_connection_timeout(time_t sec, time_t usec=0)
Definition httplib.h:14496
std::string bearer_token_auth_token_
Definition httplib.h:2270
void set_hostname_addr_map(std::map< std::string, std::string > addr_map)
Definition httplib.h:14532
int proxy_port_
Definition httplib.h:2291
void set_logger(Logger logger)
Definition httplib.h:14645
ClientImpl(const std::string &host)
Definition httplib.h:12178
void set_compress(bool on)
Definition httplib.h:14557
void output_log(const Request &req, const Response &res) const
Definition httplib.h:13444
bool path_encode_
Definition httplib.h:2275
int port() const
Definition httplib.h:14487
int address_family_
Definition httplib.h:2277
void set_address_family(int family)
Definition httplib.h:14545
std::string client_key_path_
Definition httplib.h:2258
std::string interface_
Definition httplib.h:2288
Result Put(const std::string &path)
Definition httplib.h:13981
Headers default_headers_
Definition httplib.h:2250
std::string client_cert_path_
Definition httplib.h:2257
void set_ipv6_v6only(bool on)
Definition httplib.h:14551
bool ipv6_v6only_
Definition httplib.h:2279
Result Post(const std::string &path)
Definition httplib.h:13783
time_t connection_timeout_usec_
Definition httplib.h:2261
std::string proxy_basic_auth_username_
Definition httplib.h:2293
bool has_payload_max_length_
Definition httplib.h:2286
void shutdown_socket(Socket &socket) const
Definition httplib.h:12300
Logger logger_
Definition httplib.h:2298
std::function< ssize_t(Stream &, Headers &)> header_writer_
Definition httplib.h:2253
bool process_request(Stream &strm, Request &req, Response &res, bool close_connection, Error &error)
Definition httplib.h:13460
std::thread::id socket_requests_are_from_thread_
Definition httplib.h:2243
bool compress_
Definition httplib.h:2282
std::mutex logger_mutex_
Definition httplib.h:2297
std::map< std::string, std::string > addr_map_
Definition httplib.h:2247
ErrorLogger error_logger_
Definition httplib.h:2299
time_t write_timeout_usec_
Definition httplib.h:2265
std::string proxy_basic_auth_password_
Definition httplib.h:2294
void set_write_timeout(time_t sec, time_t usec=0)
Definition httplib.h:14506
void copy_settings(const ClientImpl &rhs)
Definition httplib.h:12208
void output_error_log(const Error &err, const Request *req) const
Definition httplib.h:13452
void set_max_timeout(time_t msec)
Definition httplib.h:14511
void set_header_writer(std::function< ssize_t(Stream &, Headers &)> const &writer)
Definition httplib.h:14540
std::recursive_mutex request_mutex_
Definition httplib.h:2239
const int port_
Definition httplib.h:2234
Result Options(const std::string &path)
Definition httplib.h:14445
size_t is_socket_open() const
Definition httplib.h:14489
void set_default_headers(Headers headers)
Definition httplib.h:14536
void set_payload_max_length(size_t length)
Definition httplib.h:14561
void set_follow_location(bool on)
Definition httplib.h:14527
SocketOptions socket_options_
Definition httplib.h:2280
void set_keep_alive(bool on)
Definition httplib.h:14525
void set_path_encode(bool on)
Definition httplib.h:14529
bool socket_should_be_closed_when_request_is_done_
Definition httplib.h:2244
bool keep_alive_
Definition httplib.h:2272
Result Head(const std::string &path)
Definition httplib.h:13766
std::mutex socket_mutex_
Definition httplib.h:2238
virtual ~ClientImpl()
Definition httplib.h:12190
StreamHandle open_stream(const std::string &method, const std::string &path, const Params ¶ms={}, const Headers &headers={}, const std::string &body={}, const std::string &content_type={})
Definition httplib.h:12544
std::string basic_auth_username_
Definition httplib.h:2268
virtual bool create_and_connect_socket(Socket &socket, Error &error)
Definition httplib.h:12273
Result Get(const std::string &path, DownloadProgress progress=nullptr)
Definition httplib.h:13671
virtual bool is_valid() const
Definition httplib.h:12206
void set_read_timeout(time_t sec, time_t usec=0)
Definition httplib.h:14501
void set_bearer_token_auth(const std::string &token)
Definition httplib.h:14521
Definition httplib.h:2388
ClientImpl::StreamHandle open_stream(const std::string &method, const std::string &path, const Params ¶ms={}, const Headers &headers={}, const std::string &body={}, const std::string &content_type={})
Definition httplib.h:15228
void set_read_timeout(time_t sec, time_t usec=0)
Definition httplib.h:15278
Result Post(const std::string &path)
Definition httplib.h:14797
Client(Client &&)=default
Result Put(const std::string &path)
Definition httplib.h:14924
void set_connection_timeout(time_t sec, time_t usec=0)
Definition httplib.h:15274
bool send(Request &req, Response &res, Error &error)
Definition httplib.h:15234
Result Options(const std::string &path)
Definition httplib.h:15220
void set_default_headers(Headers headers)
Definition httplib.h:15255
void set_proxy_bearer_token_auth(const std::string &token)
Definition httplib.h:15326
void set_hostname_addr_map(std::map< std::string, std::string > addr_map)
Definition httplib.h:15251
Client & operator=(Client &&)=default
void set_proxy_basic_auth(const std::string &username, const std::string &password)
Definition httplib.h:15322
void set_tcp_nodelay(bool on)
Definition httplib.h:15268
void set_keep_alive(bool on)
Definition httplib.h:15294
void stop()
Definition httplib.h:15240
void set_max_timeout(time_t msec)
Definition httplib.h:2919
void set_interface(const std::string &intf)
Definition httplib.h:15315
socket_t socket() const
Definition httplib.h:15248
Result Get(const std::string &path, DownloadProgress progress=nullptr)
Definition httplib.h:14740
void set_decompress(bool on)
Definition httplib.h:15309
size_t is_socket_open() const
Definition httplib.h:15246
bool is_valid() const
Definition httplib.h:14736
void set_follow_location(bool on)
Definition httplib.h:15295
void set_path_encode(bool on)
Definition httplib.h:15299
void set_proxy(const std::string &host, int port)
Definition httplib.h:15319
void set_write_timeout(time_t sec, time_t usec=0)
Definition httplib.h:15282
Client(const std::string &scheme_host_port)
Definition httplib.h:14673
void set_address_family(int family)
Definition httplib.h:15264
Result Head(const std::string &path)
Definition httplib.h:14792
std::string host() const
Definition httplib.h:15242
void set_error_logger(ErrorLogger error_logger)
Definition httplib.h:15334
void set_bearer_token_auth(const std::string &token)
Definition httplib.h:15290
void set_payload_max_length(size_t length)
Definition httplib.h:15311
void set_url_encode(bool on)
Definition httplib.h:15303
void set_logger(Logger logger)
Definition httplib.h:15330
void set_header_writer(std::function< ssize_t(Stream &, Headers &)> const &writer)
Definition httplib.h:15259
Result Patch(const std::string &path)
Definition httplib.h:15050
void set_socket_options(SocketOptions socket_options)
Definition httplib.h:15270
void set_compress(bool on)
Definition httplib.h:15307
Result Delete(const std::string &path, DownloadProgress progress=nullptr)
Definition httplib.h:15179
void set_basic_auth(const std::string &username, const std::string &password)
Definition httplib.h:15286
int port() const
Definition httplib.h:15244
Definition httplib.h:1100
Reader reader_
Definition httplib.h:1118
ContentReader(Reader reader, FormDataReader multipart_reader)
Definition httplib.h:1106
bool operator()(FormDataHeader header, ContentReceiver receiver) const
Definition httplib.h:1110
bool operator()(ContentReceiver receiver) const
Definition httplib.h:1114
std::function< bool(ContentReceiver receiver)> Reader
Definition httplib.h:1102
FormDataReader formdata_reader_
Definition httplib.h:1119
std::function< bool(FormDataHeader header, ContentReceiver receiver)> FormDataReader
Definition httplib.h:1103
std::function< bool(const char *data, size_t data_len)> write
Definition httplib.h:995
DataSink(DataSink &&)=delete
DataSink(const DataSink &)=delete
DataSink & operator=(DataSink &&)=delete
DataSink & operator=(const DataSink &)=delete
std::function< void()> done
Definition httplib.h:997
std::function< bool()> is_writable
Definition httplib.h:996
DataSink()
Definition httplib.h:988
std::ostream os
Definition httplib.h:999
std::function< void(const Headers &trailer)> done_with_trailer
Definition httplib.h:998
Definition httplib.h:1835
bool has_request_header(const std::string &key) const
Definition httplib.h:9871
Response & value()
Definition httplib.h:1847
const Response & value() const
Definition httplib.h:1846
size_t get_request_header_value_count(const std::string &key) const
Definition httplib.h:9882
const Response & operator*() const
Definition httplib.h:1848
bool operator==(std::nullptr_t) const
Definition httplib.h:1844
Result(std::unique_ptr< Response > &&res, Error err, Headers &&request_headers=Headers{})
Definition httplib.h:1838
bool operator!=(std::nullptr_t) const
Definition httplib.h:1845
const Response * operator->() const
Definition httplib.h:1850
Response * operator->()
Definition httplib.h:1851
size_t get_request_header_value_u64(const std::string &key, size_t def=0, size_t id=0) const
Definition httplib.h:9865
Error error() const
Definition httplib.h:1854
Response & operator*()
Definition httplib.h:1849
std::string get_request_header_value(const std::string &key, const char *def="", size_t id=0) const
Definition httplib.h:9875
Definition httplib.h:1573
time_t read_timeout_usec_
Definition httplib.h:1709
Server & set_default_file_mimetype(const std::string &mime)
Definition httplib.h:10741
void stop()
Definition httplib.h:10918
std::function< int(const Request &, Response &)> Expect100ContinueHandler
Definition httplib.h:1590
Server & Put(const std::string &pattern, Handler handler)
Definition httplib.h:10639
Server & Delete(const std::string &pattern, Handler handler)
Definition httplib.h:10663
Server & set_pre_routing_handler(HandlerWithResponse handler)
Definition httplib.h:10771
Server & set_write_timeout(time_t sec, time_t usec=0)
Definition httplib.h:10860
time_t idle_interval_usec_
Definition httplib.h:1713
size_t keep_alive_max_count_
Definition httplib.h:1706
time_t write_timeout_sec_
Definition httplib.h:1710
Server & set_error_handler(ErrorHandlerFunc &&handler)
Definition httplib.h:1630
bool listen(const std::string &host, int port, int socket_flags=0)
Definition httplib.h:10905
Server & WebSocket(const std::string &pattern, WebSocketHandler handler)
Definition httplib.h:10680
bool set_base_dir(const std::string &dir, const std::string &mount_point=std::string())
Definition httplib.h:10695
void decommission()
Definition httplib.h:10928
bool listen_after_bind()
Definition httplib.h:10903
std::vector< std::string > trusted_proxies_
Definition httplib.h:1704
Server & set_tcp_nodelay(bool on)
Definition httplib.h:10812
Server & set_header_writer(std::function< ssize_t(Stream &, Headers &)> const &writer)
Definition httplib.h:10832
Server & set_payload_max_length(size_t length)
Definition httplib.h:10872
Server & Options(const std::string &pattern, Handler handler)
Definition httplib.h:10675
virtual bool is_valid() const
Definition httplib.h:12124
int bind_to_any_port(const std::string &host, int socket_flags=0)
Definition httplib.h:10897
Server()
Definition httplib.h:10601
time_t idle_interval_sec_
Definition httplib.h:1712
bool bind_to_port(const std::string &host, int port, int socket_flags=0)
Definition httplib.h:10891
time_t write_timeout_usec_
Definition httplib.h:1711
time_t keep_alive_timeout_sec_
Definition httplib.h:1707
HandlerResponse
Definition httplib.h:1580
@ Unhandled
Definition httplib.h:1582
@ Handled
Definition httplib.h:1581
Server & Patch(const std::string &pattern, Handler handler)
Definition httplib.h:10651
Server & set_default_headers(Headers headers)
Definition httplib.h:10827
time_t websocket_ping_interval_sec_
Definition httplib.h:1715
Server & Get(const std::string &pattern, Handler handler)
Definition httplib.h:10622
Server & set_trusted_proxies(const std::vector< std::string > &proxies)
Definition httplib.h:10839
Server & set_file_request_handler(Handler handler)
Definition httplib.h:10746
std::function< void(const Request &, Response &)> Handler
Definition httplib.h:1575
std::function< std::string(const std::vector< std::string > &protocols)> SubProtocolSelector
Definition httplib.h:1595
std::function< void(const Request &, Response &, std::exception_ptr ep)> ExceptionHandler
Definition httplib.h:1577
std::atomic< socket_t > svr_sock_
Definition httplib.h:1702
void wait_until_ready() const
Definition httplib.h:10912
Server & set_post_routing_handler(Handler handler)
Definition httplib.h:10776
bool is_running() const
Definition httplib.h:10910
Server & Post(const std::string &pattern, Handler handler)
Definition httplib.h:10627
Server & set_idle_interval(time_t sec, time_t usec=0)
Definition httplib.h:10866
Server & set_address_family(int family)
Definition httplib.h:10807
bool process_request(Stream &strm, const std::string &remote_addr, int remote_port, const std::string &local_addr, int local_port, bool close_connection, bool &connection_closed, const std::function< void(Request &)> &setup_request, bool *websocket_upgraded=nullptr)
Definition httplib.h:11871
bool remove_mount_point(const std::string &mount_point)
Definition httplib.h:10724
Server & set_keep_alive_timeout(time_t sec)
Definition httplib.h:10849
std::function< TaskQueue *(void)> new_task_queue
Definition httplib.h:1692
Server & set_logger(Logger logger)
Definition httplib.h:10786
std::function< HandlerResponse(const Request &, Response &)> HandlerWithResponse
Definition httplib.h:1584
std::function< void(const Request &, ws::WebSocket &)> WebSocketHandler
Definition httplib.h:1593
bool set_mount_point(const std::string &mount_point, const std::string &dir, Headers headers=Headers())
Definition httplib.h:10700
Server & set_socket_options(SocketOptions socket_options)
Definition httplib.h:10822
Server & set_pre_compression_logger(Logger logger)
Definition httplib.h:10796
time_t read_timeout_sec_
Definition httplib.h:1708
Server & set_pre_request_handler(HandlerWithResponse handler)
Definition httplib.h:10781
Server & set_exception_handler(ExceptionHandler handler)
Definition httplib.h:10766
Server & set_error_logger(ErrorLogger error_logger)
Definition httplib.h:10791
Server & set_expect_100_continue_handler(Expect100ContinueHandler handler)
Definition httplib.h:10802
Server & set_websocket_ping_interval(time_t sec)
Definition httplib.h:10877
Server & set_ipv6_v6only(bool on)
Definition httplib.h:10817
size_t payload_max_length_
Definition httplib.h:1714
Server & set_file_extension_and_mimetype_mapping(const std::string &ext, const std::string &mime)
Definition httplib.h:10735
std::function< void( const Request &, Response &, const ContentReader &content_reader)> HandlerWithContentReader
Definition httplib.h:1587
Server & set_keep_alive_max_count(size_t count)
Definition httplib.h:10844
Server & set_read_timeout(time_t sec, time_t usec=0)
Definition httplib.h:10854
Definition httplib.h:1399
Error get_error() const
Definition httplib.h:1424
virtual bool wait_writable() const =0
Error error_
Definition httplib.h:1427
virtual bool wait_readable() const =0
virtual ssize_t write(const char *ptr, size_t size)=0
virtual ssize_t read(char *ptr, size_t size)=0
virtual void get_remote_ip_and_port(std::string &ip, int &port) const =0
virtual void get_local_ip_and_port(std::string &ip, int &port) const =0
virtual bool is_peer_alive() const
Definition httplib.h:1406
virtual time_t duration() const =0
virtual void set_read_timeout(time_t sec, time_t usec=0)
Definition httplib.h:1416
virtual ~Stream()=default
virtual socket_t socket() const =0
virtual bool is_readable() const =0
Definition httplib.h:1430
virtual bool enqueue(std::function< void()> fn)=0
virtual void on_idle()
Definition httplib.h:1438
virtual ~TaskQueue()=default
virtual void shutdown()=0
Definition httplib.h:1441
ThreadPool(size_t n, size_t max_n=0, size_t mqr=0)
Definition httplib.h:9971
void shutdown() override
Definition httplib.h:10008
ThreadPool(const ThreadPool &)=delete
~ThreadPool() override=default
bool enqueue(std::function< void()> fn) override
Definition httplib.h:9987
bool has_value() const noexcept
Definition httplib.h:884
void reset() noexcept
Definition httplib.h:885
any & operator=(any &&) noexcept=default
any & operator=(T &&v)
Definition httplib.h:879
any(any &&) noexcept=default
const char * what() const noexcept override
Definition httplib.h:826
bool wait_writable() const override
Definition httplib.h:10264
void get_remote_ip_and_port(std::string &ip, int &port) const override
Definition httplib.h:10281
void get_local_ip_and_port(std::string &ip, int &port) const override
Definition httplib.h:10284
ssize_t write(const char *ptr, size_t size) override
Definition httplib.h:10276
~BufferStream() override=default
time_t duration() const override
Definition httplib.h:10289
bool wait_readable() const override
Definition httplib.h:10262
const std::string & get_buffer() const
Definition httplib.h:10291
socket_t socket() const override
Definition httplib.h:10287
bool is_readable() const override
Definition httplib.h:10260
ssize_t read(char *ptr, size_t size) override
Definition httplib.h:10266
Definition httplib.h:8571
bool operator()(size_t offset, size_t, DataSink &sink)
Definition httplib.h:8577
ContentProviderAdapter(ContentProviderWithoutLength &&content_provider)
Definition httplib.h:8573
virtual bool match(Request &request) const =0
virtual ~MatcherBase()=default
MatcherBase(std::string pattern)
Definition httplib.h:1494
const std::string & pattern() const
Definition httplib.h:1497
PathParamsMatcher(const std::string &pattern)
Definition httplib.h:10293
bool match(Request &request) const override
Definition httplib.h:10342
bool match(Request &request) const override
Definition httplib.h:10385
RegexMatcher(const std::string &pattern)
Definition httplib.h:1555
Definition httplib.h:5551
bool wait_readable() const override
Definition httplib.h:10142
bool wait_writable() const override
Definition httplib.h:10155
void get_remote_ip_and_port(std::string &ip, int &port) const override
Definition httplib.h:10236
socket_t socket() const override
Definition httplib.h:10246
bool is_peer_alive() const override
Definition httplib.h:10159
time_t duration() const override
Definition httplib.h:10248
bool is_readable() const override
Definition httplib.h:10138
ssize_t write(const char *ptr, size_t size) override
Definition httplib.h:10225
void get_local_ip_and_port(std::string &ip, int &port) const override
Definition httplib.h:10241
SocketStream(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, time_t write_timeout_usec, time_t max_timeout_msec=0, std::chrono::time_point< std::chrono::steady_clock > start_time=(std::chrono::steady_clock::time_point::min)())
Definition httplib.h:10124
ssize_t read(char *ptr, size_t size) override
Definition httplib.h:10163
void set_read_timeout(time_t sec, time_t usec=0) override
Definition httplib.h:10254
Definition httplib.h:3088
virtual bool compress(const char *data, size_t data_length, bool last, Callback callback)=0
std::function< bool(const char *data, size_t data_len)> Callback
Definition httplib.h:3092
virtual ~compressor()=default
Definition httplib.h:3097
virtual ~decompressor()=default
virtual bool decompress(const char *data, size_t data_length, Callback callback)=0
virtual bool is_valid() const =0
std::function< bool(const char *data, size_t data_len)> Callback
Definition httplib.h:3103
const char * data() const
Definition httplib.h:5405
bool open(const char *path)
Definition httplib.h:5330
~mmap()
Definition httplib.h:5328
size_t size() const
Definition httplib.h:5403
mmap(const char *path)
Definition httplib.h:5326
bool is_open() const
Definition httplib.h:5399
void close()
Definition httplib.h:5409
Definition httplib.h:3108
~nocompressor() override=default
bool compress(const char *data, size_t data_length, bool, Callback callback) override
Definition httplib.h:6644
Definition httplib.h:3205
stream_line_reader(Stream &strm, char *fixed_buffer, size_t fixed_buffer_size)
Definition httplib.h:5247
bool getline()
Definition httplib.h:5273
bool end_with_crlf() const
Definition httplib.h:5268
size_t size() const
Definition httplib.h:5260
const char * ptr() const
Definition httplib.h:5252
void start_async()
Definition httplib.h:4032
const std::string & last_event_id() const
Definition httplib.h:4023
bool is_connected() const
Definition httplib.h:4021
SSEClient & on_event(const std::string &type, MessageHandler handler)
Definition httplib.h:3989
SSEClient & set_reconnect_interval(int ms)
Definition httplib.h:4005
SSEClient & on_message(MessageHandler handler)
Definition httplib.h:3984
SSEClient & set_max_reconnect_attempts(int n)
Definition httplib.h:4010
SSEClient(const SSEClient &)=delete
SSEClient & on_open(OpenHandler handler)
Definition httplib.h:3995
SSEClient & operator=(const SSEClient &)=delete
~SSEClient()
Definition httplib.h:3982
SSEClient & set_headers(const Headers &headers)
Definition httplib.h:4015
void stop()
Definition httplib.h:4037
std::function< void(Error)> ErrorHandler
Definition httplib.h:3648
SSEClient & on_error(ErrorHandler handler)
Definition httplib.h:4000
SSEClient(Client &client, const std::string &path)
Definition httplib.h:3975
std::function< void(const SSEMessage &)> MessageHandler
Definition httplib.h:3647
std::function< void()> OpenHandler
Definition httplib.h:3649
void start()
Definition httplib.h:4027
Definition httplib.h:3351
Result & operator=(const Result &)=delete
Result & operator=(Result &&other) noexcept
Definition httplib.h:3896
const char * data() const
Definition httplib.h:3950
Result()
Definition httplib.h:3883
size_t size() const
Definition httplib.h:3951
Error error() const
Definition httplib.h:3930
bool has_read_error() const
Definition httplib.h:3932
bool is_valid() const
Definition httplib.h:3909
const Headers & headers() const
Definition httplib.h:3916
int status() const
Definition httplib.h:3912
std::string get_header_value(const std::string &key, const char *def="") const
Definition httplib.h:3921
bool has_header(const std::string &key) const
Definition httplib.h:3926
std::string read_all()
Definition httplib.h:3953
bool next()
Definition httplib.h:3934
Error read_error() const
Definition httplib.h:3931
Result(const Result &)=delete
bool send(const std::string &data)
Definition httplib.h:20241
WebSocketClient(const std::string &scheme_host_port_path, const Headers &headers={})
Definition httplib.h:20109
bool connect()
Definition httplib.h:20201
WebSocketClient & operator=(const WebSocketClient &)=delete
ReadResult read(std::string &msg)
Definition httplib.h:20236
void set_address_family(int family)
Definition httplib.h:20278
~WebSocketClient()
Definition httplib.h:20152
void set_read_timeout(time_t sec, time_t usec=0)
Definition httplib.h:20262
void close(CloseStatus status=CloseStatus::Normal, const std::string &reason="")
Definition httplib.h:20251
void set_ipv6_v6only(bool on)
Definition httplib.h:20282
WebSocketClient(const WebSocketClient &)=delete
void set_connection_timeout(time_t sec, time_t usec=0)
Definition httplib.h:20288
bool is_valid() const
Definition httplib.h:20154
const std::string & subprotocol() const
Definition httplib.h:20258
void set_socket_options(SocketOptions socket_options)
Definition httplib.h:20284
void set_websocket_ping_interval(time_t sec)
Definition httplib.h:20272
void set_write_timeout(time_t sec, time_t usec=0)
Definition httplib.h:20267
void set_tcp_nodelay(bool on)
Definition httplib.h:20276
bool is_open() const
Definition httplib.h:20256
void set_interface(const std::string &intf)
Definition httplib.h:20293
Definition httplib.h:3743
bool send(const std::string &data)
Definition httplib.h:20042
const Request & request() const
Definition httplib.h:20104
void close(CloseStatus status=CloseStatus::Normal, const std::string &reason="")
Definition httplib.h:20050
bool is_open() const
Definition httplib.h:20106
ReadResult read(std::string &msg)
Definition httplib.h:19953
friend class WebSocketClient
Definition httplib.h:3759
WebSocket(const WebSocket &)=delete
~WebSocket()
Definition httplib.h:20078
WebSocket & operator=(const WebSocket &)=delete
#define CPPHTTPLIB_VERSION
Definition httplib.h:11
#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT
Definition httplib.h:126
#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH
Definition httplib.h:130
#define CPPHTTPLIB_HEADER_MAX_COUNT
Definition httplib.h:118
#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND
Definition httplib.h:46
#define INVALID_SOCKET
Definition httplib.h:296
#define CPPHTTPLIB_SEND_FLAGS
Definition httplib.h:181
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND
Definition httplib.h:30
#define CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND
Definition httplib.h:197
#define CPPHTTPLIB_SEND_BUFSIZ
Definition httplib.h:154
#define CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH
Definition httplib.h:193
#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND
Definition httplib.h:50
#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND
Definition httplib.h:54
#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND
Definition httplib.h:74
#define CPPHTTPLIB_LISTEN_BACKLOG
Definition httplib.h:185
#define CPPHTTPLIB_IDLE_INTERVAL_SECOND
Definition httplib.h:98
#define CPPHTTPLIB_EXPECT_100_THRESHOLD
Definition httplib.h:82
#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT
Definition httplib.h:34
#define CPPHTTPLIB_RANGE_MAX_COUNT
Definition httplib.h:138
#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH
Definition httplib.h:134
#define CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_THRESHOLD
Definition httplib.h:90
#define CPPHTTPLIB_THREAD_POOL_IDLE_TIMEOUT
Definition httplib.h:173
#define CPPHTTPLIB_IDLE_INTERVAL_USECOND
Definition httplib.h:105
#define CPPHTTPLIB_IPV6_V6ONLY
Definition httplib.h:146
#define CPPHTTPLIB_RECV_FLAGS
Definition httplib.h:177
#define CPPHTTPLIB_THREAD_POOL_MAX_COUNT
Definition httplib.h:169
#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND
Definition httplib.h:62
int socket_t
Definition httplib.h:294
#define CPPHTTPLIB_HEADER_MAX_LENGTH
Definition httplib.h:114
#define CPPHTTPLIB_EXPECT_100_TIMEOUT_MSECOND
Definition httplib.h:86
#define CPPHTTPLIB_COMPRESSION_BUFSIZ
Definition httplib.h:158
#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND
Definition httplib.h:26
#define CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND
Definition httplib.h:205
#define CPPHTTPLIB_THREAD_POOL_COUNT
Definition httplib.h:162
#define CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND
Definition httplib.h:78
#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND
Definition httplib.h:58
#define CPPHTTPLIB_RECV_BUFSIZ
Definition httplib.h:150
#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH
Definition httplib.h:110
#define CPPHTTPLIB_REDIRECT_MAX_COUNT
Definition httplib.h:122
#define CPPHTTPLIB_MAX_LINE_LENGTH
Definition httplib.h:189
#define CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND
Definition httplib.h:201
#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND
Definition httplib.h:66
#define CPPHTTPLIB_TCP_NODELAY
Definition httplib.h:142
#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND
Definition httplib.h:70
#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND
Definition httplib.h:38
#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND
Definition httplib.h:42
#define CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_TIMEOUT_MSECOND
Definition httplib.h:94
std::unordered_set< T, detail::case_ignore::hash, detail::case_ignore::equal_to > unordered_set
Definition httplib.h:596
bool equal(const std::string &a, const std::string &b)
Definition httplib.h:566
unsigned char to_lower(int c)
Definition httplib.h:534
Definition httplib.h:3268
bool is_obs_text(char c)
Definition httplib.h:8606
bool is_vchar(char c)
Definition httplib.h:8604
bool is_field_value(const std::string &s)
Definition httplib.h:8635
bool is_token(const std::string &s)
Definition httplib.h:8594
bool is_token_char(char c)
Definition httplib.h:8588
bool is_field_name(const std::string &s)
Definition httplib.h:8602
bool is_field_content(const std::string &s)
Definition httplib.h:8610
bool is_field_vchar(char c)
Definition httplib.h:8608
Definition httplib.h:6400
size_t to_utf8(int code, char *buff)
Definition httplib.h:4483
void divide(const char *data, std::size_t size, char d, std::function< void(const char *, std::size_t, const char *, std::size_t)> fn)
Definition httplib.h:5164
std::string make_host_and_port_string_always_port(const std::string &host, int port)
Definition httplib.h:10419
std::string trim_double_quotes_copy(const std::string &s)
Definition httplib.h:5156
ssize_t send_socket(socket_t sock, const void *ptr, size_t size, int flags)
Definition httplib.h:5473
std::string sha1(const std::string &input)
Definition httplib.h:4595
std::string make_host_and_port_string(const std::string &host, int port, bool is_ssl)
Definition httplib.h:10403
void get_remote_ip_and_port(socket_t sock, std::string &ip, int &port)
Definition httplib.h:6356
bool parse_www_authenticate(const Response &res, std::map< std::string, std::string > &auth, bool is_proxy)
Definition httplib.h:8537
bool parse_quality(const char *b, const char *e, std::string &token, double &quality)
Definition httplib.h:6534
std::string serialize_multipart_formdata_get_content_type(const std::string &boundary)
Definition httplib.h:8184
bool is_socket_alive(socket_t sock)
Definition httplib.h:5540
void coalesce_ranges(Ranges &ranges, size_t content_length)
Definition httplib.h:8270
bool has_header(const Headers &headers, const std::string &key)
Definition httplib.h:6952
size_t get_multipart_content_length(const UploadFormDataItems &items, const std::string &boundary)
Definition httplib.h:8203
int poll_wrapper(struct pollfd *fds, nfds_t nfds, int timeout)
Definition httplib.h:5486
EncodingType
Definition httplib.h:3062
@ Zstd
Definition httplib.h:3062
@ Gzip
Definition httplib.h:3062
@ Brotli
Definition httplib.h:3062
@ None
Definition httplib.h:3062
std::string compute_etag(const FileStat &fs)
Definition httplib.h:4397
size_t get_header_value_u64(const Headers &headers, const std::string &key, size_t def, size_t id, bool &is_invalid_value)
Definition httplib.h:2821
time_t parse_http_date(const std::string &date_str)
Definition httplib.h:4435
void split(const char *b, const char *e, char d, std::function< void(const char *, const char *)> fn)
Definition httplib.h:5184
bool write_websocket_frame(Stream &strm, ws::Opcode opcode, const char *data, size_t len, bool fin, bool mask)
Definition httplib.h:4724
std::string normalize_query_string(const std::string &query)
Definition httplib.h:7633
const void * any_type_id
Definition httplib.h:831
ReadContentResult read_content_with_length(Stream &strm, size_t len, DownloadProgress progress, ContentReceiverWithProgress out, size_t payload_max_length=(std::numeric_limits< size_t >::max)())
Definition httplib.h:7078
bool read_content(Stream &strm, T &x, size_t payload_max_length, int &status, DownloadProgress progress, ContentReceiverWithProgress receiver, bool decompress)
Definition httplib.h:7237
std::pair< std::unique_ptr< compressor >, const char * > create_compressor()
Definition httplib.h:6928
std::unique_ptr< decompressor > create_decompressor(const std::string &encoding)
Definition httplib.h:6905
std::string trim_copy(const std::string &s)
Definition httplib.h:5151
std::string base64_encode(const std::string &in)
Definition httplib.h:4567
std::string file_mtime_to_http_date(time_t mtime)
Definition httplib.h:4417
bool perform_websocket_handshake(Stream &strm, const std::string &host, int port, const std::string &path, const Headers &headers, std::string &selected_subprotocol)
Definition httplib.h:8639
std::string serialize_multipart_formdata_item_end()
Definition httplib.h:8176
bool is_hex(char c, int &v)
Definition httplib.h:4356
bool write_content_without_length(Stream &strm, const ContentProvider &content_provider, const T &is_shutting_down)
Definition httplib.h:7417
std::string if2ip(int address_family, const std::string &ifn)
Definition httplib.h:6228
std::string extract_media_type(const std::string &content_type, std::map< std::string, std::string > *params=nullptr)
Definition httplib.h:6475
bool is_space_or_tab(char c)
Definition httplib.h:4995
ssize_t write_response_line(Stream &strm, int status)
Definition httplib.h:7305
ssize_t read_body_content(Stream *stream, BodyReader &br, char *buf, size_t len)
Definition httplib.h:1961
bool redirect(T &cli, Request &req, Response &res, const std::string &path, const std::string &location, Error &error)
Definition httplib.h:7564
bool parse_trailers(stream_line_reader &line_reader, Headers &dest, const Headers &src_headers)
Definition httplib.h:5047
std::enable_if<!std::is_array< T >::value, std::unique_ptr< T > >::type make_unique(Args &&...args)
Definition httplib.h:521
bool is_weak_etag(const std::string &s)
Definition httplib.h:4472
ssize_t select_impl(socket_t sock, short events, time_t sec, time_t usec)
Definition httplib.h:5494
bool from_hex_to_i(const std::string &s, size_t i, size_t cnt, int &val)
Definition httplib.h:4370
void parse_query_text(const char *data, std::size_t size, Params ¶ms)
Definition httplib.h:7602
bool process_client_socket(socket_t sock, time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, time_t write_timeout_usec, time_t max_timeout_msec, std::chrono::time_point< std::chrono::steady_clock > start_time, std::function< bool(Stream &)> callback)
Definition httplib.h:5655
void set_nonblocking(socket_t sock, bool nonblocking)
Definition httplib.h:6177
socket_t create_socket(const std::string &host, const std::string &ip, int port, int address_family, int socket_flags, bool tcp_nodelay, bool ipv6_v6only, SocketOptions socket_options, BindOrConnect bind_or_connect, time_t timeout_sec=0)
Definition httplib.h:6033
int shutdown_socket(socket_t sock)
Definition httplib.h:5667
bool keep_alive(const std::atomic< socket_t > &svr_sock, socket_t sock, time_t keep_alive_timeout_sec)
Definition httplib.h:5588
std::string serialize_multipart_formdata_item_begin(const T &item, const std::string &boundary)
Definition httplib.h:8160
bool set_socket_opt_impl(socket_t sock, int level, int optname, const void *optval, socklen_t optlen)
Definition httplib.h:4329
bool is_strong_etag(const std::string &s)
Definition httplib.h:4477
std::pair< size_t, size_t > get_range_offset_and_length(Range r, size_t content_length)
Definition httplib.h:8395
bool write_content_with_progress(Stream &strm, const ContentProvider &content_provider, size_t offset, size_t length, T is_shutting_down, const UploadProgress &upload_progress, Error &error)
Definition httplib.h:7344
std::string file_extension(const std::string &path)
Definition httplib.h:4988
void parse_disposition_params(const std::string &s, Params ¶ms)
Definition httplib.h:7671
unsigned int str2tag(const std::string &s)
Definition httplib.h:6396
bool read_websocket_upgrade_response(Stream &strm, const std::string &expected_accept, std::string &selected_subprotocol)
Definition httplib.h:7032
bool split_find(const char *b, const char *e, char d, size_t m, std::function< bool(const char *, const char *)> fn)
Definition httplib.h:5211
void calc_actual_timeout(time_t max_timeout_msec, time_t duration_msec, time_t timeout_sec, time_t timeout_usec, time_t &actual_timeout_sec, time_t &actual_timeout_usec)
Definition httplib.h:10108
bool expect_content(const Request &req)
Definition httplib.h:8506
ssize_t handle_EINTR(T fn)
Definition httplib.h:5448
ssize_t select_write(socket_t sock, time_t sec, time_t usec)
Definition httplib.h:5510
bool get_ip_and_port(const struct sockaddr_storage &addr, socklen_t addr_len, std::string &ip, int &port)
Definition httplib.h:6325
void make_multipart_ranges_data(const Request &req, Response &res, const std::string &boundary, const std::string &content_type, size_t content_length, std::string &data)
Definition httplib.h:8456
constexpr size_t str_len(const char(&)[N])
Definition httplib.h:2811
bool is_valid_path(const std::string &path)
Definition httplib.h:4866
std::string websocket_accept_key(const std::string &client_key)
Definition httplib.h:4685
bool set_socket_opt(socket_t sock, int level, int optname, int optval)
Definition httplib.h:4340
bool parse_header(const char *beg, const char *end, T fn)
Definition httplib.h:5001
std::string random_string(size_t length)
Definition httplib.h:8121
bool process_multipart_ranges_data(const Request &req, const std::string &boundary, const std::string &content_type, size_t content_length, SToken stoken, CToken ctoken, Content content)
Definition httplib.h:8420
std::pair< size_t, size_t > trim(const char *b, const char *e, size_t left, size_t right)
Definition httplib.h:5140
bool range_error(Request &req, Response &res)
Definition httplib.h:8326
EncodingType encoding_type(const Request &req, const Response &res)
Definition httplib.h:6587
bool bind_ip_address(socket_t sock, const std::string &host)
Definition httplib.h:6196
bool parse_multipart_boundary(const std::string &content_type, std::string &boundary)
Definition httplib.h:7661
ssize_t read_socket(socket_t sock, void *ptr, size_t size, int flags)
Definition httplib.h:5461
bool parse_port(const char *s, size_t len, int &port)
Definition httplib.h:692
std::string serialize_multipart_formdata_finish(const std::string &boundary)
Definition httplib.h:8179
std::string params_to_query_str(const Params ¶ms)
Definition httplib.h:7590
int close_socket(socket_t sock)
Definition httplib.h:5440
ReadContentResult read_content_without_length(Stream &strm, size_t payload_max_length, ContentReceiverWithProgress out)
Definition httplib.h:7120
bool prepare_content_receiver(T &x, int &status, ContentReceiverWithProgress receiver, bool decompress, size_t payload_max_length, bool &exceed_payload_max_length, U callback)
Definition httplib.h:7185
ssize_t write_headers(Stream &strm, const Headers &headers)
Definition httplib.h:7314
bool is_chunked_transfer_encoding(const Headers &headers)
Definition httplib.h:7179
bool can_compress_content_type(const std::string &content_type)
Definition httplib.h:6509
std::string from_i_to_hex(size_t n)
Definition httplib.h:4387
bool write_content(Stream &strm, const ContentProvider &content_provider, size_t offset, size_t length, T is_shutting_down, Error &error)
Definition httplib.h:7399
bool is_path_within_base(const std::string &resolved_path, const std::string &resolved_base)
Definition httplib.h:4921
bool parse_accept_header(const std::string &s, std::vector< std::string > &content_types)
Definition httplib.h:7756
socket_t create_client_socket(const std::string &host, const std::string &ip, int port, int address_family, bool tcp_nodelay, bool ipv6_v6only, SocketOptions socket_options, time_t connection_timeout_sec, time_t connection_timeout_usec, time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, time_t write_timeout_usec, const std::string &intf, Error &error)
Definition httplib.h:6265
bool is_websocket_upgrade(const Request &req)
Definition httplib.h:4690
bool parse_range_header(const std::string &s, Ranges &ranges)
Definition httplib.h:7698
from_chars_result< T > from_chars(const char *first, const char *last, T &value, int base=10)
Definition httplib.h:637
bool write_multipart_ranges_data(Stream &strm, const Request &req, Response &res, const std::string &boundary, const std::string &content_type, size_t content_length, const T &is_shutting_down)
Definition httplib.h:8492
void duration_to_sec_and_usec(const T &duration, U callback)
Definition httplib.h:2803
const char * get_header_value(const Headers &headers, const std::string &key, const char *def, size_t id)
Definition httplib.h:6957
std::string find_content_type(const std::string &path, const std::map< std::string, std::string > &user_data, const std::string &default_content_type)
Definition httplib.h:6409
any_type_id any_typeid() noexcept
Definition httplib.h:836
bool canonicalize_path(const char *path, std::string &resolved)
Definition httplib.h:4908
ssize_t select_read(socket_t sock, time_t sec, time_t usec)
Definition httplib.h:5506
std::string serialize_multipart_formdata(const UploadFormDataItems &items, const std::string &boundary, bool finish=true)
Definition httplib.h:8189
bool set_socket_opt_time(socket_t sock, int level, int optname, time_t sec, time_t usec)
Definition httplib.h:4344
std::string make_multipart_data_boundary()
Definition httplib.h:8142
void get_local_ip_and_port(socket_t sock, std::string &ip, int &port)
Definition httplib.h:6347
ReadContentResult read_content_chunked(Stream &strm, T &x, size_t payload_max_length, ContentReceiverWithProgress out)
Definition httplib.h:7145
bool is_multipart_boundary_chars_valid(const std::string &boundary)
Definition httplib.h:8146
size_t get_multipart_ranges_data_length(const Request &req, const std::string &boundary, const std::string &content_type, size_t content_length)
Definition httplib.h:8472
ContentProvider make_multipart_content_provider(const UploadFormDataItems &items, const std::string &boundary)
Definition httplib.h:8223
ssize_t write_request_line(Stream &strm, const std::string &method, const std::string &path)
Definition httplib.h:7296
std::string make_content_range_header_field(const std::pair< size_t, size_t > &offset_and_length, size_t content_length)
Definition httplib.h:8405
std::string escape_abstract_namespace_unix_domain(const std::string &s)
Definition httplib.h:5675
bool read_headers(Stream &strm, Headers &headers)
Definition httplib.h:6976
std::string unescape_abstract_namespace_unix_domain(const std::string &s)
Definition httplib.h:5685
bool is_connection_error()
Definition httplib.h:6188
bool write_data(Stream &strm, const char *d, size_t l)
Definition httplib.h:7333
bool check_and_write_headers(Stream &strm, Headers &headers, T header_writer, Error &error)
Definition httplib.h:10424
Error wait_until_socket_is_ready(socket_t sock, time_t sec, time_t usec)
Definition httplib.h:5514
bool write_content_chunked(Stream &strm, const ContentProvider &content_provider, const T &is_shutting_down, U &compressor, Error &error)
Definition httplib.h:7452
ReadContentResult
Definition httplib.h:7072
@ PayloadTooLarge
Definition httplib.h:7074
@ Success
Definition httplib.h:7073
@ Error
Definition httplib.h:7075
bool is_prohibited_header_name(const std::string &name)
Definition httplib.h:6940
bool process_server_socket(const std::atomic< socket_t > &svr_sock, socket_t sock, size_t keep_alive_max_count, time_t keep_alive_timeout_sec, time_t read_timeout_sec, time_t read_timeout_usec, time_t write_timeout_sec, time_t write_timeout_usec, T callback)
Definition httplib.h:5641
std::string prepare_host_string(const std::string &host)
Definition httplib.h:10391
bool is_numeric(const std::string &str)
Definition httplib.h:2815
int getaddrinfo_with_timeout(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res, time_t timeout_sec)
Definition httplib.h:5694
constexpr unsigned int str2tag_core(const char *s, size_t l, unsigned int h)
Definition httplib.h:6384
std::string encode_path(const std::string &s)
Definition httplib.h:4956
bool process_server_socket_core(const std::atomic< socket_t > &svr_sock, socket_t sock, size_t keep_alive_max_count, time_t keep_alive_timeout_sec, T callback)
Definition httplib.h:5623
Definition httplib.h:3634
Definition httplib.h:3349
Result Options(ClientType &cli, const std::string &path, size_t chunk_size=8192)
Definition httplib.h:3608
Result Post(ClientType &cli, const std::string &path, const std::string &body, const std::string &content_type, size_t chunk_size=8192)
Definition httplib.h:3414
Result Delete(ClientType &cli, const std::string &path, size_t chunk_size=8192)
Definition httplib.h:3519
Result Put(ClientType &cli, const std::string &path, const std::string &body, const std::string &content_type, size_t chunk_size=8192)
Definition httplib.h:3449
Result Head(ClientType &cli, const std::string &path, size_t chunk_size=8192)
Definition httplib.h:3582
Result Get(ClientType &cli, const std::string &path, size_t chunk_size=8192)
Definition httplib.h:3388
Result Patch(ClientType &cli, const std::string &path, const std::string &body, const std::string &content_type, size_t chunk_size=8192)
Definition httplib.h:3484
Definition httplib.h:3863
bool is_valid_utf8(const std::string &s)
Definition httplib.h:4520
bool read_websocket_frame(Stream &strm, Opcode &opcode, std::string &payload, bool &fin, bool expect_masked, size_t max_len)
Definition httplib.h:4789
CloseStatus
Definition httplib.h:3727
@ Abnormal
Definition httplib.h:3733
@ MessageTooBig
Definition httplib.h:3736
@ NoStatus
Definition httplib.h:3732
@ InvalidPayload
Definition httplib.h:3734
@ InternalError
Definition httplib.h:3738
@ Normal
Definition httplib.h:3728
@ UnsupportedData
Definition httplib.h:3731
@ PolicyViolation
Definition httplib.h:3735
@ MandatoryExtension
Definition httplib.h:3737
@ GoingAway
Definition httplib.h:3729
@ ProtocolError
Definition httplib.h:3730
ReadResult
Definition httplib.h:3741
@ Binary
Definition httplib.h:3741
@ Text
Definition httplib.h:3741
@ Fail
Definition httplib.h:3741
Opcode
Definition httplib.h:3718
@ Pong
Definition httplib.h:3724
@ Binary
Definition httplib.h:3721
@ Text
Definition httplib.h:3720
@ Ping
Definition httplib.h:3723
@ Close
Definition httplib.h:3722
@ Continuation
Definition httplib.h:3719
std::function< bool(size_t offset, DataSink &sink)> ContentProviderWithoutLength
Definition httplib.h:1022
std::ostream & operator<<(std::ostream &os, const Error &obj)
Definition httplib.h:9276
FormDataProvider make_file_provider(const std::string &name, const std::string &filepath, const std::string &filename=std::string(), const std::string &content_type=std::string())
Definition httplib.h:1036
std::pair< std::string, std::string > make_range_header(const Ranges &ranges)
Definition httplib.h:9589
std::string encode_path_component(const std::string &component)
Definition httplib.h:9403
std::function< bool(const Response &response)> ResponseHandler
Definition httplib.h:942
std::function< bool( const char *data, size_t data_length, size_t offset, size_t total_length)> ContentReceiverWithProgress
Definition httplib.h:1092
std::function< void(socket_t sock)> SocketOptions
Definition httplib.h:1478
std::string get_client_ip(const std::string &x_forwarded_for, const std::vector< std::string > &trusted_proxies)
Definition httplib.h:11837
std::function< bool(const FormData &file)> FormDataHeader
Definition httplib.h:1098
std::string hosted_at(const std::string &hostname)
Definition httplib.h:9282
std::string decode_uri_component(const std::string &value)
Definition httplib.h:9363
std::function< void(const Request &, const Response &)> Logger
Definition httplib.h:1472
std::vector< UploadFormData > UploadFormDataItems
Definition httplib.h:984
Error
Definition httplib.h:1355
@ Canceled
Definition httplib.h:1363
@ ConnectionTimeout
Definition httplib.h:1370
@ Write
Definition httplib.h:1361
@ ExceedUriMaxLength
Definition httplib.h:1377
@ TooManyFormDataFiles
Definition httplib.h:1375
@ SSLServerVerification
Definition httplib.h:1366
@ ConnectionClosed
Definition httplib.h:1372
@ SSLServerHostnameVerification
Definition httplib.h:1367
@ ExceedMaxSocketDescriptorCount
Definition httplib.h:1378
@ InvalidHTTPMethod
Definition httplib.h:1380
@ OpenFile
Definition httplib.h:1384
@ ResourceExhaustion
Definition httplib.h:1374
@ Success
Definition httplib.h:1356
@ BindIPAddress
Definition httplib.h:1359
@ Read
Definition httplib.h:1360
@ InvalidRequestLine
Definition httplib.h:1379
@ Compression
Definition httplib.h:1369
@ GetSockName
Definition httplib.h:1386
@ Unknown
Definition httplib.h:1357
@ InvalidHeaders
Definition httplib.h:1382
@ SSLConnection
Definition httplib.h:1364
@ UnsupportedAddressFamily
Definition httplib.h:1387
@ ProxyConnection
Definition httplib.h:1371
@ InvalidRangeHeader
Definition httplib.h:1389
@ ExceedMaxPayloadSize
Definition httplib.h:1376
@ MultipartParsing
Definition httplib.h:1383
@ Connection
Definition httplib.h:1358
@ Timeout
Definition httplib.h:1373
@ Listen
Definition httplib.h:1385
@ HTTPParsing
Definition httplib.h:1388
@ ExceedRedirectCount
Definition httplib.h:1362
@ InvalidHTTPVersion
Definition httplib.h:1381
@ SSLLoadingCerts
Definition httplib.h:1365
@ UnsupportedMultipartBoundaryChars
Definition httplib.h:1368
@ SSLPeerCouldBeClosed_
Definition httplib.h:1392
std::string to_string(Error error)
Definition httplib.h:9231
std::pair< size_t, ContentProvider > make_file_body(const std::string &filepath)
Definition httplib.h:1064
T * any_cast(any *a) noexcept
Definition httplib.h:891
std::string encode_uri_component(const std::string &value)
Definition httplib.h:9320
std::pair< std::string, std::string > make_basic_authentication_header(const std::string &username, const std::string &password, bool is_proxy=false)
Definition httplib.h:9603
std::function< bool(const char *data, size_t data_length)> ContentReceiver
Definition httplib.h:1095
std::function< bool(size_t offset, size_t length, DataSink &sink)> ContentProvider
Definition httplib.h:1019
std::string sanitize_filename(const std::string &filename)
Definition httplib.h:9554
const char * status_message(int status)
Definition httplib.h:9155
std::multimap< std::string, std::string > Params
Definition httplib.h:794
std::smatch Match
Definition httplib.h:795
SSLVerifierResponse
Definition httplib.h:706
@ CertificateAccepted
Definition httplib.h:710
@ CertificateRejected
Definition httplib.h:712
@ NoDecisionMade
Definition httplib.h:708
std::string get_bearer_token_auth(const Request &req)
Definition httplib.h:9146
std::pair< std::string, std::string > make_bearer_token_authentication_header(const std::string &token, bool is_proxy=false)
Definition httplib.h:9611
std::function< bool(size_t current, size_t total)> DownloadProgress
Definition httplib.h:797
std::unordered_multimap< std::string, std::string, detail::case_ignore::hash, detail::case_ignore::equal_to > Headers
Definition httplib.h:790
std::function< void(bool success)> ContentProviderResourceReleaser
Definition httplib.h:1025
std::vector< Range > Ranges
Definition httplib.h:1123
std::string decode_path_component(const std::string &component)
Definition httplib.h:9438
std::string decode_uri(const std::string &value)
Definition httplib.h:9383
std::string encode_query_component(const std::string &component, bool space_as_plus=true)
Definition httplib.h:9475
std::vector< FormDataProvider > FormDataProviderItems
Definition httplib.h:1033
std::multimap< std::string, FormField > FormFields
Definition httplib.h:957
std::function< void(const Error &, const Request *)> ErrorLogger
Definition httplib.h:1476
std::string decode_query_component(const std::string &component, bool plus_as_space=true)
Definition httplib.h:9529
StatusCode
Definition httplib.h:715
@ Conflict_409
Definition httplib.h:755
@ IMUsed_226
Definition httplib.h:732
@ SwitchingProtocol_101
Definition httplib.h:718
@ MisdirectedRequest_421
Definition httplib.h:765
@ FailedDependency_424
Definition httplib.h:768
@ Found_302
Definition httplib.h:737
@ MultipleChoices_300
Definition httplib.h:735
@ UnavailableForLegalReasons_451
Definition httplib.h:774
@ LoopDetected_508
Definition httplib.h:785
@ ServiceUnavailable_503
Definition httplib.h:780
@ EarlyHints_103
Definition httplib.h:720
@ ProxyAuthenticationRequired_407
Definition httplib.h:753
@ Processing_102
Definition httplib.h:719
@ Locked_423
Definition httplib.h:767
@ PaymentRequired_402
Definition httplib.h:748
@ NonAuthoritativeInformation_203
Definition httplib.h:726
@ UriTooLong_414
Definition httplib.h:760
@ Accepted_202
Definition httplib.h:725
@ ResetContent_205
Definition httplib.h:728
@ Forbidden_403
Definition httplib.h:749
@ Gone_410
Definition httplib.h:756
@ UnsupportedMediaType_415
Definition httplib.h:761
@ NotExtended_510
Definition httplib.h:786
@ NotModified_304
Definition httplib.h:739
@ VariantAlsoNegotiates_506
Definition httplib.h:783
@ unused_306
Definition httplib.h:741
@ TooManyRequests_429
Definition httplib.h:772
@ RequestTimeout_408
Definition httplib.h:754
@ OK_200
Definition httplib.h:723
@ NetworkAuthenticationRequired_511
Definition httplib.h:787
@ AlreadyReported_208
Definition httplib.h:731
@ MultiStatus_207
Definition httplib.h:730
@ ImATeapot_418
Definition httplib.h:764
@ NotAcceptable_406
Definition httplib.h:752
@ InternalServerError_500
Definition httplib.h:777
@ ExpectationFailed_417
Definition httplib.h:763
@ MethodNotAllowed_405
Definition httplib.h:751
@ NotFound_404
Definition httplib.h:750
@ TemporaryRedirect_307
Definition httplib.h:742
@ PermanentRedirect_308
Definition httplib.h:743
@ SeeOther_303
Definition httplib.h:738
@ Unauthorized_401
Definition httplib.h:747
@ PreconditionFailed_412
Definition httplib.h:758
@ Created_201
Definition httplib.h:724
@ NotImplemented_501
Definition httplib.h:778
@ UseProxy_305
Definition httplib.h:740
@ NoContent_204
Definition httplib.h:727
@ InsufficientStorage_507
Definition httplib.h:784
@ TooEarly_425
Definition httplib.h:769
@ BadGateway_502
Definition httplib.h:779
@ MovedPermanently_301
Definition httplib.h:736
@ PreconditionRequired_428
Definition httplib.h:771
@ PartialContent_206
Definition httplib.h:729
@ LengthRequired_411
Definition httplib.h:757
@ PayloadTooLarge_413
Definition httplib.h:759
@ RangeNotSatisfiable_416
Definition httplib.h:762
@ UnprocessableContent_422
Definition httplib.h:766
@ RequestHeaderFieldsTooLarge_431
Definition httplib.h:773
@ Continue_100
Definition httplib.h:717
@ BadRequest_400
Definition httplib.h:746
@ UpgradeRequired_426
Definition httplib.h:770
@ GatewayTimeout_504
Definition httplib.h:781
@ HttpVersionNotSupported_505
Definition httplib.h:782
std::string encode_uri(const std::string &value)
Definition httplib.h:9341
std::function< bool(size_t current, size_t total)> UploadProgress
Definition httplib.h:798
void default_socket_options(socket_t sock)
Definition httplib.h:9136
std::string append_query_params(const std::string &path, const Params ¶ms)
Definition httplib.h:9578
std::pair< ssize_t, ssize_t > Range
Definition httplib.h:1122
std::multimap< std::string, FormData > FormFiles
Definition httplib.h:959
ClientConnection & operator=(ClientConnection &&other) noexcept
Definition httplib.h:1925
ClientConnection(ClientConnection &&other) noexcept
Definition httplib.h:1912
~ClientConnection()
Definition httplib.h:14657
ClientConnection & operator=(const ClientConnection &)=delete
ClientConnection()=default
socket_t sock
Definition httplib.h:1901
ClientConnection(const ClientConnection &)=delete
bool is_open() const
Definition httplib.h:1903
Definition httplib.h:2190
bool is_open() const
Definition httplib.h:2196
socket_t sock
Definition httplib.h:2191
std::chrono::time_point< std::chrono::steady_clock > start_time_
Definition httplib.h:2194
Definition httplib.h:1985
bool trailers_parsed_
Definition httplib.h:2005
friend class ClientImpl
Definition httplib.h:2008
bool has_read_error() const
Definition httplib.h:2003
Error error
Definition httplib.h:1987
StreamHandle & operator=(StreamHandle &&)=default
ssize_t read(char *buf, size_t len)
Definition httplib.h:12677
StreamHandle(const StreamHandle &)=delete
bool is_valid() const
Definition httplib.h:1996
StreamHandle & operator=(const StreamHandle &)=delete
Error get_read_error() const
Definition httplib.h:2002
StreamHandle(StreamHandle &&)=default
void parse_trailers_if_needed()
Definition httplib.h:12750
std::unique_ptr< Response > response
Definition httplib.h:1986
Definition httplib.h:1224
MultipartFormData form
Definition httplib.h:1241
bool has_param(const std::string &key) const
Definition httplib.h:9664
bool has_header(const std::string &key) const
Definition httplib.h:9624
DownloadProgress download_progress
Definition httplib.h:1251
size_t get_param_value_count(const std::string &key) const
Definition httplib.h:9677
std::vector< std::string > accept_content_types
Definition httplib.h:1248
size_t get_trailer_value_count(const std::string &key) const
Definition httplib.h:9659
ContentReceiverWithProgress content_receiver
Definition httplib.h:1250
std::string local_addr
Definition httplib.h:1235
std::unordered_map< std::string, std::string > path_params
Definition httplib.h:1244
UploadProgress upload_progress
Definition httplib.h:1252
Headers trailers
Definition httplib.h:1230
std::string remote_addr
Definition httplib.h:1233
std::string get_header_value(const std::string &key, const char *def="", size_t id=0) const
Definition httplib.h:9628
int remote_port
Definition httplib.h:1234
Params params
Definition httplib.h:1228
std::string target
Definition httplib.h:1240
size_t get_header_value_u64(const std::string &key, size_t def=0, size_t id=0) const
Definition httplib.h:9619
std::string get_param_value(const std::string &key, size_t id=0) const
Definition httplib.h:9668
size_t authorization_count_
Definition httplib.h:1277
bool is_multipart_form_data() const
Definition httplib.h:9682
Match matches
Definition httplib.h:1243
std::string version
Definition httplib.h:1239
bool has_trailer(const std::string &key) const
Definition httplib.h:9646
std::chrono::time_point< std::chrono::steady_clock > start_time_
Definition httplib.h:1278
ContentProvider content_provider_
Definition httplib.h:1275
std::string get_trailer_value(const std::string &key, size_t id=0) const
Definition httplib.h:9650
size_t content_length_
Definition httplib.h:1274
Ranges ranges
Definition httplib.h:1242
std::string path
Definition httplib.h:1226
bool is_chunked_content_provider_
Definition httplib.h:1276
std::function< bool()> is_connection_closed
Definition httplib.h:1245
std::string body
Definition httplib.h:1231
size_t redirect_count_
Definition httplib.h:1273
std::string matched_route
Definition httplib.h:1227
size_t get_header_value_count(const std::string &key) const
Definition httplib.h:9633
ResponseHandler response_handler
Definition httplib.h:1249
int local_port
Definition httplib.h:1236
std::string method
Definition httplib.h:1225
void set_header(const std::string &key, const std::string &val)
Definition httplib.h:9638
Headers headers
Definition httplib.h:1229
Definition httplib.h:1288
ContentProvider content_provider_
Definition httplib.h:1347
bool is_chunked_content_provider_
Definition httplib.h:1349
Headers trailers
Definition httplib.h:1293
void set_redirect(const std::string &url, int status=StatusCode::Found_302)
Definition httplib.h:9790
Response & operator=(Response &&)=default
std::string file_content_path_
Definition httplib.h:1351
size_t get_header_value_u64(const std::string &key, size_t def=0, size_t id=0) const
Definition httplib.h:9745
size_t content_length_
Definition httplib.h:1346
void set_content_provider(size_t length, const std::string &content_type, ContentProvider provider, ContentProviderResourceReleaser resource_releaser=nullptr)
Definition httplib.h:9824
std::string version
Definition httplib.h:1289
Headers headers
Definition httplib.h:1292
void set_content(const char *s, size_t n, const std::string &content_type)
Definition httplib.h:9801
bool has_header(const std::string &key) const
Definition httplib.h:9750
bool content_provider_success_
Definition httplib.h:1350
ContentProviderResourceReleaser content_provider_resource_releaser_
Definition httplib.h:1348
std::string get_header_value(const std::string &key, const char *def="", size_t id=0) const
Definition httplib.h:9754
void set_chunked_content_provider(const std::string &content_type, ContentProviderWithoutLength provider, ContentProviderResourceReleaser resource_releaser=nullptr)
Definition httplib.h:9844
int status
Definition httplib.h:1290
std::string get_trailer_value(const std::string &key, size_t id=0) const
Definition httplib.h:9776
std::string reason
Definition httplib.h:1291
size_t get_trailer_value_count(const std::string &key) const
Definition httplib.h:9785
std::map< std::string, any > user_data
Definition httplib.h:1299
std::string body
Definition httplib.h:1294
void set_file_content(const std::string &path, const std::string &content_type)
Definition httplib.h:9854
bool has_trailer(const std::string &key) const
Definition httplib.h:9772
Response & operator=(const Response &)=default
Response(const Response &)=default
~Response()
Definition httplib.h:1339
std::string file_content_content_type_
Definition httplib.h:1352
Response(Response &&)=default
void set_header(const std::string &key, const std::string &val)
Definition httplib.h:9765
size_t get_header_value_count(const std::string &key) const
Definition httplib.h:9760
std::string location
Definition httplib.h:1295
Definition httplib.h:1946
size_t bytes_read
Definition httplib.h:1951
bool has_content_length
Definition httplib.h:1948
std::unique_ptr< ChunkedDecoder > chunked_decoder
Definition httplib.h:1954
bool has_error() const
Definition httplib.h:1958
size_t content_length
Definition httplib.h:1949
Stream * stream
Definition httplib.h:1947
bool chunked
Definition httplib.h:1952
size_t payload_max_length
Definition httplib.h:1950
ssize_t read(char *buf, size_t len)
Definition httplib.h:9897
Error last_error
Definition httplib.h:1955
bool eof
Definition httplib.h:1953
Definition httplib.h:3227
char line_buf[64]
Definition httplib.h:3231
ssize_t read_payload(char *buf, size_t len, size_t &out_chunk_offset, size_t &out_chunk_total)
Definition httplib.h:12773
size_t last_chunk_offset
Definition httplib.h:3233
size_t chunk_remaining
Definition httplib.h:3229
bool parse_trailers_into(Headers &dest, const Headers &src_headers)
Definition httplib.h:12820
bool finished
Definition httplib.h:3230
size_t last_chunk_total
Definition httplib.h:3232
Stream & strm
Definition httplib.h:3228
ChunkedDecoder(Stream &s)
Definition httplib.h:12771
Definition httplib.h:2985
time_t mtime() const
Definition httplib.h:4947
FileStat(const std::string &path)
Definition httplib.h:4932
size_t size() const
Definition httplib.h:4952
bool is_file() const
Definition httplib.h:4940
bool is_dir() const
Definition httplib.h:4943
Definition httplib.h:8215
size_t size
Definition httplib.h:8217
const char * data
Definition httplib.h:8216
virtual std::unique_ptr< any_storage > clone() const =0
virtual ~any_storage()=default
virtual any_type_id type_id() const noexcept=0
any_type_id type_id() const noexcept override
Definition httplib.h:853
any_value(U &&v)
Definition httplib.h:849
std::unique_ptr< any_storage > clone() const override
Definition httplib.h:850
T value
Definition httplib.h:848
bool operator()(const std::string &a, const std::string &b) const
Definition httplib.h:574
size_t operator()(const std::string &key) const
Definition httplib.h:580
size_t hash_core(const char *s, size_t l, size_t h) const
Definition httplib.h:584
std::errc ec
Definition httplib.h:633
const char * ptr
Definition httplib.h:632
scope_exit(std::function< void(void)> &&f)
Definition httplib.h:605
scope_exit(scope_exit &&rhs) noexcept
Definition httplib.h:608
void release()
Definition httplib.h:618
~scope_exit()
Definition httplib.h:614
Definition httplib.h:3636
std::string event
Definition httplib.h:3637
void clear()
Definition httplib.h:3968
SSEMessage()
Definition httplib.h:3966
std::string data
Definition httplib.h:3638
std::string id
Definition httplib.h:3639