KBaba7/llama.cpp
0
1//2// httplib.h3//4// Copyright (c) 2024 Yuji Hirose. All rights reserved.5// MIT License6//7 8#ifndef CPPHTTPLIB_HTTPLIB_H9#define CPPHTTPLIB_HTTPLIB_H10 11#define CPPHTTPLIB_VERSION "0.18.5"12 13/*14 * Configuration15 */16 17#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND18#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND 519#endif20 21#ifndef CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND22#define CPPHTTPLIB_KEEPALIVE_TIMEOUT_CHECK_INTERVAL_USECOND 1000023#endif24 25#ifndef CPPHTTPLIB_KEEPALIVE_MAX_COUNT26#define CPPHTTPLIB_KEEPALIVE_MAX_COUNT 10027#endif28 29#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND30#define CPPHTTPLIB_CONNECTION_TIMEOUT_SECOND 30031#endif32 33#ifndef CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND34#define CPPHTTPLIB_CONNECTION_TIMEOUT_USECOND 035#endif36 37#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND38#define CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND 539#endif40 41#ifndef CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND42#define CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND 043#endif44 45#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND46#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND 547#endif48 49#ifndef CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND50#define CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND 051#endif52 53#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND54#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_SECOND 30055#endif56 57#ifndef CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND58#define CPPHTTPLIB_CLIENT_READ_TIMEOUT_USECOND 059#endif60 61#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND62#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_SECOND 563#endif64 65#ifndef CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND66#define CPPHTTPLIB_CLIENT_WRITE_TIMEOUT_USECOND 067#endif68 69#ifndef CPPHTTPLIB_IDLE_INTERVAL_SECOND70#define CPPHTTPLIB_IDLE_INTERVAL_SECOND 071#endif72 73#ifndef CPPHTTPLIB_IDLE_INTERVAL_USECOND74#ifdef _WIN3275#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 1000076#else77#define CPPHTTPLIB_IDLE_INTERVAL_USECOND 078#endif79#endif80 81#ifndef CPPHTTPLIB_REQUEST_URI_MAX_LENGTH82#define CPPHTTPLIB_REQUEST_URI_MAX_LENGTH 819283#endif84 85#ifndef CPPHTTPLIB_HEADER_MAX_LENGTH86#define CPPHTTPLIB_HEADER_MAX_LENGTH 819287#endif88 89#ifndef CPPHTTPLIB_REDIRECT_MAX_COUNT90#define CPPHTTPLIB_REDIRECT_MAX_COUNT 2091#endif92 93#ifndef CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT94#define CPPHTTPLIB_MULTIPART_FORM_DATA_FILE_MAX_COUNT 102495#endif96 97#ifndef CPPHTTPLIB_PAYLOAD_MAX_LENGTH98#define CPPHTTPLIB_PAYLOAD_MAX_LENGTH ((std::numeric_limits<size_t>::max)())99#endif100 101#ifndef CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH102#define CPPHTTPLIB_FORM_URL_ENCODED_PAYLOAD_MAX_LENGTH 8192103#endif104 105#ifndef CPPHTTPLIB_RANGE_MAX_COUNT106#define CPPHTTPLIB_RANGE_MAX_COUNT 1024107#endif108 109#ifndef CPPHTTPLIB_TCP_NODELAY110#define CPPHTTPLIB_TCP_NODELAY false111#endif112 113#ifndef CPPHTTPLIB_IPV6_V6ONLY114#define CPPHTTPLIB_IPV6_V6ONLY false115#endif116 117#ifndef CPPHTTPLIB_RECV_BUFSIZ118#define CPPHTTPLIB_RECV_BUFSIZ size_t(16384u)119#endif120 121#ifndef CPPHTTPLIB_COMPRESSION_BUFSIZ122#define CPPHTTPLIB_COMPRESSION_BUFSIZ size_t(16384u)123#endif124 125#ifndef CPPHTTPLIB_THREAD_POOL_COUNT126#define CPPHTTPLIB_THREAD_POOL_COUNT \127 ((std::max)(8u, std::thread::hardware_concurrency() > 0 \128 ? std::thread::hardware_concurrency() - 1 \129 : 0))130#endif131 132#ifndef CPPHTTPLIB_RECV_FLAGS133#define CPPHTTPLIB_RECV_FLAGS 0134#endif135 136#ifndef CPPHTTPLIB_SEND_FLAGS137#define CPPHTTPLIB_SEND_FLAGS 0138#endif139 140#ifndef CPPHTTPLIB_LISTEN_BACKLOG141#define CPPHTTPLIB_LISTEN_BACKLOG 5142#endif143 144/*145 * Headers146 */147 148#ifdef _WIN32149#ifndef _CRT_SECURE_NO_WARNINGS150#define _CRT_SECURE_NO_WARNINGS151#endif //_CRT_SECURE_NO_WARNINGS152 153#ifndef _CRT_NONSTDC_NO_DEPRECATE154#define _CRT_NONSTDC_NO_DEPRECATE155#endif //_CRT_NONSTDC_NO_DEPRECATE156 157#if defined(_MSC_VER)158#if _MSC_VER < 1900159#error Sorry, Visual Studio versions prior to 2015 are not supported160#endif161 162#pragma comment(lib, "ws2_32.lib")163 164#ifdef _WIN64165using ssize_t = __int64;166#else167using ssize_t = long;168#endif169#endif // _MSC_VER170 171#ifndef S_ISREG172#define S_ISREG(m) (((m) & S_IFREG) == S_IFREG)173#endif // S_ISREG174 175#ifndef S_ISDIR176#define S_ISDIR(m) (((m) & S_IFDIR) == S_IFDIR)177#endif // S_ISDIR178 179#ifndef NOMINMAX180#define NOMINMAX181#endif // NOMINMAX182 183#include <io.h>184#include <winsock2.h>185#include <ws2tcpip.h>186 187#ifndef WSA_FLAG_NO_HANDLE_INHERIT188#define WSA_FLAG_NO_HANDLE_INHERIT 0x80189#endif190 191using socket_t = SOCKET;192#ifdef CPPHTTPLIB_USE_POLL193#define poll(fds, nfds, timeout) WSAPoll(fds, nfds, timeout)194#endif195 196#else // not _WIN32197 198#include <arpa/inet.h>199#if !defined(_AIX) && !defined(__MVS__)200#include <ifaddrs.h>201#endif202#ifdef __MVS__203#include <strings.h>204#ifndef NI_MAXHOST205#define NI_MAXHOST 1025206#endif207#endif208#include <net/if.h>209#include <netdb.h>210#include <netinet/in.h>211#ifdef __linux__212#include <resolv.h>213#endif214#include <netinet/tcp.h>215#ifdef CPPHTTPLIB_USE_POLL216#include <poll.h>217#endif218#include <csignal>219#include <pthread.h>220#include <sys/mman.h>221#include <sys/select.h>222#include <sys/socket.h>223#include <sys/un.h>224#include <unistd.h>225 226using socket_t = int;227#ifndef INVALID_SOCKET228#define INVALID_SOCKET (-1)229#endif230#endif //_WIN32231 232#include <algorithm>233#include <array>234#include <atomic>235#include <cassert>236#include <cctype>237#include <climits>238#include <condition_variable>239#include <cstring>240#include <errno.h>241#include <exception>242#include <fcntl.h>243#include <fstream>244#include <functional>245#include <iomanip>246#include <iostream>247#include <list>248#include <map>249#include <memory>250#include <mutex>251#include <random>252#include <regex>253#include <set>254#include <sstream>255#include <string>256#include <sys/stat.h>257#include <thread>258#include <unordered_map>259#include <unordered_set>260#include <utility>261 262#ifdef CPPHTTPLIB_OPENSSL_SUPPORT263#ifdef _WIN32264#include <wincrypt.h>265 266// these are defined in wincrypt.h and it breaks compilation if BoringSSL is267// used268#undef X509_NAME269#undef X509_CERT_PAIR270#undef X509_EXTENSIONS271#undef PKCS7_SIGNER_INFO272 273#ifdef _MSC_VER274#pragma comment(lib, "crypt32.lib")275#endif276#elif defined(CPPHTTPLIB_USE_CERTS_FROM_MACOSX_KEYCHAIN) && defined(__APPLE__)277#include <TargetConditionals.h>278#if TARGET_OS_OSX279#include <CoreFoundation/CoreFoundation.h>280#include <Security/Security.h>281#endif // TARGET_OS_OSX282#endif // _WIN32283 284#include <openssl/err.h>285#include <openssl/evp.h>286#include <openssl/ssl.h>287#include <openssl/x509v3.h>288 289#if defined(_WIN32) && defined(OPENSSL_USE_APPLINK)290#include <openssl/applink.c>291#endif292 293#include <iostream>294#include <sstream>295 296#if defined(OPENSSL_IS_BORINGSSL) || defined(LIBRESSL_VERSION_NUMBER)297#if OPENSSL_VERSION_NUMBER < 0x1010107f298#error Please use OpenSSL or a current version of BoringSSL299#endif300#define SSL_get1_peer_certificate SSL_get_peer_certificate301#elif OPENSSL_VERSION_NUMBER < 0x30000000L302#error Sorry, OpenSSL versions prior to 3.0.0 are not supported303#endif304 305#endif306 307#ifdef CPPHTTPLIB_ZLIB_SUPPORT308#include <zlib.h>309#endif310 311#ifdef CPPHTTPLIB_BROTLI_SUPPORT312#include <brotli/decode.h>313#include <brotli/encode.h>314#endif315 316/*317 * Declaration318 */319namespace httplib {320 321namespace detail {322 323/*324 * Backport std::make_unique from C++14.325 *326 * NOTE: This code came up with the following stackoverflow post:327 * https://stackoverflow.com/questions/10149840/c-arrays-and-make-unique328 *329 */330 331template <class T, class... Args>332typename std::enable_if<!std::is_array<T>::value, std::unique_ptr<T>>::type333make_unique(Args &&...args) {334 return std::unique_ptr<T>(new T(std::forward<Args>(args)...));335}336 337template <class T>338typename std::enable_if<std::is_array<T>::value, std::unique_ptr<T>>::type339make_unique(std::size_t n) {340 typedef typename std::remove_extent<T>::type RT;341 return std::unique_ptr<T>(new RT[n]);342}343 344namespace case_ignore {345 346inline unsigned char to_lower(int c) {347 const static unsigned char table[256] = {348 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,349 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,350 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,351 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,352 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,353 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121,354 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,355 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119,356 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,357 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149,358 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,359 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179,360 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 224, 225, 226,361 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241,362 242, 243, 244, 245, 246, 215, 248, 249, 250, 251, 252, 253, 254, 223, 224,363 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,364 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254,365 255,366 };367 return table[(unsigned char)(char)c];368}369 370inline bool equal(const std::string &a, const std::string &b) {371 return a.size() == b.size() &&372 std::equal(a.begin(), a.end(), b.begin(), [](char ca, char cb) {373 return to_lower(ca) == to_lower(cb);374 });375}376 377struct equal_to {378 bool operator()(const std::string &a, const std::string &b) const {379 return equal(a, b);380 }381};382 383struct hash {384 size_t operator()(const std::string &key) const {385 return hash_core(key.data(), key.size(), 0);386 }387 388 size_t hash_core(const char *s, size_t l, size_t h) const {389 return (l == 0) ? h390 : hash_core(s + 1, l - 1,391 // Unsets the 6 high bits of h, therefore no392 // overflow happens393 (((std::numeric_limits<size_t>::max)() >> 6) &394 h * 33) ^395 static_cast<unsigned char>(to_lower(*s)));396 }397};398 399} // namespace case_ignore400 401// This is based on402// "http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4189".403 404struct scope_exit {405 explicit scope_exit(std::function<void(void)> &&f)406 : exit_function(std::move(f)), execute_on_destruction{true} {}407 408 scope_exit(scope_exit &&rhs) noexcept409 : exit_function(std::move(rhs.exit_function)),410 execute_on_destruction{rhs.execute_on_destruction} {411 rhs.release();412 }413 414 ~scope_exit() {415 if (execute_on_destruction) { this->exit_function(); }416 }417 418 void release() { this->execute_on_destruction = false; }419 420private:421 scope_exit(const scope_exit &) = delete;422 void operator=(const scope_exit &) = delete;423 scope_exit &operator=(scope_exit &&) = delete;424 425 std::function<void(void)> exit_function;426 bool execute_on_destruction;427};428 429} // namespace detail430 431enum StatusCode {432 // Information responses433 Continue_100 = 100,434 SwitchingProtocol_101 = 101,435 Processing_102 = 102,436 EarlyHints_103 = 103,437 438 // Successful responses439 OK_200 = 200,440 Created_201 = 201,441 Accepted_202 = 202,442 NonAuthoritativeInformation_203 = 203,443 NoContent_204 = 204,444 ResetContent_205 = 205,445 PartialContent_206 = 206,446 MultiStatus_207 = 207,447 AlreadyReported_208 = 208,448 IMUsed_226 = 226,449 450 // Redirection messages451 MultipleChoices_300 = 300,452 MovedPermanently_301 = 301,453 Found_302 = 302,454 SeeOther_303 = 303,455 NotModified_304 = 304,456 UseProxy_305 = 305,457 unused_306 = 306,458 TemporaryRedirect_307 = 307,459 PermanentRedirect_308 = 308,460 461 // Client error responses462 BadRequest_400 = 400,463 Unauthorized_401 = 401,464 PaymentRequired_402 = 402,465 Forbidden_403 = 403,466 NotFound_404 = 404,467 MethodNotAllowed_405 = 405,468 NotAcceptable_406 = 406,469 ProxyAuthenticationRequired_407 = 407,470 RequestTimeout_408 = 408,471 Conflict_409 = 409,472 Gone_410 = 410,473 LengthRequired_411 = 411,474 PreconditionFailed_412 = 412,475 PayloadTooLarge_413 = 413,476 UriTooLong_414 = 414,477 UnsupportedMediaType_415 = 415,478 RangeNotSatisfiable_416 = 416,479 ExpectationFailed_417 = 417,480 ImATeapot_418 = 418,481 MisdirectedRequest_421 = 421,482 UnprocessableContent_422 = 422,483 Locked_423 = 423,484 FailedDependency_424 = 424,485 TooEarly_425 = 425,486 UpgradeRequired_426 = 426,487 PreconditionRequired_428 = 428,488 TooManyRequests_429 = 429,489 RequestHeaderFieldsTooLarge_431 = 431,490 UnavailableForLegalReasons_451 = 451,491 492 // Server error responses493 InternalServerError_500 = 500,494 NotImplemented_501 = 501,495 BadGateway_502 = 502,496 ServiceUnavailable_503 = 503,497 GatewayTimeout_504 = 504,498 HttpVersionNotSupported_505 = 505,499 VariantAlsoNegotiates_506 = 506,500 InsufficientStorage_507 = 507,501 LoopDetected_508 = 508,502 NotExtended_510 = 510,503 NetworkAuthenticationRequired_511 = 511,504};505 506using Headers =507 std::unordered_multimap<std::string, std::string, detail::case_ignore::hash,508 detail::case_ignore::equal_to>;509 510using Params = std::multimap<std::string, std::string>;511using Match = std::smatch;512 513using Progress = std::function<bool(uint64_t current, uint64_t total)>;514 515struct Response;516using ResponseHandler = std::function<bool(const Response &response)>;517 518struct MultipartFormData {519 std::string name;520 std::string content;521 std::string filename;522 std::string content_type;523};524using MultipartFormDataItems = std::vector<MultipartFormData>;525using MultipartFormDataMap = std::multimap<std::string, MultipartFormData>;526 527class DataSink {528public:529 DataSink() : os(&sb_), sb_(*this) {}530 531 DataSink(const DataSink &) = delete;532 DataSink &operator=(const DataSink &) = delete;533 DataSink(DataSink &&) = delete;534 DataSink &operator=(DataSink &&) = delete;535 536 std::function<bool(const char *data, size_t data_len)> write;537 std::function<bool()> is_writable;538 std::function<void()> done;539 std::function<void(const Headers &trailer)> done_with_trailer;540 std::ostream os;541 542private:543 class data_sink_streambuf final : public std::streambuf {544 public:545 explicit data_sink_streambuf(DataSink &sink) : sink_(sink) {}546 547 protected:548 std::streamsize xsputn(const char *s, std::streamsize n) override {549 sink_.write(s, static_cast<size_t>(n));550 return n;551 }552 553 private:554 DataSink &sink_;555 };556 557 data_sink_streambuf sb_;558};559 560using ContentProvider =561 std::function<bool(size_t offset, size_t length, DataSink &sink)>;562 563using ContentProviderWithoutLength =564 std::function<bool(size_t offset, DataSink &sink)>;565 566using ContentProviderResourceReleaser = std::function<void(bool success)>;567 568struct MultipartFormDataProvider {569 std::string name;570 ContentProviderWithoutLength provider;571 std::string filename;572 std::string content_type;573};574using MultipartFormDataProviderItems = std::vector<MultipartFormDataProvider>;575 576using ContentReceiverWithProgress =577 std::function<bool(const char *data, size_t data_length, uint64_t offset,578 uint64_t total_length)>;579 580using ContentReceiver =581 std::function<bool(const char *data, size_t data_length)>;582 583using MultipartContentHeader =584 std::function<bool(const MultipartFormData &file)>;585 586class ContentReader {587public:588 using Reader = std::function<bool(ContentReceiver receiver)>;589 using MultipartReader = std::function<bool(MultipartContentHeader header,590 ContentReceiver receiver)>;591 592 ContentReader(Reader reader, MultipartReader multipart_reader)593 : reader_(std::move(reader)),594 multipart_reader_(std::move(multipart_reader)) {}595 596 bool operator()(MultipartContentHeader header,597 ContentReceiver receiver) const {598 return multipart_reader_(std::move(header), std::move(receiver));599 }600 601 bool operator()(ContentReceiver receiver) const {602 return reader_(std::move(receiver));603 }604 605 Reader reader_;606 MultipartReader multipart_reader_;607};608 609using Range = std::pair<ssize_t, ssize_t>;610using Ranges = std::vector<Range>;611 612struct Request {613 std::string method;614 std::string path;615 Params params;616 Headers headers;617 std::string body;618 619 std::string remote_addr;620 int remote_port = -1;621 std::string local_addr;622 int local_port = -1;623 624 // for server625 std::string version;626 std::string target;627 MultipartFormDataMap files;628 Ranges ranges;629 Match matches;630 std::unordered_map<std::string, std::string> path_params;631 std::function<bool()> is_connection_closed = []() { return true; };632 633 // for client634 ResponseHandler response_handler;635 ContentReceiverWithProgress content_receiver;636 Progress progress;637#ifdef CPPHTTPLIB_OPENSSL_SUPPORT638 const SSL *ssl = nullptr;639#endif640 641 bool has_header(const std::string &key) const;642 std::string get_header_value(const std::string &key, const char *def = "",643 size_t id = 0) const;644 uint64_t get_header_value_u64(const std::string &key, uint64_t def = 0,645 size_t id = 0) const;646 size_t get_header_value_count(const std::string &key) const;647 void set_header(const std::string &key, const std::string &val);648 649 bool has_param(const std::string &key) const;650 std::string get_param_value(const std::string &key, size_t id = 0) const;651 size_t get_param_value_count(const std::string &key) const;652 653 bool is_multipart_form_data() const;654 655 bool has_file(const std::string &key) const;656 MultipartFormData get_file_value(const std::string &key) const;657 std::vector<MultipartFormData> get_file_values(const std::string &key) const;658 659 // private members...660 size_t redirect_count_ = CPPHTTPLIB_REDIRECT_MAX_COUNT;661 size_t content_length_ = 0;662 ContentProvider content_provider_;663 bool is_chunked_content_provider_ = false;664 size_t authorization_count_ = 0;665};666 667struct Response {668 std::string version;669 int status = -1;670 std::string reason;671 Headers headers;672 std::string body;673 std::string location; // Redirect location674 675 bool has_header(const std::string &key) const;676 std::string get_header_value(const std::string &key, const char *def = "",677 size_t id = 0) const;678 uint64_t get_header_value_u64(const std::string &key, uint64_t def = 0,679 size_t id = 0) const;680 size_t get_header_value_count(const std::string &key) const;681 void set_header(const std::string &key, const std::string &val);682 683 void set_redirect(const std::string &url, int status = StatusCode::Found_302);684 void set_content(const char *s, size_t n, const std::string &content_type);685 void set_content(const std::string &s, const std::string &content_type);686 void set_content(std::string &&s, const std::string &content_type);687 688 void set_content_provider(689 size_t length, const std::string &content_type, ContentProvider provider,690 ContentProviderResourceReleaser resource_releaser = nullptr);691 692 void set_content_provider(693 const std::string &content_type, ContentProviderWithoutLength provider,694 ContentProviderResourceReleaser resource_releaser = nullptr);695 696 void set_chunked_content_provider(697 const std::string &content_type, ContentProviderWithoutLength provider,698 ContentProviderResourceReleaser resource_releaser = nullptr);699 700 void set_file_content(const std::string &path,701 const std::string &content_type);702 void set_file_content(const std::string &path);703 704 Response() = default;705 Response(const Response &) = default;706 Response &operator=(const Response &) = default;707 Response(Response &&) = default;708 Response &operator=(Response &&) = default;709 ~Response() {710 if (content_provider_resource_releaser_) {711 content_provider_resource_releaser_(content_provider_success_);712 }713 }714 715 // private members...716 size_t content_length_ = 0;717 ContentProvider content_provider_;718 ContentProviderResourceReleaser content_provider_resource_releaser_;719 bool is_chunked_content_provider_ = false;720 bool content_provider_success_ = false;721 std::string file_content_path_;722 std::string file_content_content_type_;723};724 725class Stream {726public:727 virtual ~Stream() = default;728 729 virtual bool is_readable() const = 0;730 virtual bool is_writable() const = 0;731 732 virtual ssize_t read(char *ptr, size_t size) = 0;733 virtual ssize_t write(const char *ptr, size_t size) = 0;734 virtual void get_remote_ip_and_port(std::string &ip, int &port) const = 0;735 virtual void get_local_ip_and_port(std::string &ip, int &port) const = 0;736 virtual socket_t socket() const = 0;737 738 ssize_t write(const char *ptr);739 ssize_t write(const std::string &s);740};741 742class TaskQueue {743public:744 TaskQueue() = default;745 virtual ~TaskQueue() = default;746 747 virtual bool enqueue(std::function<void()> fn) = 0;748 virtual void shutdown() = 0;749 750 virtual void on_idle() {}751};752 753class ThreadPool final : public TaskQueue {754public:755 explicit ThreadPool(size_t n, size_t mqr = 0)756 : shutdown_(false), max_queued_requests_(mqr) {757 while (n) {758 threads_.emplace_back(worker(*this));759 n--;760 }761 }762 763 ThreadPool(const ThreadPool &) = delete;764 ~ThreadPool() override = default;765 766 bool enqueue(std::function<void()> fn) override {767 {768 std::unique_lock<std::mutex> lock(mutex_);769 if (max_queued_requests_ > 0 && jobs_.size() >= max_queued_requests_) {770 return false;771 }772 jobs_.push_back(std::move(fn));773 }774 775 cond_.notify_one();776 return true;777 }778 779 void shutdown() override {780 // Stop all worker threads...781 {782 std::unique_lock<std::mutex> lock(mutex_);783 shutdown_ = true;784 }785 786 cond_.notify_all();787 788 // Join...789 for (auto &t : threads_) {790 t.join();791 }792 }793 794private:795 struct worker {796 explicit worker(ThreadPool &pool) : pool_(pool) {}797 798 void operator()() {799 for (;;) {800 std::function<void()> fn;801 {802 std::unique_lock<std::mutex> lock(pool_.mutex_);803 804 pool_.cond_.wait(805 lock, [&] { return !pool_.jobs_.empty() || pool_.shutdown_; });806 807 if (pool_.shutdown_ && pool_.jobs_.empty()) { break; }808 809 fn = pool_.jobs_.front();810 pool_.jobs_.pop_front();811 }812 813 assert(true == static_cast<bool>(fn));814 fn();815 }816 817#if defined(CPPHTTPLIB_OPENSSL_SUPPORT) && !defined(OPENSSL_IS_BORINGSSL) && \818 !defined(LIBRESSL_VERSION_NUMBER)819 OPENSSL_thread_stop();820#endif821 }822 823 ThreadPool &pool_;824 };825 friend struct worker;826 827 std::vector<std::thread> threads_;828 std::list<std::function<void()>> jobs_;829 830 bool shutdown_;831 size_t max_queued_requests_ = 0;832 833 std::condition_variable cond_;834 std::mutex mutex_;835};836 837using Logger = std::function<void(const Request &, const Response &)>;838 839using SocketOptions = std::function<void(socket_t sock)>;840 841void default_socket_options(socket_t sock);842 843const char *status_message(int status);844 845std::string get_bearer_token_auth(const Request &req);846 847namespace detail {848 849class MatcherBase {850public:851 virtual ~MatcherBase() = default;852 853 // Match request path and populate its matches and854 virtual bool match(Request &request) const = 0;855};856 857/**858 * Captures parameters in request path and stores them in Request::path_params859 *860 * Capture name is a substring of a pattern from : to /.861 * The rest of the pattern is matched agains the request path directly862 * Parameters are captured starting from the next character after863 * the end of the last matched static pattern fragment until the next /.864 *865 * Example pattern:866 * "/path/fragments/:capture/more/fragments/:second_capture"867 * Static fragments:868 * "/path/fragments/", "more/fragments/"869 *870 * Given the following request path:871 * "/path/fragments/:1/more/fragments/:2"872 * the resulting capture will be873 * {{"capture", "1"}, {"second_capture", "2"}}874 */875class PathParamsMatcher final : public MatcherBase {876public:877 PathParamsMatcher(const std::string &pattern);878 879 bool match(Request &request) const override;880 881private:882 // Treat segment separators as the end of path parameter capture883 // Does not need to handle query parameters as they are parsed before path884 // matching885 static constexpr char separator = '/';886 887 // Contains static path fragments to match against, excluding the '/' after888 // path params889 // Fragments are separated by path params890 std::vector<std::string> static_fragments_;891 // Stores the names of the path parameters to be used as keys in the892 // Request::path_params map893 std::vector<std::string> param_names_;894};895 896/**897 * Performs std::regex_match on request path898 * and stores the result in Request::matches899 *900 * Note that regex match is performed directly on the whole request.901 * This means that wildcard patterns may match multiple path segments with /:902 * "/begin/(.*)/end" will match both "/begin/middle/end" and "/begin/1/2/end".903 */904class RegexMatcher final : public MatcherBase {905public:906 RegexMatcher(const std::string &pattern) : regex_(pattern) {}907 908 bool match(Request &request) const override;909 910private:911 std::regex regex_;912};913 914ssize_t write_headers(Stream &strm, const Headers &headers);915 916} // namespace detail917 918class Server {919public:920 using Handler = std::function<void(const Request &, Response &)>;921 922 using ExceptionHandler =923 std::function<void(const Request &, Response &, std::exception_ptr ep)>;924 925 enum class HandlerResponse {926 Handled,927 Unhandled,928 };929 using HandlerWithResponse =930 std::function<HandlerResponse(const Request &, Response &)>;931 932 using HandlerWithContentReader = std::function<void(933 const Request &, Response &, const ContentReader &content_reader)>;934 935 using Expect100ContinueHandler =936 std::function<int(const Request &, Response &)>;937 938 Server();939 940 virtual ~Server();941 942 virtual bool is_valid() const;943 944 Server &Get(const std::string &pattern, Handler handler);945 Server &Post(const std::string &pattern, Handler handler);946 Server &Post(const std::string &pattern, HandlerWithContentReader handler);947 Server &Put(const std::string &pattern, Handler handler);948 Server &Put(const std::string &pattern, HandlerWithContentReader handler);949 Server &Patch(const std::string &pattern, Handler handler);950 Server &Patch(const std::string &pattern, HandlerWithContentReader handler);951 Server &Delete(const std::string &pattern, Handler handler);952 Server &Delete(const std::string &pattern, HandlerWithContentReader handler);953 Server &Options(const std::string &pattern, Handler handler);954 955 bool set_base_dir(const std::string &dir,956 const std::string &mount_point = std::string());957 bool set_mount_point(const std::string &mount_point, const std::string &dir,958 Headers headers = Headers());959 bool remove_mount_point(const std::string &mount_point);960 Server &set_file_extension_and_mimetype_mapping(const std::string &ext,961 const std::string &mime);962 Server &set_default_file_mimetype(const std::string &mime);963 Server &set_file_request_handler(Handler handler);964 965 template <class ErrorHandlerFunc>966 Server &set_error_handler(ErrorHandlerFunc &&handler) {967 return set_error_handler_core(968 std::forward<ErrorHandlerFunc>(handler),969 std::is_convertible<ErrorHandlerFunc, HandlerWithResponse>{});970 }971 972 Server &set_exception_handler(ExceptionHandler handler);973 Server &set_pre_routing_handler(HandlerWithResponse handler);974 Server &set_post_routing_handler(Handler handler);975 976 Server &set_expect_100_continue_handler(Expect100ContinueHandler handler);977 Server &set_logger(Logger logger);978 979 Server &set_address_family(int family);980 Server &set_tcp_nodelay(bool on);981 Server &set_ipv6_v6only(bool on);982 Server &set_socket_options(SocketOptions socket_options);983 984 Server &set_default_headers(Headers headers);985 Server &986 set_header_writer(std::function<ssize_t(Stream &, Headers &)> const &writer);987 988 Server &set_keep_alive_max_count(size_t count);989 Server &set_keep_alive_timeout(time_t sec);990 991 Server &set_read_timeout(time_t sec, time_t usec = 0);992 template <class Rep, class Period>993 Server &set_read_timeout(const std::chrono::duration<Rep, Period> &duration);994 995 Server &set_write_timeout(time_t sec, time_t usec = 0);996 template <class Rep, class Period>997 Server &set_write_timeout(const std::chrono::duration<Rep, Period> &duration);998 999 Server &set_idle_interval(time_t sec, time_t usec = 0);1000 template <class Rep, class Period>1001 Server &set_idle_interval(const std::chrono::duration<Rep, Period> &duration);1002 1003 Server &set_payload_max_length(size_t length);1004 1005 bool bind_to_port(const std::string &host, int port, int socket_flags = 0);1006 int bind_to_any_port(const std::string &host, int socket_flags = 0);1007 bool listen_after_bind();1008 1009 bool listen(const std::string &host, int port, int socket_flags = 0);1010 1011 bool is_running() const;1012 void wait_until_ready() const;1013 void stop();1014 void decommission();1015 1016 std::function<TaskQueue *(void)> new_task_queue;1017 1018protected:1019 bool process_request(Stream &strm, const std::string &remote_addr,1020 int remote_port, const std::string &local_addr,1021 int local_port, bool close_connection,1022 bool &connection_closed,1023 const std::function<void(Request &)> &setup_request);1024 1025 std::atomic<socket_t> svr_sock_{INVALID_SOCKET};1026 size_t keep_alive_max_count_ = CPPHTTPLIB_KEEPALIVE_MAX_COUNT;1027 time_t keep_alive_timeout_sec_ = CPPHTTPLIB_KEEPALIVE_TIMEOUT_SECOND;1028 time_t read_timeout_sec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_SECOND;1029 time_t read_timeout_usec_ = CPPHTTPLIB_SERVER_READ_TIMEOUT_USECOND;1030 time_t write_timeout_sec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_SECOND;1031 time_t write_timeout_usec_ = CPPHTTPLIB_SERVER_WRITE_TIMEOUT_USECOND;1032 time_t idle_interval_sec_ = CPPHTTPLIB_IDLE_INTERVAL_SECOND;1033 time_t idle_interval_usec_ = CPPHTTPLIB_IDLE_INTERVAL_USECOND;1034 size_t payload_max_length_ = CPPHTTPLIB_PAYLOAD_MAX_LENGTH;1035 1036private:1037 using Handlers =1038 std::vector<std::pair<std::unique_ptr<detail::MatcherBase>, Handler>>;1039 using HandlersForContentReader =1040 std::vector<std::pair<std::unique_ptr<detail::MatcherBase>,1041 HandlerWithContentReader>>;1042 1043 static std::unique_ptr<detail::MatcherBase>1044 make_matcher(const std::string &pattern);1045 1046 Server &set_error_handler_core(HandlerWithResponse handler, std::true_type);1047 Server &set_error_handler_core(Handler handler, std::false_type);1048 1049 socket_t create_server_socket(const std::string &host, int port,1050 int socket_flags,1051 SocketOptions socket_options) const;1052 int bind_internal(const std::string &host, int port, int socket_flags);1053 bool listen_internal();1054 1055 bool routing(Request &req, Response &res, Stream &strm);1056 bool handle_file_request(const Request &req, Response &res,1057 bool head = false);1058 bool dispatch_request(Request &req, Response &res,1059 const Handlers &handlers) const;1060 bool dispatch_request_for_content_reader(1061 Request &req, Response &res, ContentReader content_reader,1062 const HandlersForContentReader &handlers) const;1063 1064 bool parse_request_line(const char *s, Request &req) const;1065 void apply_ranges(const Request &req, Response &res,1066 std::string &content_type, std::string &boundary) const;1067 bool write_response(Stream &strm, bool close_connection, Request &req,1068 Response &res);1069 bool write_response_with_content(Stream &strm, bool close_connection,1070 const Request &req, Response &res);1071 bool write_response_core(Stream &strm, bool close_connection,1072 const Request &req, Response &res,1073 bool need_apply_ranges);1074 bool write_content_with_provider(Stream &strm, const Request &req,1075 Response &res, const std::string &boundary,1076 const std::string &content_type);1077 bool read_content(Stream &strm, Request &req, Response &res);1078 bool1079 read_content_with_content_receiver(Stream &strm, Request &req, Response &res,1080 ContentReceiver receiver,1081 MultipartContentHeader multipart_header,1082 ContentReceiver multipart_receiver);1083 bool read_content_core(Stream &strm, Request &req, Response &res,1084 ContentReceiver receiver,1085 MultipartContentHeader multipart_header,1086 ContentReceiver multipart_receiver) const;1087 1088 virtual bool process_and_close_socket(socket_t sock);1089 1090 std::atomic<bool> is_running_{false};1091 std::atomic<bool> is_decommisioned{false};1092 1093 struct MountPointEntry {1094 std::string mount_point;1095 std::string base_dir;1096 Headers headers;1097 };1098 std::vector<MountPointEntry> base_dirs_;1099 std::map<std::string, std::string> file_extension_and_mimetype_map_;1100 std::string default_file_mimetype_ = "application/octet-stream";1101 Handler file_request_handler_;1102 1103 Handlers get_handlers_;1104 Handlers post_handlers_;1105 HandlersForContentReader post_handlers_for_content_reader_;1106 Handlers put_handlers_;1107 HandlersForContentReader put_handlers_for_content_reader_;1108 Handlers patch_handlers_;1109 HandlersForContentReader patch_handlers_for_content_reader_;1110 Handlers delete_handlers_;1111 HandlersForContentReader delete_handlers_for_content_reader_;1112 Handlers options_handlers_;1113 1114 HandlerWithResponse error_handler_;1115 ExceptionHandler exception_handler_;1116 HandlerWithResponse pre_routing_handler_;1117 Handler post_routing_handler_;1118 Expect100ContinueHandler expect_100_continue_handler_;1119 1120 Logger logger_;1121 1122 int address_family_ = AF_UNSPEC;1123 bool tcp_nodelay_ = CPPHTTPLIB_TCP_NODELAY;1124 bool ipv6_v6only_ = CPPHTTPLIB_IPV6_V6ONLY;1125 SocketOptions socket_options_ = default_socket_options;1126 1127 Headers default_headers_;1128 std::function<ssize_t(Stream &, Headers &)> header_writer_ =1129 detail::write_headers;1130};1131 1132enum class Error {1133 Success = 0,1134 Unknown,1135 Connection,1136 BindIPAddress,1137 Read,1138 Write,1139 ExceedRedirectCount,1140 Canceled,1141 SSLConnection,1142 SSLLoadingCerts,1143 SSLServerVerification,1144 SSLServerHostnameVerification,1145 UnsupportedMultipartBoundaryChars,1146 Compression,1147 ConnectionTimeout,1148 ProxyConnection,1149 1150 // For internal use only1151 SSLPeerCouldBeClosed_,1152};1153 1154std::string to_string(Error error);1155 1156std::ostream &operator<<(std::ostream &os, const Error &obj);1157 1158class Result {1159public:1160 Result() = default;1161 Result(std::unique_ptr<Response> &&res, Error err,1162 Headers &&request_headers = Headers{})1163 : res_(std::move(res)), err_(err),1164 request_headers_(std::move(request_headers)) {}1165 // Response1166 operator bool() const { return res_ != nullptr; }1167 bool operator==(std::nullptr_t) const { return res_ == nullptr; }1168 bool operator!=(std::nullptr_t) const { return res_ != nullptr; }1169 const Response &value() const { return *res_; }1170 Response &value() { return *res_; }1171 const Response &operator*() const { return *res_; }1172 Response &operator*() { return *res_; }1173 const Response *operator->() const { return res_.get(); }1174 Response *operator->() { return res_.get(); }1175 1176 // Error1177 Error error() const { return err_; }1178 1179 // Request Headers1180 bool has_request_header(const std::string &key) const;1181 std::string get_request_header_value(const std::string &key,1182 const char *def = "",1183 size_t id = 0) const;1184 uint64_t get_request_header_value_u64(const std::string &key,1185 uint64_t def = 0, size_t id = 0) const;1186 size_t get_request_header_value_count(const std::string &key) const;1187 1188private:1189 std::unique_ptr<Response> res_;1190 Error err_ = Error::Unknown;1191 Headers request_headers_;1192};1193 1194class ClientImpl {1195public:1196 explicit ClientImpl(const std::string &host);1197 1198 explicit ClientImpl(const std::string &host, int port);1199 1200 explicit ClientImpl(const std::string &host, int port,