From 931cf49320c65325da91cf33f6a40603cf0f12ff Mon Sep 17 00:00:00 2001 From: Mike Nolan Date: Tue, 14 Oct 2025 23:12:43 -0500 Subject: [PATCH] Add changeable server --- CMakeLists.txt | 1 + examples/webserverex.cpp | 22 ++++++++++ include/TessesFramework/Common.hpp | 8 +++- .../Filesystem/MountableFilesystem.hpp | 1 - .../TessesFramework/Http/ChangeableServer.hpp | 14 +++++++ include/TessesFramework/Http/HttpServer.hpp | 7 ++++ include/TessesFramework/Streams/Stream.hpp | 1 + include/TessesFramework/TessesFramework.hpp | 1 + src/Filesystem/MountableFilesystem.cpp | 7 +--- src/Http/ChangeableServer.cpp | 22 ++++++++++ src/Http/HttpServer.cpp | 41 ++++++++++++++++++- src/Streams/FileStream.cpp | 2 +- src/Streams/Stream.cpp | 25 ++++++++++- 13 files changed, 139 insertions(+), 13 deletions(-) create mode 100644 include/TessesFramework/Http/ChangeableServer.hpp create mode 100644 src/Http/ChangeableServer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index d19450f..bfe7983 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,6 +15,7 @@ src/Http/HttpClient.cpp src/Http/HttpStream.cpp src/Http/ContentDisposition.cpp src/Http/WebSocket.cpp +src/Http/ChangeableServer.cpp src/Mail/Smtp.cpp src/Serialization/Json.cpp src/Serialization/SQLite.cpp diff --git a/examples/webserverex.cpp b/examples/webserverex.cpp index 2f84a21..840268c 100644 --- a/examples/webserverex.cpp +++ b/examples/webserverex.cpp @@ -32,6 +32,22 @@ class MyWebServer : public IHttpServer { .SendStream(fs); return true; } + else if(ctx.path == "/mypath.html") + { + std::string txt = "

Root: " + HttpUtils::HtmlEncode(ctx.GetServerRoot()) + "

"; + ctx.WithMimeType("text/html").SendText(txt); + return true; + } + else if(ctx.path == "/getabsolute.html") + { + std::string path; + if(ctx.queryParams.TryGetFirst("path",path)) + { + std::string txt = "

Path: " + HttpUtils::HtmlEncode(ctx.MakeAbsolute(path)) + "

"; + ctx.WithMimeType("text/html").SendText(txt); + return true; + } + } else if(ctx.path == "/streaming.html") { StreamWriter writer(ctx.OpenResponseStream()); @@ -109,6 +125,12 @@ class MyOtherWebServer : public IHttpServer ctx.SendText(data->text); return true; } + else if(ctx.path == "/mypath.html") + { + std::string txt = "

Root: " + HttpUtils::HtmlEncode(ctx.GetServerRoot()) + "

"; + ctx.WithMimeType("text/html").SendText(txt); + return true; + } return false; } diff --git a/include/TessesFramework/Common.hpp b/include/TessesFramework/Common.hpp index c3575cc..019e63b 100644 --- a/include/TessesFramework/Common.hpp +++ b/include/TessesFramework/Common.hpp @@ -43,7 +43,10 @@ namespace Tesses::Framework mtx.Lock(); for(std::shared_ptr>& item : this->items) { - if(item.get() == event.get()) return; + if(item.get() == event.get()) { + mtx.Unlock(); + return; + } } this->items.push_back(event); mtx.Unlock(); @@ -56,10 +59,11 @@ namespace Tesses::Framework if(i->get() == event.get()) { this->items.erase(i); + mtx.Unlock(); return; } } - mtx.Lock(); + mtx.Unlock(); } void Invoke(TArgs... args) { diff --git a/include/TessesFramework/Filesystem/MountableFilesystem.hpp b/include/TessesFramework/Filesystem/MountableFilesystem.hpp index 5dee18f..22be923 100644 --- a/include/TessesFramework/Filesystem/MountableFilesystem.hpp +++ b/include/TessesFramework/Filesystem/MountableFilesystem.hpp @@ -57,6 +57,5 @@ namespace Tesses::Framework::Filesystem void Chmod(VFSPath path, uint32_t mode); - void Close(); }; } \ No newline at end of file diff --git a/include/TessesFramework/Http/ChangeableServer.hpp b/include/TessesFramework/Http/ChangeableServer.hpp new file mode 100644 index 0000000..d6d6439 --- /dev/null +++ b/include/TessesFramework/Http/ChangeableServer.hpp @@ -0,0 +1,14 @@ +#pragma once +#include "HttpServer.hpp" + +namespace Tesses::Framework::Http +{ + class ChangeableServer { + public: + ChangeableServer(); + ChangeableServer(std::shared_ptr original); + std::shared_ptr server; + bool Handle(ServerContext& ctx); + ~ChangeableServer(); + }; +} \ No newline at end of file diff --git a/include/TessesFramework/Http/HttpServer.hpp b/include/TessesFramework/Http/HttpServer.hpp index 17965cf..c2d75db 100644 --- a/include/TessesFramework/Http/HttpServer.hpp +++ b/include/TessesFramework/Http/HttpServer.hpp @@ -56,8 +56,15 @@ namespace Tesses::Framework::Http ServerContext& WithMimeType(std::string mime); ServerContext& WithContentDisposition(std::string filename, bool isInline); ServerContext& WriteHeaders(); + ServerContext& WithLocationHeader(std::string url); + ServerContext& WithLocationHeader(std::string url,StatusCode sc); void StartWebSocketSession(std::function,std::function,std::function)> onOpen, std::function onReceive, std::function onClose); void StartWebSocketSession(std::shared_ptr connection); + std::string GetServerRoot(); + std::string MakeAbsolute(std::string path); + void SendRedirect(std::string url); + void SendRedirect(std::string url, StatusCode sc); + template T* GetServerContentData(std::string tag) diff --git a/include/TessesFramework/Streams/Stream.hpp b/include/TessesFramework/Streams/Stream.hpp index 0e29229..09ab6ab 100644 --- a/include/TessesFramework/Streams/Stream.hpp +++ b/include/TessesFramework/Streams/Stream.hpp @@ -24,6 +24,7 @@ namespace Tesses::Framework::Streams virtual void Flush(); virtual void Seek(int64_t pos, SeekOrigin whence); void CopyTo(std::shared_ptr strm, size_t buffSize=1024); + void CopyToLimit(std::shared_ptr strm,uint64_t len, size_t buffSize=1024); virtual void Close(); virtual ~Stream(); }; diff --git a/include/TessesFramework/TessesFramework.hpp b/include/TessesFramework/TessesFramework.hpp index a5fa039..7daa587 100644 --- a/include/TessesFramework/TessesFramework.hpp +++ b/include/TessesFramework/TessesFramework.hpp @@ -6,6 +6,7 @@ #include "Http/CallbackServer.hpp" #include "Http/MountableServer.hpp" #include "Http/ContentDisposition.hpp" +#include "Http/ChangeableServer.hpp" #include "Streams/FileStream.hpp" #include "Streams/MemoryStream.hpp" #include "Streams/NetworkStream.hpp" diff --git a/src/Filesystem/MountableFilesystem.cpp b/src/Filesystem/MountableFilesystem.cpp index 9f037b9..4de3600 100644 --- a/src/Filesystem/MountableFilesystem.cpp +++ b/src/Filesystem/MountableFilesystem.cpp @@ -21,12 +21,7 @@ namespace Tesses::Framework::Filesystem for(auto item : this->directories) delete item; } - void MountableFilesystem::Close() - { - this->root=nullptr; - for(auto item : this->directories) delete item; - this->directories.clear(); - } + void MountableFilesystem::GetFS(VFSPath srcPath, VFSPath& destRoot, VFSPath& destPath, std::shared_ptr& vfs) diff --git a/src/Http/ChangeableServer.cpp b/src/Http/ChangeableServer.cpp new file mode 100644 index 0000000..d3c24e1 --- /dev/null +++ b/src/Http/ChangeableServer.cpp @@ -0,0 +1,22 @@ +#include "TessesFramework/Http/ChangeableServer.hpp" + +namespace Tesses::Framework::Http { +ChangeableServer::ChangeableServer() : ChangeableServer(nullptr) +{ + +} +ChangeableServer::ChangeableServer(std::shared_ptr original) +{ + this->server = original; +} + +bool ChangeableServer::Handle(ServerContext& ctx) +{ + if(this->server) this->server->Handle(ctx); + return false; +} +ChangeableServer::~ChangeableServer() +{ + +} +} \ No newline at end of file diff --git a/src/Http/HttpServer.cpp b/src/Http/HttpServer.cpp index c6a6cc0..f4c6f0f 100644 --- a/src/Http/HttpServer.cpp +++ b/src/Http/HttpServer.cpp @@ -10,6 +10,8 @@ #include "TessesFramework/Threading/Mutex.hpp" #include "TessesFramework/Common.hpp" #include "TessesFramework/TextStreams/StdIOWriter.hpp" +#include "TessesFramework/Filesystem/VFSFix.hpp" +#include "TessesFramework/Filesystem/VFS.hpp" #include using FileStream = Tesses::Framework::Streams::FileStream; @@ -801,7 +803,7 @@ namespace Tesses::Framework::Http this->strm->WriteBlock(buffer,read); begin += read; - } while(read > 0); + } while(read > 0 && !this->strm->EndOfStream()); } @@ -858,6 +860,26 @@ namespace Tesses::Framework::Http this->responseHeaders.SetValue("Content-Disposition",cd.ToString()); return *this; } + ServerContext& ServerContext::WithLocationHeader(std::string url) + { + return WithSingleHeader("Location", this->MakeAbsolute(url)); + } + ServerContext& ServerContext::WithLocationHeader(std::string url,StatusCode sc) + { + this->statusCode = sc; + return WithSingleHeader("Location", this->MakeAbsolute(url)); + } + void ServerContext::SendRedirect(std::string url) + { + WithLocationHeader(url); + this->WriteHeaders(); + } + void ServerContext::SendRedirect(std::string url,StatusCode sc) + { + WithLocationHeader(url,sc); + this->WriteHeaders(); + } + void ServerContext::SendNotFound() { if(sent) return; @@ -1053,5 +1075,22 @@ namespace Tesses::Framework::Http svr.Start(); thrd.Join(); } + std::string ServerContext::GetServerRoot() + { + if(this->originalPath == this->path) return "/"; + Tesses::Framework::Filesystem::VFSPath originalPath=this->originalPath; + Tesses::Framework::Filesystem::VFSPath path=this->path; + if(originalPath.path.size() <= path.path.size()) return "/"; + + originalPath.path.resize(originalPath.path.size() - path.path.size()); + return originalPath.ToString(); + } + std::string ServerContext::MakeAbsolute(std::string path) + { + if(path.find("http://") == 0 || path.find("https://") == 0 || path.find("/") == 0) return path; + Tesses::Framework::Filesystem::VFSPath path2 = GetServerRoot(); + path2 = path2 / path; + return path2.CollapseRelativeParents().ToString(); + } } diff --git a/src/Streams/FileStream.cpp b/src/Streams/FileStream.cpp index 10b3f39..0bc2a7f 100644 --- a/src/Streams/FileStream.cpp +++ b/src/Streams/FileStream.cpp @@ -111,7 +111,7 @@ namespace Tesses::Framework::Streams if(!f) return; if(this->owns) { - fclose(this->f); + fclose(this->f); f=NULL; } } diff --git a/src/Streams/Stream.cpp b/src/Streams/Stream.cpp index 45878d1..e7540d2 100644 --- a/src/Streams/Stream.cpp +++ b/src/Streams/Stream.cpp @@ -53,7 +53,7 @@ namespace Tesses::Framework::Streams { buffer += read; len -= read; - } while(read > 0); + } while(read > 0 && !this->EndOfStream()); } bool Stream::CanRead() { @@ -96,6 +96,27 @@ namespace Tesses::Framework::Streams { { } + + void Stream::CopyToLimit(std::shared_ptr strm,uint64_t len, size_t buffSize) + { + size_t read; + uint8_t* buffer = new uint8_t[buffSize]; + uint64_t offset = 0; + + do { + if(offset >= len) break; + read = (size_t)std::min(len-offset,(uint64_t)buffSize); + + read = this->Read(buffer,read); + strm->WriteBlock(buffer, read); + + offset += read; + + } while(read > 0 && !strm->EndOfStream()); + strm->Flush(); + + delete[] buffer; + } void Stream::CopyTo(std::shared_ptr strm, size_t buffSize) { @@ -107,7 +128,7 @@ namespace Tesses::Framework::Streams { read = this->Read(buffer,buffSize); strm->WriteBlock(buffer, read); - } while(read > 0); + } while(read > 0 && !strm->EndOfStream()); strm->Flush(); delete[] buffer;