137 lines
2.8 KiB
C++
137 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <string_view>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
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<Cookie> parse(string_view cookie_header) {
|
|
std::vector<Cookie> 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<Cookie>& 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;
|
|
}
|
|
};
|