#include "Includes/VWeb.h" #include "StringUtils.h" namespace VWeb { void Cookies::Remove(const std::string &name) { if (Data.contains(name)) Data.erase(name); } bool Cookies::Has(const std::string &name) const { return Data.contains(name); } std::string Cookies::TransformToHeader() { std::stringstream view{}; for (auto &cookie : Data) { auto &realCookie = cookie.second; if (!realCookie.IsOld && !realCookie.Name.empty() && !realCookie.Value.empty()) CookieToString(view, realCookie); } return view.str(); } void Cookies::CreateCookieFromString(const std::string &data) { auto params = String::Split(data, ";"); Cookie cookie{}; int i = 0; for (auto ¶m : params) { auto split = String::Split(param, "="); if (split.size() == 1) { // we have a bool parameter if (split[0] == "HttpOnly") cookie.HttpOnly = true; else if (split[0] == "Secure") cookie.Secure = true; } else { if (i == 0) { cookie.Name = split[0]; cookie.Value = split[1]; } else { if (split[0] == "SameSite") { if (split[1] == "None") cookie.SameSite = CookieSameSite::None; else if (split[1] == "Lax") cookie.SameSite = CookieSameSite::Lax; else if (split[1] == "Strict") cookie.SameSite = CookieSameSite::Strict; } else if (split[0] == "Path") cookie.Path = split[1]; else if (split[0] == "Domain") cookie.Domain = split[1]; else if (split[0] == "Max-Age") cookie.MaxAge = String::ToNumber(split[1], 0); else if (split[0] == "Expires") cookie.Expires = split[1]; } } i++; } if (!cookie.Name.empty() && !cookie.Value.empty()) Data[cookie.Name] = std::move(cookie); } void Cookies::CreateOld(const std::string &name, const std::string &value) { auto& cookie = Data[name]; cookie.Name = name; cookie.Value = value; cookie.IsOld = true; } void Cookies::CookieToString(std::stringstream &stream, Cookie &cookie) { if (cookie.Name.empty() || cookie.Value.empty()) return; std::stringstream view{}; // Cookie names that are starting with __Secure or __Host are Secure only // Cookies! if (cookie.Name.starts_with("__Secure")) cookie.Secure = true; if (cookie.Name.starts_with("__Host")) { cookie.Secure = true; if (cookie.Path.empty()) cookie.Path = "/"; } view << "Set-Cookie: " << cookie.Name << "=" << cookie.Value; if (!cookie.Expires.empty()) view << "; Expires=" << cookie.Expires; if (cookie.MaxAge) view << "; Max-Age=" << cookie.MaxAge; if (!cookie.Domain.empty()) view << "; Domain=" << cookie.Domain; if (!cookie.Path.empty()) view << "; Path=" << cookie.Path; if (cookie.Secure || cookie.SameSite == CookieSameSite::None) view << "; Secure"; if (cookie.HttpOnly) view << "; HttpOnly"; if (cookie.SameSite != CookieSameSite::Invalid) { std::string sameSiteValue; switch (cookie.SameSite) { case CookieSameSite::None: sameSiteValue = "None"; break; case CookieSameSite::Strict: sameSiteValue = "Strict"; break; case CookieSameSite::Lax: sameSiteValue = "Lax"; break; default: break; } view << "; SameSite=" << sameSiteValue; } view << "\n"; stream << view.str(); } } // namespace VWeb