Brunobkr/llama.cpp_AlgMor24_github
ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.
03.1k
1//2// httplib.h3//4// Copyright (c) 2026 Yuji Hirose. All rights reserved.5// MIT License6//7 8#ifndef CPPHTTPLIB_HTTPLIB_H9#define CPPHTTPLIB_HTTPLIB_H10 11#define CPPHTTPLIB_VERSION "0.53.0"12#define CPPHTTPLIB_VERSION_NUM "0x003500"13 14#ifdef _WIN3215#if defined(_WIN32_WINNT) && _WIN32_WINNT < 0x0A0016#error \17 "cpp-httplib doesn't support Windows 8 or lower. Please use Windows 10 or later."18#endif19#endif20 21/*22 * Configuration23 */24 25#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND26#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 527#endif28 29#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND30#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND 1000031#endif32 33#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT34#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 10035#endif36 37#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND38#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 30039#endif40 41#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND42#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 043#endif44 45#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND46#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND 547#endif48 49#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND50#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND 051#endif52 53#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND54#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND 555#endif56 57#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND58#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND 059#endif60 61#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND62#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND 30063#endif64 65#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND66#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND 067#endif68 69#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND70#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND 571#endif72 73#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND74#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND 075#endif76 77#ifndef CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND78#define CPPHTTPLIB_CLIENT_MAX_TIMEOUT_MSECOND 079#endif80 81#ifndef CPPHTTPLIB_EXPECT_100_THRESHOLD82#define CPPHTTPLIB_EXPECT_100_THRESHOLD 102483#endif84 85#ifndef CPPHTTPLIB_EXPECT_100_TIMEOUT_MSECOND86#define CPPHTTPLIB_EXPECT_100_TIMEOUT_MSECOND 100087#endif88 89#ifndef CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_THRESHOLD90#define CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_THRESHOLD (1024 * 1024)91#endif92 93#ifndef CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_TIMEOUT_MSECOND94#define CPPHTTPLIB_WAIT_EARLY_SERVER_RESPONSE_TIMEOUT_MSECOND 5095#endif96 97#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND98#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 099#endif100 101#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND102#ifdef _WIN32103#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 1000104#else105#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 0106#endif107#endif108 109#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH110#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 8192111#endif112 113#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH114#define CPPHTTPLIB_HEADER_MAX_LENGTH 8192115#endif116 117#ifndef CPPHTTPLIB_HEADER_MAX_COUNT118#define CPPHTTPLIB_HEADER_MAX_COUNT 100119#endif120 121#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT122#define CPPHTTPLIB_REDIRECT_MAX_COUNT 20123#endif124 125#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT126#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 1024127#endif128 129#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH130#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH (100 * 1024 * 1024) // 100MB131#endif132 133#ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH134#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192135#endif136 137#ifndef CPPHTTPLIB_RANGE_MAX_COUNT138#define CPPHTTPLIB_RANGE_MAX_COUNT 1024139#endif140 141#ifndef CPPHTTPLIB_TCP_NODELAY142#define CPPHTTPLIB_TCP_NODELAY false143#endif144 145#ifndef CPPHTTPLIB_IPV6_V6ONLY146#define CPPHTTPLIB_IPV6_V6ONLY false147#endif148 149#ifndef CPPHTTPLIB_RECV_BUFSIZ150#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)151#endif152 153#ifndef CPPHTTPLIB_SEND_BUFSIZ154#define CPPHTTPLIB_SEND_BUFSIZ size_t(16384u)155#endif156 157#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ158#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)159#endif160 161#ifndef CPPHTTPLIB_THREAD_POOL_COUNT162#define CPPHTTPLIB_THREAD_POOL_COUNT \163 ((std::max)(8u, std::thread::hardware_concurrency() > 0 \164 ? std::thread::hardware_concurrency() - 1 \165 : 0))166#endif167 168#ifndef CPPHTTPLIB_THREAD_POOL_MAX_COUNT169#define CPPHTTPLIB_THREAD_POOL_MAX_COUNT (CPPHTTPLIB_THREAD_POOL_COUNT * 4)170#endif171 172#ifndef CPPHTTPLIB_THREAD_POOL_IDLE_TIMEOUT173#define CPPHTTPLIB_THREAD_POOL_IDLE_TIMEOUT 3 // seconds174#endif175 176#ifndef CPPHTTPLIB_RECV_FLAGS177#define CPPHTTPLIB_RECV_FLAGS 0178#endif179 180#ifndef CPPHTTPLIB_SEND_FLAGS181#define CPPHTTPLIB_SEND_FLAGS 0182#endif183 184#ifndef CPPHTTPLIB_LISTEN_BACKLOG185#define CPPHTTPLIB_LISTEN_BACKLOG 128186#endif187 188#ifndef CPPHTTPLIB_MAX_LINE_LENGTH189#define CPPHTTPLIB_MAX_LINE_LENGTH 32768190#endif191 192#ifndef CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH193#define CPPHTTPLIB_WEBSOCKET_MAX_PAYLOAD_LENGTH 16777216194#endif195 196#ifndef CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND197#define CPPHTTPLIB_WEBSOCKET_READ_TIMEOUT_SECOND 300198#endif199 200#ifndef CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND201#define CPPHTTPLIB_WEBSOCKET_CLOSE_TIMEOUT_SECOND 5202#endif203 204#ifndef CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND205#define CPPHTTPLIB_WEBSOCKET_PING_INTERVAL_SECOND 30206#endif207 208#ifndef CPPHTTPLIB_WEBSOCKET_MAX_MISSED_PONGS209#define CPPHTTPLIB_WEBSOCKET_MAX_MISSED_PONGS 0210#endif211 212/*213 * Headers214 */215 216#ifdef _WIN32217#ifndef _CRT_SECURE_NO_WARNINGS218#define _CRT_SECURE_NO_WARNINGS219#endif //_CRT_SECURE_NO_WARNINGS220 221#ifndef _CRT_NONSTDC_NO_DEPRECATE222#define _CRT_NONSTDC_NO_DEPRECATE223#endif //_CRT_NONSTDC_NO_DEPRECATE224 225#if defined(_MSC_VER)226#if _MSC_VER < 1900227#error Sorry, Visual Studio versions prior to 2015 are not supported228#endif229 230#pragma comment(lib, "ws2_32.lib")231 232#ifndef _SSIZE_T_DEFINED233using ssize_t = __int64;234#define _SSIZE_T_DEFINED235#endif236#endif // _MSC_VER237 238#ifndef S_ISREG239#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)240#endif // S_ISREG241 242#ifndef S_ISDIR243#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)244#endif // S_ISDIR245 246#ifndef NOMINMAX247#define NOMINMAX248#endif // NOMINMAX249 250#include <io.h>251#include <winsock2.h>252#include <ws2tcpip.h>253 254#if defined(__has_include)255#if __has_include(<afunix.h>)256// afunix.h uses types declared in winsock2.h, so has to be included after it.257#include <afunix.h>258#define CPPHTTPLIB_HAVE_AFUNIX_H 1259#endif260#endif261 262#ifndef WSA_FLAG_NO_HANDLE_INHERIT263#define WSA_FLAG_NO_HANDLE_INHERIT 0x80264#endif265 266using nfds_t = unsigned long;267using socket_t = SOCKET;268using socklen_t = int;269 270#else // not _WIN32271 272#include <arpa/inet.h>273#if !defined(_AIX) && !defined(__MVS__)274#include <ifaddrs.h>275#endif276#ifdef __MVS__277#include <strings.h>278#ifndef NI_MAXHOST279#define NI_MAXHOST 1025280#endif281#endif282#include <net/if.h>283#include <netdb.h>284#include <netinet/in.h>285#ifdef __linux__286#include <resolv.h>287#undef _res // Undefine _res macro to avoid conflicts with user code (#2278)288#endif289#include <csignal>290#include <netinet/tcp.h>291#include <poll.h>292#include <pthread.h>293#include <sys/mman.h>294#include <sys/socket.h>295#include <sys/un.h>296#include <unistd.h>297 298using socket_t = int;299#ifndef INVALID_SOCKET300#define INVALID_SOCKET (-1)301#endif302#endif //_WIN32303 304#if defined(__APPLE__)305#include <TargetConditionals.h>306#endif307 308#include <algorithm>309#include <array>310#include <atomic>311#include <cassert>312#include <chrono>313#include <climits>314#include <condition_variable>315#include <cstdlib>316#include <cstring>317#include <errno.h>318#include <exception>319#include <fcntl.h>320#include <fstream>321#include <functional>322#include <iomanip>323#include <iostream>324#include <iterator>325#include <list>326#include <map>327#include <memory>328#include <mutex>329#include <random>330#include <regex>331#include <set>332#include <sstream>333#include <string>334#include <sys/stat.h>335#include <system_error>336#include <thread>337#include <type_traits>338#include <unordered_map>339#include <unordered_set>340#include <utility>341#include <vector>342 343// On macOS with a TLS backend, enable Keychain root certificates by default344// unless the user explicitly opts out. Not enabled on iOS/tvOS/watchOS since345// the SecTrustSettings APIs used to enumerate anchor certificates are macOS346// only; on those platforms the user must provide a CA bundle explicitly.347#if defined(__APPLE__) && defined(__clang__) && \348 !defined(CPPHTTPLIB_DISABLE_MACOSX_AUTOMATIC_ROOT_CERTIFICATES) && \349 (defined(CPPHTTPLIB_OPENSSL_SUPPORT) || \350 defined(CPPHTTPLIB_MBEDTLS_SUPPORT) || \351 defined(CPPHTTPLIB_WOLFSSL_SUPPORT))352#if TARGET_OS_OSX353#ifndef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN354#define CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN355#endif356#endif357#endif358 359#if defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && \360 defined(__APPLE__) && !TARGET_OS_OSX361#error \362 "CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN is only supported on macOS. On iOS/tvOS/watchOS, supply a CA bundle via set_ca_cert_path()."363#endif364 365// On Windows, enable Schannel certificate verification by default366// unless the user explicitly opts out.367#if defined(_WIN32) && \368 !defined(CPPHTTPLIB_DISABLE_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE)369#define CPPHTTPLIB_WINDOWS_AUTOMATIC_ROOT_CERTIFICATES_UPDATE370#endif371 372#if defined(CPPHTTPLIB_USE_NON_BLOCKING_GETADDRINFO) || \373 defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN)374#if TARGET_OS_MAC && defined(__clang__)375#include <CFNetwork/CFHost.h>376#include <CoreFoundation/CoreFoundation.h>377#endif378#endif379 380#ifdef CPPHTTPLIB_OPENSSL_SUPPORT381#ifdef _WIN32382#include <wincrypt.h>383 384// these are defined in wincrypt.h and it breaks compilation if BoringSSL is385// used386#undef X509_NAME387#undef X509_CERT_PAIR388#undef X509_EXTENSIONS389#undef PKCS7_SIGNER_INFO390 391#ifdef _MSC_VER392#pragma comment(lib, "crypt32.lib")393#endif394#endif // _WIN32395 396#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN397#if TARGET_OS_OSX398#include <Security/Security.h>399#endif400#endif401 402#include <openssl/err.h>403#include <openssl/evp.h>404#include <openssl/ssl.h>405#include <openssl/x509v3.h>406 407#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)408#include <openssl/applink.c>409#endif410 411#include <iostream>412#include <sstream>413 414#if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER)415#if OPENSSL_VERSION_NUMBER < 0x1010107f416#error Please use OpenSSL or a current version of BoringSSL417#endif418#define SSL_get1_peer_certificate SSL_get_peer_certificate419#elif OPENSSL_VERSION_NUMBER < 0x30000000L420#error Sorry, OpenSSL versions prior to 3.0.0 are not supported421#endif422 423#endif // CPPHTTPLIB_OPENSSL_SUPPORT424 425#ifdef CPPHTTPLIB_MBEDTLS_SUPPORT426// version.h defines MBEDTLS_VERSION_MAJOR (on 2.x/3.x/4.x alike); it is pulled427// in with this first include group so the version gating below can use it.428#include <mbedtls/error.h>429#include <mbedtls/net_sockets.h>430#include <mbedtls/oid.h>431#include <mbedtls/pk.h>432#include <mbedtls/ssl.h>433#include <mbedtls/version.h>434#include <mbedtls/x509_crt.h>435#if MBEDTLS_VERSION_MAJOR >= 4436// Mbed TLS 4.x moved hashing/RNG to PSA Crypto and removed these headers.437#include <psa/crypto.h>438#else439#include <mbedtls/ctr_drbg.h>440#include <mbedtls/entropy.h>441#include <mbedtls/md5.h>442#include <mbedtls/sha1.h>443#include <mbedtls/sha256.h>444#include <mbedtls/sha512.h>445#endif446#ifdef _WIN32447#include <wincrypt.h>448#ifdef _MSC_VER449#pragma comment(lib, "crypt32.lib")450#endif451#endif // _WIN32452#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN453#if TARGET_OS_OSX454#include <Security/Security.h>455#endif456#endif457 458// Mbed TLS version API compatibility. Note: V4 implies V3 (both defined on459// 4.x), so version-specific 3.x-only code must check V3 && !V4.460#if MBEDTLS_VERSION_MAJOR >= 4461#define CPPHTTPLIB_MBEDTLS_V4462#endif463#if MBEDTLS_VERSION_MAJOR >= 3464#define CPPHTTPLIB_MBEDTLS_V3465#endif466 467#endif // CPPHTTPLIB_MBEDTLS_SUPPORT468 469#ifdef CPPHTTPLIB_WOLFSSL_SUPPORT470#include <wolfssl/options.h>471 472#include <wolfssl/openssl/x509v3.h>473 474// Fallback definitions for older wolfSSL versions (e.g., 5.6.6)475#ifndef WOLFSSL_GEN_EMAIL476#define WOLFSSL_GEN_EMAIL 1477#endif478#ifndef WOLFSSL_GEN_DNS479#define WOLFSSL_GEN_DNS 2480#endif481#ifndef WOLFSSL_GEN_URI482#define WOLFSSL_GEN_URI 6483#endif484#ifndef WOLFSSL_GEN_IPADD485#define WOLFSSL_GEN_IPADD 7486#endif487 488#include <wolfssl/ssl.h>489#include <wolfssl/wolfcrypt/hash.h>490#include <wolfssl/wolfcrypt/md5.h>491#include <wolfssl/wolfcrypt/sha256.h>492#include <wolfssl/wolfcrypt/sha512.h>493#ifdef _WIN32494#include <wincrypt.h>495#ifdef _MSC_VER496#pragma comment(lib, "crypt32.lib")497#endif498#endif // _WIN32499#ifdef CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN500#if TARGET_OS_OSX501#include <Security/Security.h>502#endif503#endif504#endif // CPPHTTPLIB_WOLFSSL_SUPPORT505 506// Define CPPHTTPLIB_SSL_ENABLED if any SSL backend is available507#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) || \508 defined(CPPHTTPLIB_MBEDTLS_SUPPORT) || defined(CPPHTTPLIB_WOLFSSL_SUPPORT)509#define CPPHTTPLIB_SSL_ENABLED510#endif511 512#ifdef CPPHTTPLIB_ZLIB_SUPPORT513#include <zlib.h>514#endif515 516#ifdef CPPHTTPLIB_BROTLI_SUPPORT517#include <brotli/decode.h>518#include <brotli/encode.h>519#endif520 521#ifdef CPPHTTPLIB_ZSTD_SUPPORT522#include <zstd.h>523#endif524 525/*526 * Declaration527 */528namespace httplib {529 530namespace ws {531class WebSocket;532} // namespace ws533 534namespace detail {535 536/*537 * Backport std::make_unique from C++14.538 *539 * NOTE: This code came up with the following stackoverflow post:540 * https://stackoverflow.com/questions/10149840/c-arrays-and-make-unique541 *542 */543 544template <class T, class... Args>545typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type546make_unique(Args &&...args) {547 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));548}549 550template <class T>551typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type552make_unique(std::size_t n) {553 typedef typename std::remove_extent<T>::type RT;554 return std::unique_ptr<T>(new RT[n]);555}556 557// Locale-independent ASCII character classification. The <cctype>558// counterparts (std::isalnum, std::isdigit, ...) consult the global C locale,559// so e.g. std::isalnum(0xC5) can return true once an embedder calls560// setlocale(). HTTP grammars are defined over ASCII, so raw bytes must be561// classified without regard to the locale.562inline bool is_ascii_digit(char c) { return '0' <= c && c <= '9'; }563 564inline bool is_ascii_alpha(char c) {565 return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');566}567 568inline bool is_ascii_alnum(char c) {569 return is_ascii_digit(c) || is_ascii_alpha(c);570}571 572namespace case_ignore {573 574inline unsigned char to_lower(int c) {575 const static unsigned char table[256] = {576 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,577 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,578 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,579 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,580 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,581 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,582 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,583 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,584 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,585 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,586 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,587 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,588 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 224, 225, 226,589 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,590 242, 243, 244, 245, 246, 215, 248, 249, 250, 251, 252, 253, 254, 223, 224,591 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,592 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,593 255,594 };595 return table[(unsigned char)(char)c];596}597 598inline std::string to_lower(const std::string &s) {599 std::string result = s;600 std::transform(601 result.begin(), result.end(), result.begin(),602 [](unsigned char c) { return static_cast<char>(to_lower(c)); });603 return result;604}605 606inline bool equal(const std::string &a, const std::string &b) {607 return a.size() == b.size() &&608 std::equal(a.begin(), a.end(), b.begin(), [](char ca, char cb) {609 return to_lower(ca) == to_lower(cb);610 });611}612 613struct equal_to {614 bool operator()(const std::string &a, const std::string &b) const {615 return equal(a, b);616 }617};618 619struct hash {620 size_t operator()(const std::string &key) const {621 return hash_core(key.data(), key.size(), 0);622 }623 624 size_t hash_core(const char *s, size_t l, size_t h) const {625 return (l == 0) ? h626 : hash_core(s + 1, l - 1,627 // Unsets the 6 high bits of h, therefore no628 // overflow happens629 (((std::numeric_limits<size_t>::max)() >> 6) &630 h * 33) ^631 static_cast<unsigned char>(to_lower(*s)));632 }633};634 635template <typename T>636using unordered_set = std::unordered_set<T, detail::case_ignore::hash,637 detail::case_ignore::equal_to>;638 639} // namespace case_ignore640 641// This is based on642// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189".643 644struct scope_exit {645 explicit scope_exit(std::function<void(void)> &&f)646 : exit_function(std::move(f)), execute_on_destruction{true} {}647 648 scope_exit(scope_exit &&rhs) noexcept649 : exit_function(std::move(rhs.exit_function)),650 execute_on_destruction{rhs.execute_on_destruction} {651 rhs.release();652 }653 654 ~scope_exit() {655 if (execute_on_destruction) { this->exit_function(); }656 }657 658 void release() { this->execute_on_destruction = false; }659 660private:661 scope_exit(const scope_exit &) = delete;662 void operator=(const scope_exit &) = delete;663 scope_exit &operator=(scope_exit &&) = delete;664 665 std::function<void(void)> exit_function;666 bool execute_on_destruction;667};668 669// Simple from_chars implementation for integer and double types (C++17670// substitute)671template <typename T> struct from_chars_result {672 const char *ptr;673 std::errc ec;674};675 676template <typename T>677inline from_chars_result<T> from_chars(const char *first, const char *last,678 T &value, int base = 10) {679 value = 0;680 const char *p = first;681 bool negative = false;682 683 if (p != last && *p == '-') {684 negative = true;685 ++p;686 }687 if (p == last) { return {first, std::errc::invalid_argument}; }688 689 T result = 0;690 for (; p != last; ++p) {691 char c = *p;692 int digit = -1;693 if (is_ascii_digit(c)) {694 digit = c - '0';695 } else if ('a' <= c && c <= 'z') {696 digit = c - 'a' + 10;697 } else if ('A' <= c && c <= 'Z') {698 digit = c - 'A' + 10;699 } else {700 break;701 }702 703 if (digit < 0 || digit >= base) { break; }704 if (result > ((std::numeric_limits<T>::max)() - digit) / base) {705 return {p, std::errc::result_out_of_range};706 }707 result = result * base + digit;708 }709 710 if (p == first || (negative && p == first + 1)) {711 return {first, std::errc::invalid_argument};712 }713 714 value = negative ? T(0) - result : result;715 return {p, std::errc{}};716}717 718// from_chars for double (hand-written, locale-independent)719//720// The only double consumed by this library is the HTTP quality value, whose721// grammar is (RFC 9110 12.4.2):722// qvalue = ( "0" [ "." 0*3DIGIT ] ) / ( "1" [ "." 0*3("0") ] )723// i.e. a non-negative decimal with no sign, exponent, "inf"/"nan", or wide724// magnitude. So this parser recognizes exactly 1*DIGIT [ "." *DIGIT ] with725// '.' always the decimal separator (std::strtod would instead read it from the726// global C locale, mis-parsing q-values once an embedder calls727// setlocale(LC_ALL, "") into a comma-decimal locale). The caller range-checks728// the result to [0, 1], so inputs outside that range need not be distinguished729// here. Allocation-free, single pass, and free of the overflow/rounding edge730// cases that exponent and wide-range handling would introduce.731inline from_chars_result<double> from_chars(const char *first, const char *last,732 double &value) {733 value = 0.0;734 const char *p = first;735 736 // Each 1eN is exactly representable, so a single final division by the737 // matching entry yields a correctly-rounded result.738 static const double powers_of_ten[] = {739 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,740 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18};741 const int max_frac_digits =742 static_cast<int>(sizeof(powers_of_ten) / sizeof(powers_of_ten[0])) - 1;743 744 // Accumulate digits into a 64-bit integer and remember how many were745 // fractional. Two independent caps keep this bounded and safe:746 // * accumulation saturates before mantissa could overflow uint64_t, and747 // * frac_digits is capped at max_frac_digits so it is always a valid index748 // into powers_of_ten (without this an input like "0.000...0" would never749 // grow mantissa, so the saturation cap alone would not bound it).750 // Both caps only drop digits far beyond the precision a q-value needs; any751 // value they would change is well outside [0, 1] and rejected by the caller.752 uint64_t mantissa = 0;753 int frac_digits = 0;754 bool seen_digit = false;755 756 const uint64_t limit = ((std::numeric_limits<uint64_t>::max)() - 9) / 10;757 auto accumulate = [&](char c) {758 if (mantissa <= limit) {759 mantissa = mantissa * 10 + static_cast<uint64_t>(c - '0');760 return true;761 }762 return false;763 };764 765 for (; p != last && is_ascii_digit(*p); ++p) {766 seen_digit = true;767 accumulate(*p);768 }769 770 if (p != last && *p == '.') {771 ++p;772 for (; p != last && is_ascii_digit(*p); ++p) {773 seen_digit = true;774 if (frac_digits < max_frac_digits && accumulate(*p)) { ++frac_digits; }775 }776 }777 778 if (!seen_digit) { return {first, std::errc::invalid_argument}; }779 780 value = static_cast<double>(mantissa) / powers_of_ten[frac_digits];781 return {p, std::errc{}};782}783 784inline bool parse_port(const char *s, size_t len, int &port) {785 int val = 0;786 auto r = from_chars(s, s + len, val);787 if (r.ec != std::errc{} || val < 1 || val > 65535) { return false; }788 port = val;789 return true;790}791 792inline bool parse_port(const std::string &s, int &port) {793 return parse_port(s.data(), s.size(), port);794}795 796struct UrlComponents {797 std::string scheme;798 std::string host;799 std::string port;800 std::string path;801 std::string query;802};803 804inline bool parse_url(const std::string &url, UrlComponents &uc) {805 uc = {};806 size_t pos = 0;807 808 auto sep = url.find("://");809 if (sep != std::string::npos) {810 uc.scheme = url.substr(0, sep);811 812 // Scheme must be [a-z]+ only813 if (uc.scheme.empty()) { return false; }814 for (auto c : uc.scheme) {815 if (c < 'a' || c > 'z') { return false; }816 }817 818 pos = sep + 3;819 } else if (url.compare(0, 2, "//") == 0) {820 pos = 2;821 }822 823 auto has_authority_prefix = pos > 0;824 auto has_authority = has_authority_prefix || (!url.empty() && url[0] != '/' &&825 url[0] != '?' && url[0] != '#');826 if (has_authority) {827 if (pos < url.size() && url[pos] == '[') {828 auto close = url.find(']', pos);829 if (close == std::string::npos) { return false; }830 uc.host = url.substr(pos + 1, close - pos - 1);831 832 // IPv6 host must be [a-fA-F0-9:]+ only833 if (uc.host.empty()) { return false; }834 for (auto c : uc.host) {835 if (!(is_ascii_digit(c) || (c >= 'a' && c <= 'f') ||836 (c >= 'A' && c <= 'F') || c == ':')) {837 return false;838 }839 }840 841 pos = close + 1;842 } else {843 auto end = url.find_first_of(":/?#", pos);844 if (end == std::string::npos) { end = url.size(); }845 uc.host = url.substr(pos, end - pos);846 pos = end;847 }848 849 if (pos < url.size() && url[pos] == ':') {850 ++pos;851 auto end = url.find_first_of("/?#", pos);852 if (end == std::string::npos) { end = url.size(); }853 uc.port = url.substr(pos, end - pos);854 pos = end;855 }856 857 // Without :// or //, the entire input must be consumed as host[:port].858 // If there is leftover (path, query, etc.), this is not a valid859 // host[:port] string — clear and reparse as a plain path.860 if (!has_authority_prefix && pos < url.size()) {861 uc.host.clear();862 uc.port.clear();863 pos = 0;864 }865 }866 867 if (pos < url.size() && url[pos] != '?' && url[pos] != '#') {868 auto end = url.find_first_of("?#", pos);869 if (end == std::string::npos) { end = url.size(); }870 uc.path = url.substr(pos, end - pos);871 pos = end;872 }873 874 if (pos < url.size() && url[pos] == '?') {875 auto end = url.find('#', pos);876 if (end == std::string::npos) { end = url.size(); }877 uc.query = url.substr(pos, end - pos);878 }879 880 return true;881}882 883} // namespace detail884 885enum class SSLVerifierResponse {886 // no decision has been made, use the built-in certificate verifier887 NoDecisionMade,888 // connection certificate is verified and accepted889 CertificateAccepted,890 // connection certificate was processed but is rejected891 CertificateRejected892};893 894// System CA loading policy for SSL clients. Auto (the default) loads system895// CA certs only when no custom CA is configured; enable_system_ca() switches896// to an explicit policy.897enum class SystemCAMode { Auto, Enabled, Disabled };898 899enum StatusCode {900 // Information responses901 Continue_100 = 100,902 SwitchingProtocol_101 = 101,903 Processing_102 = 102,904 EarlyHints_103 = 103,905 906 // Successful responses907 OK_200 = 200,908 Created_201 = 201,909 Accepted_202 = 202,910 NonAuthoritativeInformation_203 = 203,911 NoContent_204 = 204,912 ResetContent_205 = 205,913 PartialContent_206 = 206,914 MultiStatus_207 = 207,915 AlreadyReported_208 = 208,916 IMUsed_226 = 226,917 918 // Redirection messages919 MultipleChoices_300 = 300,920 MovedPermanently_301 = 301,921 Found_302 = 302,922 SeeOther_303 = 303,923 NotModified_304 = 304,924 UseProxy_305 = 305,925 unused_306 = 306,926 TemporaryRedirect_307 = 307,927 PermanentRedirect_308 = 308,928 929 // Client error responses930 BadRequest_400 = 400,931 Unauthorized_401 = 401,932 PaymentRequired_402 = 402,933 Forbidden_403 = 403,934 NotFound_404 = 404,935 MethodNotAllowed_405 = 405,936 NotAcceptable_406 = 406,937 ProxyAuthenticationRequired_407 = 407,938 RequestTimeout_408 = 408,939 Conflict_409 = 409,940 Gone_410 = 410,941 LengthRequired_411 = 411,942 PreconditionFailed_412 = 412,943 PayloadTooLarge_413 = 413,944 UriTooLong_414 = 414,945 UnsupportedMediaType_415 = 415,946 RangeNotSatisfiable_416 = 416,947 ExpectationFailed_417 = 417,948 ImATeapot_418 = 418,949 MisdirectedRequest_421 = 421,950 UnprocessableContent_422 = 422,951 Locked_423 = 423,952 FailedDependency_424 = 424,953 TooEarly_425 = 425,954 UpgradeRequired_426 = 426,955 PreconditionRequired_428 = 428,956 TooManyRequests_429 = 429,957 RequestHeaderFieldsTooLarge_431 = 431,958 UnavailableForLegalReasons_451 = 451,959 960 // Server error responses961 InternalServerError_500 = 500,962 NotImplemented_501 = 501,963 BadGateway_502 = 502,964 ServiceUnavailable_503 = 503,965 GatewayTimeout_504 = 504,966 HttpVersionNotSupported_505 = 505,967 VariantAlsoNegotiates_506 = 506,968 InsufficientStorage_507 = 507,969 LoopDetected_508 = 508,970 NotExtended_510 = 510,971 NetworkAuthenticationRequired_511 = 511,972};973 974namespace detail {975 976// A multimap that keeps its entries in the order they were inserted.977//978// HTTP needs that order in two places. RFC 9110 5.3 makes the order of header979// fields sharing a field name significant and forbids a proxy from reordering980// them, and a query string's parameters are meaningful in the order the caller981// wrote them. Neither standard container expresses it: std::unordered_multimap982// gives no ordering guarantee at all for equivalent keys (libstdc++ yields983// reverse insertion order, libc++ insertion order), and std::multimap sorts by984// key, which would drop control data such as Host behind whatever else the985// message carries and alphabetise a query string.986//987// Entries are therefore kept in a flat vector, in order. Lookup is a linear988// scan, which beats hashing for the handful of entries a message carries989// (headers are capped at CPPHTTPLIB_HEADER_MAX_COUNT).990//991// KeyEqual compares keys; it is what makes Headers case-insensitive and992// Params, whose parameter names are case-sensitive, not.993template <typename Mapped, typename KeyEqual> class insertion_ordered_multimap {994public:995 using key_type = std::string;996 using mapped_type = Mapped;997 using value_type = std::pair<std::string, Mapped>;998 using size_type = std::size_t;999 using difference_type = std::ptrdiff_t;1000 using reference = value_type &;1001 using const_reference = const value_type &;1002 1003private:1004 static size_type npos() { return static_cast<size_type>(-1); }1005 1006 static bool keys_equal(const std::string &a, const std::string &b) {1007 return KeyEqual()(a, b);1008 }1009 1010 // Iterating yields every entry in insertion order, but equal_range() and1011 // find() have to walk only the entries sharing one key, which are not1012 // adjacent. Both are the same iterator type: key_idx_ selects between the1013 // two traversals, and since equality compares only the position, an iterator1014 // restricted to one key still compares equal to end().1015 template <typename V> class iterator_t {1016 public:1017 using iterator_category = std::bidirectional_iterator_tag;1018 using value_type = insertion_ordered_multimap::value_type;1019 using difference_type = insertion_ordered_multimap::difference_type;1020 using pointer = V *;1021 using reference = V &;1022 1023 iterator_t() : data_(nullptr), idx_(0), size_(0), key_idx_(npos()) {}1024 1025 template <typename U,1026 typename std::enable_if<std::is_convertible<U *, V *>::value,1027 int>::type = 0>1028 iterator_t(const iterator_t<U> &rhs)1029 : data_(rhs.data_), idx_(rhs.idx_), size_(rhs.size_),1030 key_idx_(rhs.key_idx_) {}1031 1032 reference operator*() const { return data_[idx_]; }1033 pointer operator->() const { return data_ + idx_; }1034 1035 iterator_t &operator++() {1036 // Saturating, so that advancing past the last entry of a key (which1037 // get_multimap_value() does when asked for an out-of-range id) stays at1038 // end() instead of running off the container.1039 if (idx_ >= size_) { return *this; }1040 ++idx_;1041 if (key_idx_ != npos()) {1042 while (idx_ < size_ && !matches(idx_)) {1043 ++idx_;1044 }1045 }1046 return *this;1047 }1048 1049 iterator_t operator++(int) {1050 auto tmp = *this;1051 ++*this;1052 return tmp;1053 }1054 1055 iterator_t &operator--() {1056 if (idx_ == 0) { return *this; }1057 --idx_;1058 if (key_idx_ != npos()) {1059 while (idx_ > 0 && !matches(idx_)) {1060 --idx_;1061 }1062 }1063 return *this;1064 }1065 1066 iterator_t operator--(int) {1067 auto tmp = *this;1068 --*this;1069 return tmp;1070 }1071 1072 template <typename U> bool operator==(const iterator_t<U> &rhs) const {1073 return idx_ == rhs.idx_;1074 }1075 1076 template <typename U> bool operator!=(const iterator_t<U> &rhs) const {1077 return idx_ != rhs.idx_;1078 }1079 1080 private:1081 friend class insertion_ordered_multimap;1082 template <typename> friend class iterator_t;1083 1084 iterator_t(V *data, size_type idx, size_type size, size_type key_idx)1085 : data_(data), idx_(idx), size_(size), key_idx_(key_idx) {}1086 1087 bool matches(size_type i) const {1088 return keys_equal(data_[i].first, data_[key_idx_].first);1089 }1090 1091 V *data_;1092 size_type idx_;1093 size_type size_;1094 size_type key_idx_;1095 };1096 1097public:1098 using iterator = iterator_t<value_type>;1099 using const_iterator = iterator_t<const value_type>;1100 1101 insertion_ordered_multimap() = default;1102 insertion_ordered_multimap(std::initializer_list<value_type> il)1103 : entries_(il) {}1104 template <typename InputIt>1105 insertion_ordered_multimap(InputIt first, InputIt last)1106 : entries_(first, last) {}1107 1108 iterator begin() { return make_iter(0, npos()); }1109 iterator end() { return make_iter(entries_.size(), npos()); }1110 const_iterator begin() const { return make_citer(0, npos()); }1111 const_iterator end() const { return make_citer(entries_.size(), npos()); }1112 const_iterator cbegin() const { return begin(); }1113 const_iterator cend() const { return end(); }1114 1115 bool empty() const { return entries_.empty(); }1116 size_type size() const { return entries_.size(); }1117 void clear() { entries_.clear(); }1118 void swap(insertion_ordered_multimap &rhs) { entries_.swap(rhs.entries_); }1119 1120 iterator insert(const value_type &val) {1121 entries_.push_back(val);1122 return make_iter(entries_.size() - 1, npos());1123 }1124 1125 iterator insert(value_type &&val) {1126 entries_.push_back(std::move(val));1127 return make_iter(entries_.size() - 1, npos());1128 }1129 1130 template <typename... Args> iterator emplace(Args &&...args) {1131 entries_.emplace_back(std::forward<Args>(args)...);1132 return make_iter(entries_.size() - 1, npos());1133 }1134 1135 // For entries that have to lead the message, such as the Host header field1136 // (RFC 9110 5.3 recommends sending control data first).1137 template <typename... Args> iterator emplace_front(Args &&...args) {1138 entries_.emplace(entries_.begin(), std::forward<Args>(args)...);1139 return make_iter(0, npos());1140 }1141 1142 iterator find(const std::string &key) {1143 auto i = index_of(key);1144 return i == npos() ? end() : make_iter(i, i);1145 }1146 1147 const_iterator find(const std::string &key) const {1148 auto i = index_of(key);1149 return i == npos() ? end() : make_citer(i, i);1150 }1151 1152 size_type count(const std::string &key) const {1153 size_type n = 0;1154 for (const auto &entry : entries_) {1155 if (keys_equal(entry.first, key)) { n++; }1156 }1157 return n;1158 }1159 1160 std::pair<iterator, iterator> equal_range(const std::string &key) {1161 auto i = index_of(key);1162 return i == npos() ? std::make_pair(end(), end())1163 : std::make_pair(make_iter(i, i), end());1164 }1165 1166 std::pair<const_iterator, const_iterator>1167 equal_range(const std::string &key) const {1168 auto i = index_of(key);1169 return i == npos() ? std::make_pair(end(), end())1170 : std::make_pair(make_citer(i, i), end());1171 }1172 1173 size_type erase(const std::string &key) {1174 auto before = entries_.size();1175 entries_.erase(std::remove_if(entries_.begin(), entries_.end(),1176 [&](const value_type &entry) {1177 return keys_equal(entry.first, key);1178 }),1179 entries_.end());1180 return before - entries_.size();1181 }1182 1183 iterator erase(const_iterator pos) {1184 entries_.erase(entries_.begin() + static_cast<difference_type>(pos.idx_));1185 return make_iter(pos.idx_, npos());1186 }1187 1188 // Erases what iterating [first, last) would actually visit, so erasing an1189 // equal_range() removes only the entries with that key, not everything1190 // positioned between them.1191 iterator erase(const_iterator first, const_iterator last) {1192 auto from = first.idx_;1193 auto to = last.idx_;1194 if (from >= to) { return make_iter(from, npos()); }1195 1196 auto begin_it = entries_.begin();1197 auto from_it = begin_it + static_cast<difference_type>(from);1198 auto to_it = begin_it + static_cast<difference_type>(to);1199 1200 if (first.key_idx_ == npos()) {