Fix license compliance and fix things up, add reverse proxy, fix some security flaws with HttpUtils
Some checks failed
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-arm64:latest, aarch64-linux-gnu, arm64) (push) Successful in 2m37s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-arm:latest, arm-linux-gnueabihf, arm7) (push) Successful in 2m37s
Build and Deploy on Tag / 🔨 Build for PowerPC (push) Successful in 2m58s
Build and Deploy on Tag / 🔨 Build win32 and update the tap 🍺 (push) Failing after 3m36s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-riscv64:latest, riscv64-linux-gnu, riscv64) (push) Successful in 2m19s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-x64:latest, x86_64-linux-gnu, amd64) (push) Successful in 2m21s
Build and Deploy on Tag / 🔨 Build for everything else (git.tesses.org/tesses50/linux-x86:latest, i386-linux-gnu, 386) (push) Successful in 2m6s

This commit is contained in:
2026-08-31 20:57:18 -05:00
parent 313e75b14c
commit 3bce736834
41 changed files with 2227 additions and 384 deletions

View File

@@ -21,6 +21,7 @@
#pragma once
#include "../Streams/Stream.hpp"
#include "Crypto.hpp"
namespace Tesses::Framework::Crypto {
/**
@@ -59,6 +60,32 @@ class ClientTLSStream : public Tesses::Framework::Streams::Stream {
ClientTLSStream(
std::shared_ptr<Tesses::Framework::Streams::Stream> innerStream,
bool verify, std::string domain, std::string cert);
/**
* @brief Construct a new Client TLS Stream object, with mTLS
*
* @param innerStream the underlying encrypted in transit stream
* @param verify do we verify the certificate
* @param domain the domain name
* @param keyStore the keystore for mTLS
*/
ClientTLSStream(
std::shared_ptr<Tesses::Framework::Streams::Stream> innerStream,
bool verify, std::string domain, CertificateKeyStore keyStore);
/**
* @brief Construct a new Client TLS Stream object with an alternative
* certificate chain (for server with self signed certificates) for mTLS
*
* @param innerStream the underlying encrypted in transit stream
* @param verify do we verify the certificate
* @param domain the domain name
* @param cert the actual certificate
* @param keyStore the keystore for mTLS
*/
ClientTLSStream(
std::shared_ptr<Tesses::Framework::Streams::Stream> innerStream,
bool verify, std::string domain, std::string cert,
CertificateKeyStore keyStore);
/**
* @brief Read from the stream
*
@@ -96,6 +123,10 @@ class ClientTLSStream : public Tesses::Framework::Streams::Stream {
* @return false no
*/
bool EndOfStream();
void Shutdown(Tesses::Framework::Streams::StreamShutdownMode sdm);
void SetSendTimeout(uint64_t seconds);
void SetRecvTimeout(uint64_t seconds);
~ClientTLSStream();
};

View File

@@ -316,6 +316,29 @@ typedef enum {
*/
bool PBKDF2(std::vector<uint8_t> &output, std::string pass,
std::vector<uint8_t> &salt, long itterations, ShaVersion version);
/**
* @brief Get secure random bytes
*
* @param output The buffer to write random bytes to
* @param personal_str Some string to ensure the rng is unique (for mbedtls at
* least)
* @return true successfully generated the bytes
* @return false we failed to generate the bytes
*/
bool RandomBytes(std::vector<uint8_t> &output, std::string personal_str);
struct CertificateKeyStore {
CertificateKeyStore() = default;
CertificateKeyStore(std::string certificate, std::string key,
std::optional<std::string> chain = std::nullopt,
std::string password = "")
: certificate(certificate), key(key), chain(chain), password(password) {
}
std::string certificate;
std::string key;
std::optional<std::string> chain;
std::string password;
};
} // namespace Tesses::Framework::Crypto

View File

