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
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:
@@ -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();
|
||||
};
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
41
include/TessesFramework/Http/DomainServer.hpp
Normal file
41
include/TessesFramework/Http/DomainServer.hpp
Normal 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
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
84
include/TessesFramework/Http/HttpReverseProxy.hpp
Normal file
84
include/TessesFramework/Http/HttpReverseProxy.hpp
Normal 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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user