/* TessesFramework a library to make C++ easier for me, used in CrossLang: https://git.tesses.org/tesses50/crosslang Copyright (C) 2026 Mike Nolan This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #pragma once #include "../Common.hpp" #include "../Date/Date.hpp" #include namespace Tesses::Framework::Http { typedef enum StatusCode { Continue = 100, SwitchingProtocols = 101, Processing = 102, EarlyHints = 103, OK = 200, Created = 201, Accepted = 202, NonAuthoritativeInformation = 203, NoContent = 204, ResetContent = 205, PartialContent = 206, MultiStatus = 207, AlreadyReported = 208, IMUsed = 226, MultipleChoices = 300, MovedPermanently = 301, Found = 302, SeeOther = 303, NotModified = 304, UseProxy = 305, TemporaryRedirect = 307, PermanentRedirect = 308, BadRequest = 400, Unauthorized = 401, PaymentRequired = 402, Forbidden = 403, NotFound = 404, MethodNotAllowed = 405, NotAcceptable = 406, ProxyAuthenticationRequired = 407, RequestTimeout = 408, Conflict = 409, Gone = 410, LengthRequired = 411, PreconditionFailed = 412, PayloadTooLarge = 413, URITooLong = 414, UnsupportedMediaType = 415, RangeNotSatisfiable = 416, ExpectationFailed = 417, ImATeapot = 418, MisdirectedRequest = 421, UnprocessableContent = 422, Locked = 423, FailedDependency = 424, TooEarly = 425, UpgradeRequired = 426, PreconditionRequired = 428, TooManyRequests = 429, RequestHeaderFieldsTooLarge = 431, UnavailableForLegalReasons = 451, InternalServerError = 500, NotImplemented = 501, BadGateway = 502, ServiceUnavailable = 503, GatewayTimeout = 504, HTTPVersionNotSupported = 505, VariantAlsoNegotiates = 506, InsufficientStorage = 507, LoopDetected = 508, NotExtended = 510, NetworkAuthenticationRequired = 511 } StatusCode; struct CaseInsensitiveLess { CaseInsensitiveLess(const CaseInsensitiveLess &str); CaseInsensitiveLess(); CaseInsensitiveLess *offset; bool caseSensitive; bool operator()(const std::string &s1, const std::string &s2) const; }; class HttpDictionary { public: HttpDictionary(); HttpDictionary(bool caseSensitive); std::map, CaseInsensitiveLess> kvp; void SetCaseSensitive(bool isCaseSensitive); void Clear(); void Clear(std::string key, bool kvpExistsAfter); void SetValue(std::string key, std::string value); void SetValue(std::string key, int64_t v); void SetValue(std::string key, double v); void SetValue(std::string key, Date::DateTime v); void SetValue(std::string key, std::vector value); template void SetValue(std::string key, Itterator begin, Itterator end) { Clear(key, true); AddValue(key, begin, end); } void AddValue(std::string key, std::string value); void AddValue(std::string key, int64_t v); void AddValue(std::string key, double v); void AddValue(std::string key, Date::DateTime v); void AddValue(std::string key, std::vector value); template void AddValue(std::string key, Itterator begin, Itterator end) { auto &ls = kvp[key]; ls.insert(ls.end(), begin, end); } bool TryGetFirst(std::string key, std::string &value); bool TryGetFirstInt(std::string key, int64_t &value); bool TryGetFirstDouble(std::string key, double &value); bool TryGetFirstDate(std::string key, Date::DateTime &value); bool GetFirstBoolean(std::string key); bool AnyEquals(std::string key, std::string value); }; class Uri { public: Uri(); std::string GetQuery(); std::string GetPathAndQuery(); uint16_t GetPort(); std::string HostPort(); bool Relative(std::string url, Uri &uri); std::string ToString(); static bool TryParse(std::string url, Uri &uri); std::string scheme; std::string host; uint16_t port; std::string path; HttpDictionary query; std::string hash; }; class HttpUtils { public: static char NibbleToHex(uint8_t b, bool isUppercase); static char NibbleToHex(uint8_t nibble); static uint8_t HexToNibble(char c); static std::string BytesToHex(const std::vector &data); static void BytesToHex(std::string &text, const std::vector &data); static std::string BytesToHex(const std::vector &data, bool isUppercase); static void BytesToHex(std::string &text, const std::vector &data, bool isUppercase); static std::vector HexToBytes(const std::string &text); static void HexToBytes(std::vector &data, const std::string &text); static std::string MimeType(std::filesystem::path p); static bool Invalid(char c); static std::string Sanitise(std::string text); static void QueryParamsDecode(HttpDictionary &dict, std::string query); static std::string Join(std::string joinStr, std::vector ents); static std::string QueryParamsEncode(HttpDictionary &dict); static std::string UrlDecode(std::string v); static std::string UrlEncode(std::string v); static std::string UrlPathDecode(std::string v); static std::string UrlPathEncode(std::string v, bool ignoreSpace = false); static std::string HtmlEncode(std::string v); static std::string HtmlP(std::string text); static std::string HtmlDecodeOnlyEntityNumber(std::string v); static std::vector SplitString(std::string text, std::string delimiter, std::size_t maxCnt = std::string::npos); static std::string Replace(std::string str, std::string find, std::string replace); static std::string StatusCodeString(StatusCode code); static std::string ToLower(std::string str); static std::string ToUpper(std::string str); static std::string LeftPad(std::string text, int count, char c); }; } // namespace Tesses::Framework::Http