@@ -26,9 +26,23 @@
namespace Tesses::Framework::Date {
/**
* @brief Get the time zone in seconds from UTC
*
* @return int the utc distance in seconds, west
*/
int GetTimeZone();
/**
* @brief Does the timezone support daylight savings
*
* @return true yes
* @return false no
*/
bool TimeZoneSupportDST();
/**
* @brief Stores a DateTime
*
*/
class DateTime {
int year = 1970;
int month = 1;
@@ -41,83 +55,413 @@ class DateTime {
void FromEpochNoConvert(int64_t gmt);
public:
/**
* @brief Construct a new Date Time object with Jan 1, 1970 at 12:00AM UTC
*
*/
DateTime();
/**
* @brief Construct a new Date Time object
*
* @param year the year
* @param month the month (1-12)
* @param day the day (1-31)
* @param hour the hour (0-23)
* @param minute the minute (0-59)
* @param seconds the second (0-59)
* @param isLocal true: your timezone, false: utc
*/
DateTime(int year, int month, int day, int hour, int minute, int seconds,
bool isLocal = true);
/**
* @brief Construct a new DateTime object
*
* @param epoch seconds since Jan 1, 1970 at 12:00AM UTC
*/
DateTime(int64_t epoch);
/**
* @brief Get the year
*
* @return int ex 1992 means the year is 1992
*/
int Year() const;
/**
* @brief Get the month (1-12)
*
* @return int ex 8 means august
*/
int Month() const;
/**
* @brief Get the day (1-31)
*
* @return int ex 20 means the day is the 20th
*/
int Day() const;
/**
* @brief Get the hour (0-23)
*
* @return int ex 12 means noon, 0 means midnight, 18 means 6 PM
*/
int Hour() const;
/**
* @brief Get the minute (0-59)
*
* @return int ex 15 means quarter after the hour
*/
int Minute() const;
/**
* @brief Get the second (0-59)
*
* @return int the seconds value
*/
int Second() const;
/**
* @brief Get the day of week (0-6)
*
* @retval 0 Sunday
* @retval 1 Monday
* @retval 2 Tuesday
* @retval 3 Wednesday
* @retval 4 Thursday
* @retval 5 Friday
* @retval 6 Saturday
*/
int DayOfWeek() const;
/**
* @brief Is local timezone
*
* @return true yes
* @return false no
*/
bool IsLocal() const;
/**
* @brief Get the time as epoch
*
* @return int64_t seconds since Jan 1, 1970 at 12:00AM UTC
*/
int64_t ToEpoch() const;
/**
* @brief Convert this time to local time
*
* @return DateTime this time in local time
*/
DateTime ToLocal() const;
/**
* @brief Convert this time to utc time
*
* @return DateTime this time in UTC time
*/
DateTime ToUTC() const;
/**
* @brief Set this time to local
*
*/
void SetToLocal();
/**
* @brief Set this time to UTC
*
*/
void SetToUTC();
/**
* @brief Set the current year
*
* @param y year
*/
void SetYear(int y);
/**
* @brief Set the current month (1-12)
*
* @param m month
*/
void SetMonth(int m);
/**
* @brief Set the current day (1-31)
*
* @param d day
*/
void SetDay(int d);
/**
* @brief Set the current hour (0-23)
*
* @param h hour
*/
void SetHour(int h);
/**
* @brief Set the current minute (0-59)
*
* @param m minute
*/
void SetMinute(int m);
/**
* @brief Set the current second (0-59)
*
* @param s second
*/
void SetSecond(int s);
/**
* @brief Set whether this time is local or utc
*
* @param local true set this time to localtime or false set this time to
* utc
*/
void SetLocal(bool local);
/**
* @brief Set the seconds since Jan 1, 1970 at 12:00AM UTC
*
* @param epoch seconds since Jan 1, 1970 at 12:00AM UTC
*/
void Set(int64_t epoch);
/**
* @brief Set the time of this DateTime object
*
* @param year the year
* @param month the month (1-12)
* @param day the day (1-31)
* @param hour the hour (0-23)
* @param minute the minute (0-59)
* @param seconds the second (0-59)
* @param isLocal true: your timezone, false: utc
*/
void Set(int year, int month, int day, int hour, int minute, int seconds,
bool isLocal = true);
/**
* @brief Set this DateTime to right now in your timezone
*
*/
void SetToNow();
/**
* @brief Set this DateTime to right now in utc
*
*/
void SetToNowUTC();
/**
* @brief Construct a datetime from right now in your timezone
*
* @return DateTime the current time object
*/
static DateTime Now();
/**
* @brief Construct a datetime from right now in your timezone
*
* @return DateTime the current time object
*/
static DateTime NowUTC();
/**
* @brief Convert date to string same as ToString("%Y/%m/%d %H:%M:%S")
*
* @return std::string the date as string
*/
std::string ToString() const;
/**
* @brief Convert date to string with your own fmt
*
* @param fmt the format, see:
* https://git.tesses.org/tesses50/tessesframework/wiki/DateTime_ToString_Formating
* for more details
* @return std::string the date as a string based on fmt
*/
std::string ToString(std::string fmt) const;
/**
* @brief Format as IMF-fixdate (RFC 9110 §5.6.7)
*
* Example: "Tue, 01 Sep 2026 18:07:05 GMT"
*/
std::string ToHttpDate() const;
static bool TryParseHttpDate(std::string txt, DateTime &dt);
/**
* @brief Tries to parse an IMF-fixdate (RFC 9110 §5.6.7) date into a
* DateTime
*
* @param txt example "Tue, 01 Sep 2026 18:07:05 GMT"
* @param dt a reference to a datetime
* @return true we did parse the date correctly
* @return false we didn't parse the date correctly
*/
static bool TryParseHttpDate(std::string_view txt, DateTime &dt);
/**
* @brief Tries to parse an IMF-fixdate (RFC 9110 §5.6.7) date into the
* DateTime
*
* @param txt example "Tue, 01 Sep 2026 18:07:05 GMT"
* @return true we did parse the date correctly
* @return false we didn't parse the date correctly
*/
bool TryParseHttpDate(std::string_view txt);
};
/**
* @brief Stores a time offset in seconds
*
*/
class TimeSpan {
int64_t totalSeconds;
public:
/**
* @brief Construct a new TimeSpan with 0 seconds
*
*/
TimeSpan();
/**
* @brief Construct a new TimeSpan object with totalSeconds
*
*/
TimeSpan(int64_t totalSeconds);
/**
* @brief Construct a new TimeSpan object with hours, minutes and seconds
*
*/
TimeSpan(int hours, int minutes, int seconds);
/**
* @brief Construct a new TimeSpan object with days, hours, minutes and
* seconds
*
*/
TimeSpan(int days, int hours, int minutes, int seconds);
/**
* @brief Set the timespan with new days, hours, minutes and seconds
*
*/
void Set(int days, int hours, int minutes, int seconds);
/**
* @brief Set the timespan with new hours, minutes and seconds
*
*/
void Set(int hours, int minutes, int seconds);
/**
* @brief Set the days component (hours, minutes, seconds unchanged)
*/
void SetDays(int d);
/**
* @brief Set the hours component (days, minutes, seconds unchanged)
*/
void SetHours(int h);
/**
* @brief Set the minutes component (days, hours, seconds unchanged)
*/
void SetMinutes(int m);
/**
* @brief Set the seconds component (days, hours, minutes unchanged)
*/
void SetSeconds(int s);
/**
* @brief Get the days of the timespan
*
*/
int Days() const;
/**
* @brief Get the hours of the timespan
*
*/
int Hours() const;
/**
* @brief Get the minutes of the timespan
*
*/
int Minutes() const;
/**
* @brief Get the seconds of the timespan
*
*/
int Seconds() const;
/**
* @brief Get the total seconds of the timespan
*
*/
int64_t TotalSeconds() const;
/**
* @brief Get the total minutes of the timespan
*
*/
int64_t TotalMinutes() const;
/**
* @brief Get the total hours of the timespan
*
*/
int64_t TotalHours() const;
/**
* @brief Set the total seconds of the timespan, removing any old value
*
*/
void SetTotalSeconds(int64_t totalSeconds);
/**
* @brief Set the total minutes of the timespan, removing any old value
*
*/
void SetTotalMinutes(int64_t totalMinutes);
/**
* @brief Set the total hours of the timespan, removing any old value
*
*/
void SetTotalHours(int64_t totalHours);
/**
* @brief Set the total days of the timespan, removing any old value
*
*/
void SetTotalDays(int64_t totalHours);
/**
* @brief Add seconds to the timespan
*
*/
void AddSeconds(int64_t seconds);
/**
* @brief Add minutes to the timespan
*
*/
void AddMinutes(int64_t minutes);
/**
* @brief Add hours to the timespan
*
*/
void AddHours(int64_t hours);
/**
* @brief Add days to the timespan
*
*/
void AddDays(int64_t days);
/**
* @brief Converts the timespan to string
*
* @param slim If true, omits leading zeros (e.g. "1:00", "10:00",
* "1:00:00"). If false, always zero-pads (e.g. "00:00:00") unless there are
* days.
*/
std::string ToString(bool slim = true) const;
static bool TryParse(std::string text, TimeSpan &span);
/**
* @brief Try to parse a TimeSpan from a string
*
* @param text the string to parse
* @param span receives the parsed TimeSpan on success
* @return true we parsed successfully
* @return false we failed to parse
*/
static bool TryParse(std::string_view text, TimeSpan &span);
/**
* @brief Try to parse this timespan from string
*
* @param text the string to parse
* @return true we parsed successfully
* @return false we failed to parse
*/
bool TryParse(std::string_view text);
/**
* @brief Create a timespan with seconds, same as ctor
*
*/
static TimeSpan FromSeconds(int64_t seconds);
/**
* @brief Create a timespan with minutes
*
*/
static TimeSpan FromMinutes(int64_t minutes);
/**
* @brief Create a timespan with hours
*
*/
static TimeSpan FromHours(int64_t hours);
/**
* @brief Create a timespan with days
*
*/
static TimeSpan FromDays(int64_t days);
};
inline DateTime operator+(const DateTime &dt, const TimeSpan &ts) {

View File

@@ -24,13 +24,47 @@
#include "VFSFix.hpp"
namespace Tesses::Framework::Filesystem::Helpers {
/** @brief Read all of the text from a file
* @param vfs the VFS you want to use
* @param path the path to the file in the VFS
* @param text the file's contents
*/
void ReadAllText(std::shared_ptr<VFS> vfs, VFSPath path, std::string &text);
/**
* @brief Read all of the lines from a file
*
* @param vfs the VFS you want to use
* @param path the path to the file in the VFS
* @param lines the file's lines
*/
void ReadAllLines(std::shared_ptr<VFS> vfs, VFSPath path,
std::vector<std::string> &lines);
/**
* @brief Read all of the bytes from a file
*
* @param vfs the VFS you want to use
* @param path the path to the file in the VFS
* @param array the file's contents
*/
void ReadAllBytes(std::shared_ptr<VFS> vfs, VFSPath path,
std::vector<uint8_t> &array);
/**
* @brief Read all of the text from a file
*
* @param vfs the VFS you want to use
* @param path the path to the file in the VFS
* @return std::string the file's contents
*/
std::string ReadAllText(std::shared_ptr<VFS> vfs, VFSPath path);
/**
* @brief Read all of the lines from a file
*
* @param vfs the VFS you want to use
* @param path the path to the file in the VFS
* @return std::vector<std::string> the file's lines
*/
std::vector<std::string> ReadAllLines(std::shared_ptr<VFS> vfs, VFSPath path);
std::vector<uint8_t> ReadAllBytes(std::shared_ptr<VFS> vfs, VFSPath path);
void WriteAllText(std::shared_ptr<VFS> vfs, VFSPath path,
const std::string &text);

View File

@@ -38,8 +38,8 @@ class HiddenField {
HiddenField(HiddenFieldData *data);
void SetField(HiddenFieldData *data);
template <typename T> T GetField() { return dynamic_cast<T>(ptr); }
template <typename T> T *AllocField() {
auto v = new T();
template <typename T, typename... TArgs> T *AllocField(TArgs &&...args) {
auto v = new T(std::forward<TArgs>(args)...);
SetField(v);
return v;
}

View File

@@ -24,11 +24,15 @@
namespace Tesses::Framework::Http {
class ChangeableServer {
std::shared_ptr<IHttpServer> server;
Tesses::Framework::Threading::Mutex mtx;
public:
ChangeableServer();
ChangeableServer(std::shared_ptr<IHttpServer> original);
std::shared_ptr<IHttpServer> server;
bool Handle(ServerContext &ctx);
void SetServer(std::shared_ptr<IHttpServer> server);
std::shared_ptr<IHttpServer> GetServer();
~ChangeableServer();
};
} // namespace Tesses::Framework::Http

View File

@@ -0,0 +1,41 @@
/*
TessesFramework a library to make C++ easier for me, used in CrossLang:
https://git.tesses.org/tesses50/crosslang
Copyright (C) 2026 Mike Nolan
SPDX-License-Identifier: GPL-3.0-or-later WITH TessesFramework-Exception-1.0
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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "../Filesystem/VFS.hpp"
#include "../Filesystem/VFSFix.hpp"
#include "HttpServer.hpp"
namespace Tesses::Framework::Http {
class DomainServer : public IHttpServer {
std::shared_ptr<IHttpServer> root;
std::map<std::string, std::shared_ptr<IHttpServer>> servers;
Tesses::Framework::Threading::Mutex mtx;
public:
DomainServer();
DomainServer(std::shared_ptr<IHttpServer> root);
void Set(std::string domain, std::shared_ptr<IHttpServer> server);
void Unset(std::string domain);
void Clear();
bool Handle(ServerContext &ctx);
};
} // namespace Tesses::Framework::Http

View File

@@ -20,6 +20,7 @@
*/
#pragma once
#include "../Crypto/Crypto.hpp"
#include "../Streams/Stream.hpp"
#include "HttpUtils.hpp"
// clang-format off
@@ -66,6 +67,7 @@ class HttpRequest {
public:
HttpRequest();
std::string trusted_root_cert_bundle;
std::optional<Crypto::CertificateKeyStore> mTLS_keyStore;
bool ignoreSSLErrors;
bool followRedirects;
@@ -73,15 +75,17 @@ class HttpRequest {
std::string url;
std::string unixSocket;
HttpDictionary requestHeaders;
HttpRequestBody *body;
std::shared_ptr<HttpRequestBody> body;
static std::shared_ptr<Tesses::Framework::Streams::Stream>
EstablishConnection(Uri uri, bool ignoreSSLErrors,
std::string trusted_root_cert_bundle);
EstablishConnection(
Uri uri, bool ignoreSSLErrors, std::string trusted_root_cert_bundle,
std::optional<Crypto::CertificateKeyStore> mTLS_keyStore);
static std::shared_ptr<Tesses::Framework::Streams::Stream>
EstablishUnixPathConnection(std::string unixPath, Uri uri,
bool ignoreSSLErrors,
std::string trusted_root_cert_bundle);
EstablishUnixPathConnection(
std::string unixPath, Uri uri, bool ignoreSSLErrors,
std::string trusted_root_cert_bundle,
std::optional<Crypto::CertificateKeyStore> mTLS_keyStore);
void SendRequest(std::shared_ptr<Tesses::Framework::Streams::Stream> strm);
};

View File

@@ -0,0 +1,84 @@
/*
TessesFramework a library to make C++ easier for me, used in CrossLang:
https://git.tesses.org/tesses50/crosslang
Copyright (C) 2026 Mike Nolan
SPDX-License-Identifier: GPL-3.0-or-later WITH TessesFramework-Exception-1.0
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 <https://www.gnu.org/licenses/>.
*/
#pragma once
#include "HttpClient.hpp"
#include "HttpServer.hpp"
#include <unordered_set>
namespace Tesses::Framework::Http {
enum class ReverseProxyAction { Continue, Handled, Unhandled };
class ReverseProxyConnectionBuilder {
public:
ReverseProxyConnectionBuilder(const ReverseProxyConnectionBuilder &b) =
delete;
ReverseProxyConnectionBuilder &
operator=(const ReverseProxyConnectionBuilder &b) = delete;
ReverseProxyConnectionBuilder(ReverseProxyConnectionBuilder &&b) = delete;
ReverseProxyConnectionBuilder &
operator=(ReverseProxyConnectionBuilder &&b) = delete;
ReverseProxyConnectionBuilder(ServerContext &ctx,
bool essentalheaders = true);
ReverseProxyConnectionBuilder &WithHeadersFromRequest();
ReverseProxyConnectionBuilder &WithHeader(std::string key,
std::string value);
ReverseProxyConnectionBuilder &SetHeader(std::string key,
std::string value);
ReverseProxyConnectionBuilder &WithoutHeader(std::string key);
ReverseProxyConnectionBuilder &WithUrl(std::string url);
ReverseProxyConnectionBuilder &WithResponseCallback(
std::function<ReverseProxyAction(ServerContext &, HttpResponse &)> rc);
ReverseProxyConnectionBuilder &
WithWhitelistedUpgrade(std::string protocol = "websocket");
bool Handle();
private:
ServerContext &m_ctx;
std::optional<std::string> m_url;
HttpDictionary m_reqheaders;
std::unordered_set<std::string> m_whitelistedupgrades;
std::function<ReverseProxyAction(ServerContext &, HttpResponse &)> m_rc;
bool m_fail = false;
};
class ReverseProxyServer : public IHttpServer {
private:
std::string url;
std::function<ReverseProxyAction(ServerContext &,
ReverseProxyConnectionBuilder &, Uri &)>
request_callback;
std::function<ReverseProxyAction(ServerContext &, HttpResponse &)>
response_callback;
bool essentialheaders;
public:
ReverseProxyServer(
std::string url,
std::function<ReverseProxyAction(
ServerContext &, ReverseProxyConnectionBuilder &, Uri &)>
request_callback = nullptr,
std::function<ReverseProxyAction(ServerContext &, HttpResponse &)>
response_callback = nullptr,
bool essentialheaders = true);
bool Handle(ServerContext &ctx);
};
} // namespace Tesses::Framework::Http

View File

@@ -22,6 +22,9 @@
#pragma once
#include "../Common.hpp"
#include "../Date/Date.hpp"
#include "../Filesystem/VFS.hpp"
#include "../Filesystem/VFSFix.hpp"
#include <algorithm>
namespace Tesses::Framework::Http {
@@ -91,9 +94,7 @@ typedef enum StatusCode {
} StatusCode;
struct CaseInsensitiveLess {
CaseInsensitiveLess(const CaseInsensitiveLess &str);
CaseInsensitiveLess();
CaseInsensitiveLess *offset;
explicit CaseInsensitiveLess(bool caseSensitive);
bool caseSensitive;
bool operator()(const std::string &s1, const std::string &s2) const;
};
@@ -136,7 +137,17 @@ class HttpDictionary {
bool GetFirstBoolean(std::string key);
bool TryGetOnlyOne(std::string key, std::string &value);
bool TryGetOnlyOneInt(std::string key, int64_t &value);
bool TryGetOnlyOneDouble(std::string key, double &value);
bool TryGetOnlyOneDate(std::string key, Date::DateTime &value);
bool TryGetOnlyOneBoolean(std::string key, bool &value);
bool AnyEquals(std::string key, std::string value);
bool AnyEqualsCSV(std::string key, std::string value);
};
class Uri {
@@ -169,30 +180,40 @@ class HttpUtils {
bool isUppercase);
static void BytesToHex(std::string &text, const std::vector<uint8_t> &data,
bool isUppercase);
static std::vector<uint8_t> HexToBytes(const std::string &text);
static void HexToBytes(std::vector<uint8_t> &data, const std::string &text);
static std::string MimeType(std::filesystem::path p);
static std::vector<uint8_t> HexToBytes(std::string_view text);
static void HexToBytes(std::vector<uint8_t> &data, std::string_view text);
static std::string GetMimeType(const std::string &ext);
static std::string GetMimeTypePath(const Filesystem::VFSPath &pathWithExt);
static void AddMimeType(const std::string &ext, const std::string &mime);
static void AddMimeTypePath(const Filesystem::VFSPath &pathWithExt,
const std::string &mime);
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<std::string> ents);
static std::string Sanitise(std::string_view text);
static void QueryParamsDecode(HttpDictionary &dict, std::string_view query);
static std::string Join(std::string_view joinStr,
std::vector<std::string> 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::string UrlDecode(std::string_view v);
static std::string UrlEncode(std::string_view v);
static std::string UrlPathDecode(std::string_view v);
static std::string UrlPathEncode(std::string_view v,
bool ignoreSpace = false);
static std::string HtmlEncode(std::string_view v);
static std::string HtmlP(std::string_view text);
static void SplitString(std::vector<std::string> &out,
std::string_view text, std::string_view delimiter,
std::size_t maxCnt = std::string::npos);
static std::vector<std::string>
SplitString(std::string text, std::string delimiter,
SplitString(std::string_view text, std::string_view delimiter,
std::size_t maxCnt = std::string::npos);
static std::string Replace(std::string str, std::string find,
std::string replace);
static std::string Replace(std::string_view str, std::string_view find,
std::string_view 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);
static std::string ToLower(std::string_view str);
static std::string ToUpper(std::string_view str);
static std::string LeftPad(std::string_view text, int count, char c);
static bool CaseInsensitiveCompare(std::string_view left,
std::string_view right);
};
} // namespace Tesses::Framework::Http

View File

@@ -32,6 +32,7 @@ class MountableServer : public IHttpServer {
Filesystem::VFSPath offsetPath);
bool StartsWith(Filesystem::VFSPath fullPath,
Filesystem::VFSPath offsetPath);
Tesses::Framework::Threading::Mutex mtx;
public:
MountableServer();
@@ -39,6 +40,5 @@ class MountableServer : public IHttpServer {
void Mount(std::string path, std::shared_ptr<IHttpServer> server);
void Unmount(std::string path);
bool Handle(ServerContext &ctx);
~MountableServer();
};
} // namespace Tesses::Framework::Http

View File

@@ -42,6 +42,7 @@ class RouteServer : public IHttpServer {
};
std::vector<RouteServerRoute> routes;
std::shared_ptr<IHttpServer> root;
Tesses::Framework::Threading::Mutex mtx;
public:
RouteServer() = default;
@@ -58,5 +59,6 @@ class RouteServer : public IHttpServer {
void Add(std::string method, std::string pattern,
ServerRequestHandler handler);
bool Handle(ServerContext &ctx);
void Clear();
};
} // namespace Tesses::Framework::Http

View File

@@ -53,7 +53,7 @@ class NetworkStream : public Stream {
int32_t sock;
bool owns;
bool success;
bool endOfStream;
std::atomic<bool> endOfStream;
public:
bool DataAvailable(int timeout = 0);
@@ -85,6 +85,9 @@ class NetworkStream : public Stream {
~NetworkStream();
void SetNoDelay(bool noDelay);
void Shutdown(StreamShutdownMode mode);
void SetSendTimeout(uint64_t seconds);
void SetRecvTimeout(uint64_t seconds);
void Close();
};
} // namespace Tesses::Framework::Streams

View File

@@ -21,8 +21,11 @@
#pragma once
#include "../Common.hpp"
#include "../Date/Date.hpp"
namespace Tesses::Framework::Streams {
enum class SeekOrigin : uint8_t { Begin = 0, Current = 1, End = 2 };
enum class StreamShutdownMode { Read = 0, Write = 1, ReadWrite = 2 };
class Stream {
public:
int32_t ReadByte();
@@ -42,6 +45,12 @@ class Stream {
void CopyTo(std::shared_ptr<Stream> strm, size_t buffSize = 1024);
void CopyToLimit(std::shared_ptr<Stream> strm, uint64_t len,
size_t buffSize = 1024);
virtual void Shutdown(StreamShutdownMode mode);
void SetSendTimeout(Tesses::Framework::Date::TimeSpan ts);
void SetRecvTimeout(Tesses::Framework::Date::TimeSpan ts);
virtual void SetSendTimeout(uint64_t seconds);
virtual void SetRecvTimeout(uint64_t seconds);
virtual void Close();
virtual ~Stream();
};

View File

@@ -38,9 +38,9 @@
#include "Http/CallbackServer.hpp"
#include "Http/ChangeableServer.hpp"
#include "Http/ContentDisposition.hpp"
#include "Http/DomainServer.hpp"
#include "Http/FileServer.hpp"
#include "Http/HttpClient.hpp"
#include "Http/HttpServer.hpp"
#include "Http/HttpReverseProxy.hpp"
#include "Http/MountableServer.hpp"
#include "Http/RouteServer.hpp"
#include "Lazy.hpp"

View File

@@ -21,6 +21,7 @@
#pragma once
#include "../Date/Date.hpp"
#include "../HiddenField.hpp"
namespace Tesses::Framework::Threading {
class Mutex {
@@ -28,9 +29,39 @@ class Mutex {
public:
Mutex();
void Lock();
void Unlock();
bool TryLock();
void lock() { Lock(); }
void unlock() { Unlock(); }
~Mutex();
friend class Cond;
};
class LockGuard {
Mutex &mtx;
public:
explicit LockGuard(Mutex &m) : mtx(m) { mtx.Lock(); }
~LockGuard() { mtx.Unlock(); }
LockGuard(const LockGuard &) = delete;
LockGuard &operator=(const LockGuard &) = delete;
};
class Cond {
HiddenField data;
public:
Cond();
void Wait(Mutex *mtx);
bool Wait(Mutex *mtx, uint32_t milliseconds);
bool Wait(Mutex *mtx, Date::TimeSpan ts);
void Signal();
void Broadcast();
~Cond();
};
} // namespace Tesses::Framework::Threading