Team Ai
Datasetpublic

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.

sourceHugging Faceupdated 2mo agoView on Hugging Face
0likes3kdownloads
httplib.cpp17357 linesDownload Raw Back to cpp-httplib
1#include "httplib.h"2namespace httplib {3 4/*5 * Implementation that will be part of the .cc file if split into .h + .cc.6 */7 8namespace stream {9 10// stream::Result implementations11Result::Result() : chunk_size_(8192) {}12 13Result::Result(ClientImpl::StreamHandle &&handle, size_t chunk_size)14    : handle_(std::move(handle)), chunk_size_(chunk_size) {}15 16Result::Result(Result &&other) noexcept17    : handle_(std::move(other.handle_)), buffer_(std::move(other.buffer_)),18      current_size_(other.current_size_), chunk_size_(other.chunk_size_),19      finished_(other.finished_) {20  other.current_size_ = 0;21  other.finished_ = true;22}23 24Result &Result::operator=(Result &&other) noexcept {25  if (this != &other) {26    handle_ = std::move(other.handle_);27    buffer_ = std::move(other.buffer_);28    current_size_ = other.current_size_;29    chunk_size_ = other.chunk_size_;30    finished_ = other.finished_;31    other.current_size_ = 0;32    other.finished_ = true;33  }34  return *this;35}36 37bool Result::is_valid() const { return handle_.is_valid(); }38Result::operator bool() const { return is_valid(); }39 40int Result::status() const {41  return handle_.response ? handle_.response->status : -1;42}43 44const Headers &Result::headers() const {45  static const Headers empty_headers;46  return handle_.response ? handle_.response->headers : empty_headers;47}48 49std::string Result::get_header_value(const std::string &key,50                                            const char *def) const {51  return handle_.response ? handle_.response->get_header_value(key, def) : def;52}53 54bool Result::has_header(const std::string &key) const {55  return handle_.response ? handle_.response->has_header(key) : false;56}57 58Error Result::error() const { return handle_.error; }59Error Result::read_error() const { return handle_.get_read_error(); }60bool Result::has_read_error() const { return handle_.has_read_error(); }61 62bool Result::next() {63  if (!handle_.is_valid() || finished_) { return false; }64 65  if (buffer_.size() < chunk_size_) { buffer_.resize(chunk_size_); }66 67  ssize_t n = handle_.read(&buffer_[0], chunk_size_);68  if (n > 0) {69    current_size_ = static_cast<size_t>(n);70    return true;71  }72 73  current_size_ = 0;74  finished_ = true;75  return false;76}77 78const char *Result::data() const { return buffer_.data(); }79size_t Result::size() const { return current_size_; }80 81std::string Result::read_all() {82  std::string result;83  while (next()) {84    result.append(data(), size());85  }86  return result;87}88 89} // namespace stream90 91namespace sse {92 93// SSEMessage implementations94SSEMessage::SSEMessage() : event("message") {}95 96void SSEMessage::clear() {97  event = "message";98  data.clear();99  id.clear();100}101 102// SSEClient implementations103SSEClient::SSEClient(Client &client, const std::string &path)104    : client_(client), path_(path) {}105 106SSEClient::SSEClient(Client &client, const std::string &path,107                            const Headers &headers)108    : client_(client), path_(path), headers_(headers) {}109 110SSEClient::~SSEClient() { stop(); }111 112SSEClient &SSEClient::on_message(MessageHandler handler) {113  on_message_ = std::move(handler);114  return *this;115}116 117SSEClient &SSEClient::on_event(const std::string &type,118                                      MessageHandler handler) {119  event_handlers_[type] = std::move(handler);120  return *this;121}122 123SSEClient &SSEClient::on_open(OpenHandler handler) {124  on_open_ = std::move(handler);125  return *this;126}127 128SSEClient &SSEClient::on_error(ErrorHandler handler) {129  on_error_ = std::move(handler);130  return *this;131}132 133SSEClient &SSEClient::set_reconnect_interval(int ms) {134  reconnect_interval_ms_ = ms;135  return *this;136}137 138SSEClient &SSEClient::set_max_reconnect_attempts(int n) {139  max_reconnect_attempts_ = n;140  return *this;141}142 143SSEClient &SSEClient::set_headers(const Headers &headers) {144  std::lock_guard<std::mutex> lock(headers_mutex_);145  headers_ = headers;146  return *this;147}148 149bool SSEClient::is_connected() const { return connected_.load(); }150 151const std::string &SSEClient::last_event_id() const {152  return last_event_id_;153}154 155void SSEClient::start() {156  running_.store(true);157  run_event_loop();158}159 160void SSEClient::start_async() {161  running_.store(true);162  async_thread_ = std::thread([this]() { run_event_loop(); });163}164 165void SSEClient::stop() {166  running_.store(false);167  client_.stop(); // Cancel any pending operations168  if (async_thread_.joinable()) { async_thread_.join(); }169}170 171bool SSEClient::parse_sse_line(const std::string &line, SSEMessage &msg,172                                      int &retry_ms) {173  // Blank line signals end of event174  if (line.empty() || line == "\r") { return true; }175 176  // Lines starting with ':' are comments (ignored)177  if (!line.empty() && line[0] == ':') { return false; }178 179  // Find the colon separator180  auto colon_pos = line.find(':');181  if (colon_pos == std::string::npos) {182    // Line with no colon is treated as field name with empty value183    return false;184  }185 186  auto field = line.substr(0, colon_pos);187  std::string value;188 189  // Value starts after colon, skip optional single space190  if (colon_pos + 1 < line.size()) {191    auto value_start = colon_pos + 1;192    if (line[value_start] == ' ') { value_start++; }193    value = line.substr(value_start);194    // Remove trailing \r if present195    if (!value.empty() && value.back() == '\r') { value.pop_back(); }196  }197 198  // Handle known fields199  if (field == "event") {200    msg.event = value;201  } else if (field == "data") {202    // Multiple data lines are concatenated with newlines203    if (!msg.data.empty()) { msg.data += "\n"; }204    msg.data += value;205  } else if (field == "id") {206    // Empty id is valid (clears the last event ID)207    msg.id = value;208  } else if (field == "retry") {209    // Parse retry interval in milliseconds210    {211      int v = 0;212      auto res =213          detail::from_chars(value.data(), value.data() + value.size(), v);214      if (res.ec == std::errc{}) { retry_ms = v; }215    }216  }217  // Unknown fields are ignored per SSE spec218 219  return false;220}221 222void SSEClient::run_event_loop() {223  auto reconnect_count = 0;224 225  while (running_.load()) {226    // Build headers, including Last-Event-ID if we have one227    Headers request_headers;228    {229      std::lock_guard<std::mutex> lock(headers_mutex_);230      request_headers = headers_;231    }232    if (!last_event_id_.empty()) {233      request_headers.emplace("Last-Event-ID", last_event_id_);234    }235 236    // Open streaming connection237    auto result = stream::Get(client_, path_, request_headers);238 239    // Connection error handling240    if (!result) {241      connected_.store(false);242      if (on_error_) { on_error_(result.error()); }243 244      if (!should_reconnect(reconnect_count)) { break; }245      wait_for_reconnect();246      reconnect_count++;247      continue;248    }249 250    if (result.status() != StatusCode::OK_200) {251      connected_.store(false);252      if (on_error_) { on_error_(Error::Connection); }253 254      // For certain errors, don't reconnect.255      // Note: 401 is intentionally absent so that handlers can refresh256      // credentials via set_headers() and let the client reconnect.257      if (result.status() == StatusCode::NoContent_204 ||258          result.status() == StatusCode::NotFound_404 ||259          result.status() == StatusCode::Forbidden_403) {260        break;261      }262 263      if (!should_reconnect(reconnect_count)) { break; }264      wait_for_reconnect();265      reconnect_count++;266      continue;267    }268 269    // Connection successful270    connected_.store(true);271    reconnect_count = 0;272    if (on_open_) { on_open_(); }273 274    // Event receiving loop275    std::string buffer;276    SSEMessage current_msg;277 278    while (running_.load() && result.next()) {279      buffer.append(result.data(), result.size());280 281      // Process complete lines in the buffer282      size_t line_start = 0;283      size_t newline_pos;284 285      while ((newline_pos = buffer.find('\n', line_start)) !=286             std::string::npos) {287        auto line = buffer.substr(line_start, newline_pos - line_start);288        line_start = newline_pos + 1;289 290        // Parse the line and check if event is complete291        auto event_complete =292            parse_sse_line(line, current_msg, reconnect_interval_ms_);293 294        if (event_complete && !current_msg.data.empty()) {295          // Update last_event_id for reconnection296          if (!current_msg.id.empty()) { last_event_id_ = current_msg.id; }297 298          // Dispatch event to appropriate handler299          dispatch_event(current_msg);300 301          current_msg.clear();302        }303      }304 305      // Keep unprocessed data in buffer306      buffer.erase(0, line_start);307    }308 309    // Connection ended310    connected_.store(false);311 312    if (!running_.load()) { break; }313 314    // Check for read errors315    if (result.has_read_error()) {316      if (on_error_) { on_error_(result.read_error()); }317    }318 319    if (!should_reconnect(reconnect_count)) { break; }320    wait_for_reconnect();321    reconnect_count++;322  }323 324  connected_.store(false);325}326 327void SSEClient::dispatch_event(const SSEMessage &msg) {328  // Check for specific event type handler first329  auto it = event_handlers_.find(msg.event);330  if (it != event_handlers_.end()) {331    it->second(msg);332    return;333  }334 335  // Fall back to generic message handler336  if (on_message_) { on_message_(msg); }337}338 339bool SSEClient::should_reconnect(int count) const {340  if (!running_.load()) { return false; }341  if (max_reconnect_attempts_ == 0) { return true; } // unlimited342  return count < max_reconnect_attempts_;343}344 345void SSEClient::wait_for_reconnect() {346  // Use small increments to check running_ flag frequently347  auto waited = 0;348  while (running_.load() && waited < reconnect_interval_ms_) {349    std::this_thread::sleep_for(std::chrono::milliseconds(100));350    waited += 100;351  }352}353 354} // namespace sse355 356#ifdef CPPHTTPLIB_SSL_ENABLED357/*358 * TLS abstraction layer - internal function declarations359 * These are implementation details and not part of the public API.360 */361namespace tls {362 363// Client context364ctx_t create_client_context();365void free_context(ctx_t ctx);366bool set_min_version(ctx_t ctx, Version version);367bool load_ca_pem(ctx_t ctx, const char *pem, size_t len);368bool load_ca_file(ctx_t ctx, const char *file_path);369bool load_ca_dir(ctx_t ctx, const char *dir_path);370bool load_system_certs(ctx_t ctx);371bool set_client_cert_pem(ctx_t ctx, const char *cert, const char *key,372                         const char *password);373bool set_client_cert_file(ctx_t ctx, const char *cert_path,374                          const char *key_path, const char *password);375 376// Server context377ctx_t create_server_context();378bool set_server_cert_pem(ctx_t ctx, const char *cert, const char *key,379                         const char *password);380bool set_server_cert_file(ctx_t ctx, const char *cert_path,381                          const char *key_path, const char *password);382bool set_client_ca_file(ctx_t ctx, const char *ca_file, const char *ca_dir);383void set_verify_client(ctx_t ctx, bool require);384 385// Session management386session_t create_session(ctx_t ctx, socket_t sock);387void free_session(session_t session);388bool set_sni(session_t session, const char *hostname, bool verify_hostname);389 390// Handshake (non-blocking capable)391TlsError connect(session_t session);392TlsError accept(session_t session);393 394// Handshake with timeout (blocking until timeout)395bool connect_nonblocking(session_t session, socket_t sock, time_t timeout_sec,396                         time_t timeout_usec, TlsError *err);397bool accept_nonblocking(session_t session, socket_t sock, time_t timeout_sec,398                        time_t timeout_usec, TlsError *err);399 400// I/O (non-blocking capable)401ssize_t read(session_t session, void *buf, size_t len, TlsError &err);402ssize_t write(session_t session, const void *buf, size_t len, TlsError &err);403int pending(const_session_t session);404void shutdown(session_t session, bool graceful);405 406// Connection state407bool is_peer_closed(session_t session, socket_t sock);408 409// Certificate verification410cert_t get_peer_cert(const_session_t session);411void free_cert(cert_t cert);412bool verify_hostname(cert_t cert, const char *hostname);413uint64_t hostname_mismatch_code();414long get_verify_result(const_session_t session);415 416// Certificate introspection417std::string get_cert_subject_cn(cert_t cert);418std::string get_cert_issuer_name(cert_t cert);419bool get_cert_sans(cert_t cert, std::vector<SanEntry> &sans);420bool get_cert_validity(cert_t cert, time_t &not_before, time_t &not_after);421std::string get_cert_serial(cert_t cert);422bool get_cert_der(cert_t cert, std::vector<unsigned char> &der);423const char *get_sni(const_session_t session);424 425// CA store management426ca_store_t create_ca_store(const char *pem, size_t len);427void free_ca_store(ca_store_t store);428bool set_ca_store(ctx_t ctx, ca_store_t store);429size_t get_ca_certs(ctx_t ctx, std::vector<cert_t> &certs);430std::vector<std::string> get_ca_names(ctx_t ctx);431 432// Dynamic certificate update (for servers)433bool update_server_cert(ctx_t ctx, const char *cert_pem, const char *key_pem,434                        const char *password);435bool update_server_client_ca(ctx_t ctx, const char *ca_pem);436 437// Certificate verification callback438bool set_verify_callback(ctx_t ctx, VerifyCallback callback);439long get_verify_error(const_session_t session);440std::string verify_error_string(long error_code);441 442// TlsError information443uint64_t peek_error();444uint64_t get_error();445std::string error_string(uint64_t code);446 447} // namespace tls448#endif // CPPHTTPLIB_SSL_ENABLED449 450/*451 * Group 1: detail namespace - Non-SSL utilities452 */453 454namespace detail {455 456bool set_socket_opt_impl(socket_t sock, int level, int optname,457                                const void *optval, socklen_t optlen) {458  return setsockopt(sock, level, optname,459#ifdef _WIN32460                    reinterpret_cast<const char *>(optval),461#else462                    optval,463#endif464                    optlen) == 0;465}466 467bool set_socket_opt_time(socket_t sock, int level, int optname,468                                time_t sec, time_t usec) {469#ifdef _WIN32470  auto timeout = static_cast<uint32_t>(sec * 1000 + usec / 1000);471#else472  timeval timeout;473  timeout.tv_sec = static_cast<long>(sec);474  timeout.tv_usec = static_cast<decltype(timeout.tv_usec)>(usec);475#endif476  return set_socket_opt_impl(sock, level, optname, &timeout, sizeof(timeout));477}478 479bool is_hex(char c, int &v) {480  if (is_ascii_digit(c)) {481    v = c - '0';482    return true;483  } else if ('A' <= c && c <= 'F') {484    v = c - 'A' + 10;485    return true;486  } else if ('a' <= c && c <= 'f') {487    v = c - 'a' + 10;488    return true;489  }490  return false;491}492 493bool from_hex_to_i(const std::string &s, size_t i, size_t cnt,494                          int &val) {495  if (i >= s.size()) { return false; }496 497  val = 0;498  for (; cnt; i++, cnt--) {499    if (!s[i]) { return false; }500    auto v = 0;501    if (is_hex(s[i], v)) {502      val = val * 16 + v;503    } else {504      return false;505    }506  }507  return true;508}509 510std::string from_i_to_hex(size_t n) {511  static const auto charset = "0123456789abcdef";512  std::string ret;513  do {514    ret = charset[n & 15] + ret;515    n >>= 4;516  } while (n > 0);517  return ret;518}519 520std::string compute_etag(const FileStat &fs) {521  if (!fs.is_file()) { return std::string(); }522 523  // If mtime cannot be determined (negative value indicates an error524  // or sentinel), do not generate an ETag. Returning a neutral / fixed525  // value like 0 could collide with a real file that legitimately has526  // mtime == 0 (epoch) and lead to misleading validators.527  auto mtime_raw = fs.mtime();528  if (mtime_raw < 0) { return std::string(); }529 530  auto mtime = static_cast<size_t>(mtime_raw);531  auto size = fs.size();532 533  return std::string("W/\"") + from_i_to_hex(mtime) + "-" +534         from_i_to_hex(size) + "\"";535}536 537// Format time_t as HTTP-date (RFC 9110 Section 5.6.7): "Sun, 06 Nov 1994538// 08:49:37 GMT" This implementation is defensive: it validates `mtime`, checks539// return values from `gmtime_r`/`gmtime_s`, and ensures `strftime` succeeds.540std::string file_mtime_to_http_date(time_t mtime) {541  if (mtime < 0) { return std::string(); }542 543  struct tm tm_buf;544#ifdef _WIN32545  if (gmtime_s(&tm_buf, &mtime) != 0) { return std::string(); }546#else547  if (gmtime_r(&mtime, &tm_buf) == nullptr) { return std::string(); }548#endif549  char buf[64];550  if (strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", &tm_buf) == 0) {551    return std::string();552  }553 554  return std::string(buf);555}556 557// Parse HTTP-date (RFC 9110 Section 5.6.7) to time_t. Returns -1 on failure.558time_t parse_http_date(const std::string &date_str) {559  struct tm tm_buf;560 561  // Create a classic locale object once for all parsing attempts562  const std::locale classic_locale = std::locale::classic();563 564  // Try to parse using std::get_time (C++11, cross-platform)565  auto try_parse = [&](const char *fmt) -> bool {566    std::istringstream ss(date_str);567    ss.imbue(classic_locale);568 569    memset(&tm_buf, 0, sizeof(tm_buf));570    ss >> std::get_time(&tm_buf, fmt);571 572    return !ss.fail();573  };574 575  // RFC 9110 preferred format (HTTP-date): "Sun, 06 Nov 1994 08:49:37 GMT"576  if (!try_parse("%a, %d %b %Y %H:%M:%S")) {577    // RFC 850 format: "Sunday, 06-Nov-94 08:49:37 GMT"578    if (!try_parse("%A, %d-%b-%y %H:%M:%S")) {579      // asctime format: "Sun Nov  6 08:49:37 1994"580      if (!try_parse("%a %b %d %H:%M:%S %Y")) {581        return static_cast<time_t>(-1);582      }583    }584  }585 586#ifdef _WIN32587  return _mkgmtime(&tm_buf);588#elif defined _AIX589  return mktime(&tm_buf);590#else591  return timegm(&tm_buf);592#endif593}594 595bool is_weak_etag(const std::string &s) {596  // Check if the string is a weak ETag (starts with 'W/"')597  return s.size() > 3 && s[0] == 'W' && s[1] == '/' && s[2] == '"';598}599 600bool is_strong_etag(const std::string &s) {601  // Check if the string is a strong ETag (starts and ends with '"', at least 2602  // chars)603  return s.size() >= 2 && s[0] == '"' && s.back() == '"';604}605 606size_t to_utf8(int code, char *buff) {607  if (code < 0x0080) {608    buff[0] = static_cast<char>(code & 0x7F);609    return 1;610  } else if (code < 0x0800) {611    buff[0] = static_cast<char>(0xC0 | ((code >> 6) & 0x1F));612    buff[1] = static_cast<char>(0x80 | (code & 0x3F));613    return 2;614  } else if (code < 0xD800) {615    buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));616    buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));617    buff[2] = static_cast<char>(0x80 | (code & 0x3F));618    return 3;619  } else if (code < 0xE000) { // D800 - DFFF is invalid...620    return 0;621  } else if (code < 0x10000) {622    buff[0] = static_cast<char>(0xE0 | ((code >> 12) & 0xF));623    buff[1] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));624    buff[2] = static_cast<char>(0x80 | (code & 0x3F));625    return 3;626  } else if (code < 0x110000) {627    buff[0] = static_cast<char>(0xF0 | ((code >> 18) & 0x7));628    buff[1] = static_cast<char>(0x80 | ((code >> 12) & 0x3F));629    buff[2] = static_cast<char>(0x80 | ((code >> 6) & 0x3F));630    buff[3] = static_cast<char>(0x80 | (code & 0x3F));631    return 4;632  }633 634  // NOTREACHED635  return 0;636}637 638} // namespace detail639 640namespace ws {641namespace impl {642 643bool is_valid_utf8(const std::string &s) {644  size_t i = 0;645  auto n = s.size();646  while (i < n) {647    auto c = static_cast<unsigned char>(s[i]);648    size_t len;649    uint32_t cp;650    if (c < 0x80) {651      i++;652      continue;653    } else if ((c & 0xE0) == 0xC0) {654      len = 2;655      cp = c & 0x1F;656    } else if ((c & 0xF0) == 0xE0) {657      len = 3;658      cp = c & 0x0F;659    } else if ((c & 0xF8) == 0xF0) {660      len = 4;661      cp = c & 0x07;662    } else {663      return false;664    }665    if (i + len > n) { return false; }666    for (size_t j = 1; j < len; j++) {667      auto b = static_cast<unsigned char>(s[i + j]);668      if ((b & 0xC0) != 0x80) { return false; }669      cp = (cp << 6) | (b & 0x3F);670    }671    // Overlong encoding check672    if (len == 2 && cp < 0x80) { return false; }673    if (len == 3 && cp < 0x800) { return false; }674    if (len == 4 && cp < 0x10000) { return false; }675    // Surrogate halves (U+D800..U+DFFF) and beyond U+10FFFF are invalid676    if (cp >= 0xD800 && cp <= 0xDFFF) { return false; }677    if (cp > 0x10FFFF) { return false; }678    i += len;679  }680  return true;681}682 683} // namespace impl684} // namespace ws685 686namespace detail {687 688// NOTE: This code came up with the following stackoverflow post:689// https://stackoverflow.com/questions/180947/base64-decode-snippet-in-c690std::string base64_encode(const std::string &in) {691  static const auto lookup =692      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";693 694  std::string out;695  out.reserve(in.size());696 697  // Unsigned: the accumulator is never masked, so with a signed int the698  // `val << 8` below overflows once enough bytes are folded in (undefined699  // behaviour before C++20). Only the low bits are ever emitted, so the700  // wrap-around of an unsigned accumulator does not affect the output.701  uint32_t val = 0;702  auto valb = -6;703 704  for (auto c : in) {705    val = (val << 8) + static_cast<uint8_t>(c);706    valb += 8;707    while (valb >= 0) {708      out.push_back(lookup[(val >> valb) & 0x3F]);709      valb -= 6;710    }711  }712 713  if (valb > -6) { out.push_back(lookup[((val << 8) >> (valb + 8)) & 0x3F]); }714 715  while (out.size() % 4) {716    out.push_back('=');717  }718 719  return out;720}721 722std::string sha1(const std::string &input) {723  // RFC 3174 SHA-1 implementation724  auto left_rotate = [](uint32_t x, uint32_t n) -> uint32_t {725    return (x << n) | (x >> (32 - n));726  };727 728  uint32_t h0 = 0x67452301;729  uint32_t h1 = 0xEFCDAB89;730  uint32_t h2 = 0x98BADCFE;731  uint32_t h3 = 0x10325476;732  uint32_t h4 = 0xC3D2E1F0;733 734  // Pre-processing: adding padding bits735  std::string msg = input;736  uint64_t original_bit_len = static_cast<uint64_t>(msg.size()) * 8;737  msg.push_back(static_cast<char>(0x80u));738  while (msg.size() % 64 != 56) {739    msg.push_back(0);740  }741 742  // Append original length in bits as 64-bit big-endian743  for (int i = 56; i >= 0; i -= 8) {744    msg.push_back(static_cast<char>((original_bit_len >> i) & 0xFF));745  }746 747  // Process each 512-bit chunk748  for (size_t offset = 0; offset < msg.size(); offset += 64) {749    uint32_t w[80];750 751    for (size_t i = 0; i < 16; i++) {752      w[i] =753          (static_cast<uint32_t>(static_cast<uint8_t>(msg[offset + i * 4]))754           << 24) |755          (static_cast<uint32_t>(static_cast<uint8_t>(msg[offset + i * 4 + 1]))756           << 16) |757          (static_cast<uint32_t>(static_cast<uint8_t>(msg[offset + i * 4 + 2]))758           << 8) |759          (static_cast<uint32_t>(760              static_cast<uint8_t>(msg[offset + i * 4 + 3])));761    }762 763    for (int i = 16; i < 80; i++) {764      w[i] = left_rotate(w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16], 1);765    }766 767    uint32_t a = h0, b = h1, c = h2, d = h3, e = h4;768 769    for (int i = 0; i < 80; i++) {770      uint32_t f, k;771      if (i < 20) {772        f = (b & c) | ((~b) & d);773        k = 0x5A827999;774      } else if (i < 40) {775        f = b ^ c ^ d;776        k = 0x6ED9EBA1;777      } else if (i < 60) {778        f = (b & c) | (b & d) | (c & d);779        k = 0x8F1BBCDC;780      } else {781        f = b ^ c ^ d;782        k = 0xCA62C1D6;783      }784 785      uint32_t temp = left_rotate(a, 5) + f + e + k + w[i];786      e = d;787      d = c;788      c = left_rotate(b, 30);789      b = a;790      a = temp;791    }792 793    h0 += a;794    h1 += b;795    h2 += c;796    h3 += d;797    h4 += e;798  }799 800  // Produce the final hash as a 20-byte binary string801  std::string hash(20, '\0');802  for (size_t i = 0; i < 4; i++) {803    hash[i] = static_cast<char>((h0 >> (24 - i * 8)) & 0xFF);804    hash[4 + i] = static_cast<char>((h1 >> (24 - i * 8)) & 0xFF);805    hash[8 + i] = static_cast<char>((h2 >> (24 - i * 8)) & 0xFF);806    hash[12 + i] = static_cast<char>((h3 >> (24 - i * 8)) & 0xFF);807    hash[16 + i] = static_cast<char>((h4 >> (24 - i * 8)) & 0xFF);808  }809  return hash;810}811 812std::string websocket_accept_key(const std::string &client_key) {813  const std::string magic = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";814  return base64_encode(sha1(client_key + magic));815}816 817bool is_websocket_upgrade(const Request &req) {818  if (req.method != "GET") { return false; }819 820  // Check Upgrade: websocket (case-insensitive)821  auto upgrade_it = req.headers.find("Upgrade");822  if (upgrade_it == req.headers.end()) { return false; }823  auto upgrade_val = case_ignore::to_lower(upgrade_it->second);824  if (upgrade_val != "websocket") { return false; }825 826  // Check Connection header contains "Upgrade"827  auto connection_it = req.headers.find("Connection");828  if (connection_it == req.headers.end()) { return false; }829  auto connection_val = case_ignore::to_lower(connection_it->second);830  if (connection_val.find("upgrade") == std::string::npos) { return false; }831 832  // Check Sec-WebSocket-Key is a valid base64-encoded 16-byte value (24 chars)833  // RFC 6455 Section 4.2.1834  auto ws_key = req.get_header_value("Sec-WebSocket-Key");835  if (ws_key.size() != 24 || ws_key[22] != '=' || ws_key[23] != '=') {836    return false;837  }838  static const std::string b64chars =839      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";840  for (size_t i = 0; i < 22; i++) {841    if (b64chars.find(ws_key[i]) == std::string::npos) { return false; }842  }843 844  // Check Sec-WebSocket-Version: 13845  auto version = req.get_header_value("Sec-WebSocket-Version");846  if (version != "13") { return false; }847 848  return true;849}850 851bool write_websocket_frame(Stream &strm, ws::Opcode opcode,852                                  const char *data, size_t len, bool fin,853                                  bool mask) {854  // First byte: FIN + opcode855  uint8_t header[2];856  header[0] = static_cast<uint8_t>((fin ? 0x80 : 0x00) |857                                   (static_cast<uint8_t>(opcode) & 0x0F));858 859  // Second byte: MASK + payload length860  if (len < 126) {861    header[1] = static_cast<uint8_t>(len);862    if (mask) { header[1] |= 0x80; }863    if (strm.write(reinterpret_cast<char *>(header), 2) < 0) { return false; }864  } else if (len <= 0xFFFF) {865    header[1] = 126;866    if (mask) { header[1] |= 0x80; }867    if (strm.write(reinterpret_cast<char *>(header), 2) < 0) { return false; }868    uint8_t ext[2];869    ext[0] = static_cast<uint8_t>((len >> 8) & 0xFF);870    ext[1] = static_cast<uint8_t>(len & 0xFF);871    if (strm.write(reinterpret_cast<char *>(ext), 2) < 0) { return false; }872  } else {873    header[1] = 127;874    if (mask) { header[1] |= 0x80; }875    if (strm.write(reinterpret_cast<char *>(header), 2) < 0) { return false; }876    uint8_t ext[8];877    for (int i = 7; i >= 0; i--) {878      ext[7 - i] =879          static_cast<uint8_t>((static_cast<uint64_t>(len) >> (i * 8)) & 0xFF);880    }881    if (strm.write(reinterpret_cast<char *>(ext), 8) < 0) { return false; }882  }883 884  if (mask) {885    // Generate random mask key886    thread_local std::mt19937 rng(std::random_device{}());887    uint8_t mask_key[4];888    auto r = rng();889    std::memcpy(mask_key, &r, 4);890    if (strm.write(reinterpret_cast<char *>(mask_key), 4) < 0) { return false; }891 892    // Write masked payload in chunks893    const size_t chunk_size = 4096;894    std::vector<char> buf((std::min)(len, chunk_size));895    for (size_t offset = 0; offset < len; offset += chunk_size) {896      size_t n = (std::min)(chunk_size, len - offset);897      for (size_t i = 0; i < n; i++) {898        buf[i] =899            data[offset + i] ^ static_cast<char>(mask_key[(offset + i) % 4]);900      }901      if (strm.write(buf.data(), n) < 0) { return false; }902    }903  } else {904    if (len > 0) {905      if (strm.write(data, len) < 0) { return false; }906    }907  }908 909  return true;910}911 912} // namespace detail913 914namespace ws {915namespace impl {916 917bool read_websocket_frame(Stream &strm, Opcode &opcode,918                                 std::string &payload, bool &fin,919                                 bool expect_masked, size_t max_len) {920  // Read first 2 bytes921  uint8_t header[2];922  if (strm.read(reinterpret_cast<char *>(header), 2) != 2) { return false; }923 924  fin = (header[0] & 0x80) != 0;925 926  // RSV1, RSV2, RSV3 must be 0 when no extension is negotiated927  if (header[0] & 0x70) { return false; }928 929  opcode = static_cast<Opcode>(header[0] & 0x0F);930  bool masked = (header[1] & 0x80) != 0;931  uint64_t payload_len = header[1] & 0x7F;932 933  // RFC 6455 Section 5.5: control frames MUST NOT be fragmented and934  // MUST have a payload length of 125 bytes or less935  bool is_control = (static_cast<uint8_t>(opcode) & 0x08) != 0;936  if (is_control) {937    if (!fin) { return false; }938    if (payload_len > 125) { return false; }939  }940 941  if (masked != expect_masked) { return false; }942 943  // Extended payload length944  if (payload_len == 126) {945    uint8_t ext[2];946    if (strm.read(reinterpret_cast<char *>(ext), 2) != 2) { return false; }947    payload_len = (static_cast<uint64_t>(ext[0]) << 8) | ext[1];948  } else if (payload_len == 127) {949    uint8_t ext[8];950    if (strm.read(reinterpret_cast<char *>(ext), 8) != 8) { return false; }951    // RFC 6455 Section 5.2: the most significant bit MUST be 0952    if (ext[0] & 0x80) { return false; }953    payload_len = 0;954    for (int i = 0; i < 8; i++) {955      payload_len = (payload_len << 8) | ext[i];956    }957  }958 959  if (payload_len > max_len) { return false; }960 961  // Read mask key if present962  uint8_t mask_key[4] = {0};963  if (masked) {964    if (strm.read(reinterpret_cast<char *>(mask_key), 4) != 4) { return false; }965  }966 967  // Read payload968  payload.resize(static_cast<size_t>(payload_len));969  if (payload_len > 0) {970    size_t total_read = 0;971    while (total_read < payload_len) {972      auto n = strm.read(&payload[total_read],973                         static_cast<size_t>(payload_len - total_read));974      if (n <= 0) { return false; }975      total_read += static_cast<size_t>(n);976    }977  }978 979  // Unmask if needed980  if (masked) {981    for (size_t i = 0; i < payload.size(); i++) {982      payload[i] ^= static_cast<char>(mask_key[i % 4]);983    }984  }985 986  return true;987}988 989} // namespace impl990} // namespace ws991 992namespace detail {993 994bool is_valid_path(const std::string &path) {995  size_t level = 0;996  size_t i = 0;997 998  // Skip slash999  while (i < path.size() && path[i] == '/') {1000    i++;1001  }1002 1003  while (i < path.size()) {1004    // Read component1005    auto beg = i;1006    while (i < path.size() && path[i] != '/') {1007      if (path[i] == '\0') {1008        return false;1009      } else if (path[i] == '\\') {1010        return false;1011      }1012      i++;1013    }1014 1015    auto len = i - beg;1016    assert(len > 0);1017 1018    if (!path.compare(beg, len, ".")) {1019      ;1020    } else if (!path.compare(beg, len, "..")) {1021      if (level == 0) { return false; }1022      level--;1023    } else {1024      level++;1025    }1026 1027    // Skip slash1028    while (i < path.size() && path[i] == '/') {1029      i++;1030    }1031  }1032 1033  return true;1034}1035 1036bool canonicalize_path(const char *path, std::string &resolved) {1037#if defined(_WIN32)1038  char buf[_MAX_PATH];1039  if (_fullpath(buf, path, _MAX_PATH) == nullptr) { return false; }1040  resolved = buf;1041#elif defined(PATH_MAX)1042  char buf[PATH_MAX];1043  if (realpath(path, buf) == nullptr) { return false; }1044  resolved = buf;1045#else1046  auto buf = realpath(path, nullptr);1047  auto guard = scope_exit([&]() { std::free(buf); });1048  if (buf == nullptr) { return false; }1049  resolved = buf;1050#endif1051  return true;1052}1053 1054bool is_path_within_base(const std::string &resolved_path,1055                                const std::string &resolved_base) {1056#if defined(_WIN32)1057  return _strnicmp(resolved_path.c_str(), resolved_base.c_str(),1058                   resolved_base.size()) == 0;1059#else1060  return strncmp(resolved_path.c_str(), resolved_base.c_str(),1061                 resolved_base.size()) == 0;1062#endif1063}1064 1065FileStat::FileStat(const std::string &path) {1066#if defined(_WIN32)1067  auto wpath = u8string_to_wstring(path.c_str());1068  ret_ = _wstat(wpath.c_str(), &st_);1069#else1070  ret_ = stat(path.c_str(), &st_);1071#endif1072}1073bool FileStat::is_file() const {1074  return ret_ >= 0 && S_ISREG(st_.st_mode);1075}1076bool FileStat::is_dir() const {1077  return ret_ >= 0 && S_ISDIR(st_.st_mode);1078}1079 1080time_t FileStat::mtime() const {1081  return ret_ >= 0 ? static_cast<time_t>(st_.st_mtime)1082                   : static_cast<time_t>(-1);1083}1084 1085size_t FileStat::size() const {1086  return ret_ >= 0 ? static_cast<size_t>(st_.st_size) : 0;1087}1088 1089std::string encode_path(const std::string &s) {1090  std::string result;1091  result.reserve(s.size());1092 1093  for (size_t i = 0; s[i]; i++) {1094    switch (s[i]) {1095    case ' ': result += "%20"; break;1096    case '+': result += "%2B"; break;1097    case '\r': result += "%0D"; break;1098    case '\n': result += "%0A"; break;1099    case '\'': result += "%27"; break;1100    case ',': result += "%2C"; break;1101    // case ':': result += "%3A"; break; // ok? probably...1102    case ';': result += "%3B"; break;1103    default:1104      auto c = static_cast<uint8_t>(s[i]);1105      if (c >= 0x80) {1106        result += '%';1107        char hex[4];1108        auto len = snprintf(hex, sizeof(hex) - 1, "%02X", c);1109        assert(len == 2);1110        result.append(hex, static_cast<size_t>(len));1111      } else {1112        result += s[i];1113      }1114      break;1115    }1116  }1117 1118  return result;1119}1120 1121std::string file_extension(const std::string &path) {1122  std::smatch m;1123  thread_local auto re = std::regex("\\.([a-zA-Z0-9]+)$");1124  if (std::regex_search(path, m, re)) { return m[1].str(); }1125  return std::string();1126}1127 1128bool is_space_or_tab(char c) { return c == ' ' || c == '\t'; }1129 1130template <typename T>1131bool parse_header(const char *beg, const char *end, T fn);1132 1133template <typename T>1134bool parse_header(const char *beg, const char *end, T fn) {1135  // Skip trailing spaces and tabs.1136  while (beg < end && is_space_or_tab(end[-1])) {1137    end--;1138  }1139 1140  auto p = beg;1141  while (p < end && *p != ':') {1142    p++;1143  }1144 1145  auto name = std::string(beg, p);1146  if (!detail::fields::is_field_name(name)) { return false; }1147 1148  if (p == end) { return false; }1149 1150  auto key_end = p;1151 1152  if (*p++ != ':') { return false; }1153 1154  while (p < end && is_space_or_tab(*p)) {1155    p++;1156  }1157 1158  if (p <= end) {1159    auto key_len = key_end - beg;1160    if (!key_len) { return false; }1161 1162    auto key = std::string(beg, key_end);1163    auto val = std::string(p, end);1164 1165    if (!detail::fields::is_field_value(val)) { return false; }1166 1167    // RFC 9110 §5.5: header field values are opaque octets and MUST NOT be1168    // percent-decoded by the recipient. Applications that need to interpret a1169    // value as a URI component should call httplib::decode_uri_component()1170    // (or decode_path_component()) explicitly.1171    fn(key, val);1172 1173    return true;1174  }1175 1176  return false;1177}1178 1179bool parse_trailers(stream_line_reader &line_reader, Headers &dest,1180                           const Headers &src_headers) {1181  // NOTE: In RFC 9112, '7.1 Chunked Transfer Coding' mentions "The chunked1182  // transfer coding is complete when a chunk with a chunk-size of zero is1183  // received, possibly followed by a trailer section, and finally terminated by1184  // an empty line". https://www.rfc-editor.org/rfc/rfc9112.html#section-7.11185  //1186  // In '7.1.3. Decoding Chunked', however, the pseudo-code in the section1187  // doesn't care for the existence of the final CRLF. In other words, it seems1188  // to be ok whether the final CRLF exists or not in the chunked data.1189  // https://www.rfc-editor.org/rfc/rfc9112.html#section-7.1.31190  //1191  // According to the reference code in RFC 9112, cpp-httplib now allows1192  // chunked transfer coding data without the final CRLF.1193 1194  // RFC 7230 Section 4.1.2 - Headers prohibited in trailers1195  thread_local case_ignore::unordered_set<std::string> prohibited_trailers = {1196      "transfer-encoding",1197      "content-length",1198      "host",1199      "authorization",1200      "www-authenticate",

Showing the first 1,200 of 17357 lines. Download the file for the rest.