#pragma once #include #include #include using std::string_view; struct Cookie { string_view name; string_view value; Cookie(string_view n, string_view v) : name(n), value(v) {} }; class CookieParser { public: static std::vector parse(string_view cookie_header) { std::vector cookies; const char* ptr = cookie_header.data(); const char* end = ptr + cookie_header.size(); while (ptr < end) { // Skip whitespace and semicolons while (ptr < end && (*ptr == ' ' || *ptr == ';')) ptr++; if (ptr >= end) break; // Find name end (=) const char* name_start = ptr; while (ptr < end && *ptr != '=' && *ptr != ';') ptr++; if (ptr >= end || *ptr != '=') break; string_view name(name_start, ptr - name_start); ptr++; // Skip '=' // Find value end (; or end) const char* value_start = ptr; while (ptr < end && *ptr != ';') ptr++; string_view value(value_start, ptr - value_start); // Trim whitespace from name and value name = trim(name); value = trim(value); if (!name.empty()) { cookies.emplace_back(name, value); } } return cookies; } private: static string_view trim(string_view str) { const char* start = str.data(); const char* end = start + str.size(); // Trim leading whitespace while (start < end && *start == ' ') start++; // Trim trailing whitespace while (end > start && *(end - 1) == ' ') end--; return string_view(start, end - start); } }; // Cookie helpers for request/response handling class CookieHelpers { public: // Get cookie value from request, returns empty string_view if not found static string_view get_cookie(const std::vector& cookies, string_view name) { for (const auto& cookie : cookies) { if (cookie.name == name) { return cookie.value; } } return {}; } // Build Set-Cookie header value static std::string build_set_cookie(string_view name, string_view value, int max_age = -1, string_view path = "", string_view domain = "", bool secure = false, bool http_only = false) { std::string result; result.reserve(256); result += name; result += "="; result += value; if (max_age >= 0) { result += "; Max-Age="; result += std::to_string(max_age); } if (!path.empty()) { result += "; Path="; result += path; } if (!domain.empty()) { result += "; Domain="; result += domain; } if (secure) { result += "; Secure"; } if (http_only) { result += "; HttpOnly"; } return result; } // Build delete cookie header (expires immediately) static std::string build_delete_cookie(string_view name, string_view path = "") { std::string result; result.reserve(128); result += name; result += "=; Max-Age=0"; if (!path.empty()) { result += "; Path="; result += path; } return result; } };