Add route server

This commit is contained in:
2026-01-12 12:25:06 -06:00
parent 2f5271f7c3
commit 848fca7f36
12 changed files with 247 additions and 19 deletions

View File

@@ -330,6 +330,35 @@ namespace Tesses::Framework::Filesystem
this->path = p;
}
VFSPath VFSPath::ParseUriPath(std::string path)
{
std::string builder = {};
VFSPath vpath;
vpath.relative=true;
if(!path.empty() && path[0] == '/') vpath.relative=false;
for(auto item : path)
{
if(item == '/')
{
if(!builder.empty())
{
vpath.path.push_back(builder);
builder.clear();
}
}
else {
builder.push_back(item);
}
}
if(!builder.empty())
{
vpath.path.push_back(builder);
}
return vpath;
}
bool VFSPath::HasExtension() const
{
if(this->path.empty()) return false;
@@ -377,6 +406,9 @@ namespace Tesses::Framework::Filesystem
if(!str.empty())
{
if(str.front() == '/') this->relative=false;
#if defined(_WIN32)
if(str.front() == '\\') this->relative=false;
#endif
if(!this->path.empty())
{
auto firstPartPath = this->path.front();

View File

@@ -566,7 +566,12 @@ namespace Tesses::Framework::Http
this->responseHeaders.SetValue("Transfer-Encoding","chunked");
this->WriteHeaders();
return std::make_shared<HttpStream>(this->strm,length,false,version == "HTTP/1.1");
auto strm = std::make_shared<HttpStream>(this->strm,length,false,version == "HTTP/1.1");
if(method == "HEAD")
{
strm->Close();
}
return strm;
}
std::shared_ptr<Stream> ServerContext::OpenRequestStream()
{
@@ -788,23 +793,26 @@ namespace Tesses::Framework::Http
this->WithSingleHeader("Content-Range","bytes " + std::to_string(begin) + "-" + std::to_string(end) + "/" + std::to_string(len));
this->statusCode = PartialContent;
this->WriteHeaders();
strm->Seek(begin,SeekOrigin::Begin);
if(this->method != "HEAD")
{
strm->Seek(begin,SeekOrigin::Begin);
uint8_t buffer[1024];
uint8_t buffer[1024];
size_t read=0;
do {
read = sizeof(buffer);
myLen = (end - begin)+1;
if(myLen < read) read = (size_t)myLen;
if(read == 0) break;
read = strm->Read(buffer,read);
if(read == 0) break;
this->strm->WriteBlock(buffer,read);
begin += read;
} while(read > 0 && !this->strm->EndOfStream());
size_t read=0;
do {
read = sizeof(buffer);
myLen = (end - begin)+1;
if(myLen < read) read = (size_t)myLen;
if(read == 0) break;
read = strm->Read(buffer,read);
if(read == 0) break;
this->strm->WriteBlock(buffer,read);
begin += read;
} while(read > 0 && !this->strm->EndOfStream());
}
}
else
@@ -821,6 +829,7 @@ namespace Tesses::Framework::Http
this->WithSingleHeader("Accept-Range","bytes");
this->WithSingleHeader("Content-Length",std::to_string(len));
this->WriteHeaders();
if(this->method != "HEAD")
strm->CopyTo(this->strm);
}
}
@@ -828,8 +837,10 @@ namespace Tesses::Framework::Http
}
else
{
auto chunkedStream = this->OpenResponseStream();
if(method != "HEAD")
strm->CopyTo(chunkedStream);

View File

@@ -27,6 +27,7 @@ namespace Tesses::Framework::Http
}
bool HttpStream::CanWrite()
{
if(this->done) return false;
if(this->recv) return false;
return this->strm->CanWrite();
}
@@ -118,6 +119,7 @@ namespace Tesses::Framework::Http
}
size_t HttpStream::Write(const uint8_t* buff, size_t len)
{
if(this->done) return 0;
if(this->recv) return 0;
if(this->length == 0) return 0;
if(this->length > 0)
@@ -153,9 +155,20 @@ namespace Tesses::Framework::Http
}
}
}
void HttpStream::Close()
{
if(this->length == -1 && this->http1_1 && !done && !this->recv)
{
this->done=true;
StreamWriter writer(this->strm);
writer.newline = "\r\n";
writer.WriteLine("0");
writer.WriteLine();
}
}
HttpStream::~HttpStream()
{
if(this->length == -1 && this->http1_1)
if(this->length == -1 && this->http1_1 && !done && !this->recv)
{
StreamWriter writer(this->strm);
writer.newline = "\r\n";

97
src/Http/RouteServer.cpp Normal file
View File

@@ -0,0 +1,97 @@
#include "TessesFramework/Http/RouteServer.hpp"
namespace Tesses::Framework::Http
{
RouteServer::RouteServerRoute::RouteServerRoute(std::string route, std::string method, ServerRequestHandler handler) : method(method), handler(handler)
{
auto path = Tesses::Framework::Filesystem::VFSPath::ParseUriPath(route);
for(auto item : path.path)
{
if(item.size() > 2 && item[0] == '{' && item[item.size()-1] == '}')
{
this->parts.emplace_back( item.substr(1,item.size()-2),true);
}
else {
this->parts.emplace_back(item,false);
}
}
}
bool RouteServer::RouteServerRoute::Equals(Tesses::Framework::Filesystem::VFSPath& path, HttpDictionary& args)
{
if(path.path.size() != this->parts.size()) return false;
for(size_t i = 0; i < this->parts.size(); i++)
{
auto& part = this->parts[i];
if(part.second)
args.SetValue(part.first, Tesses::Framework::Http::HttpUtils::UrlPathDecode(path.path[i]));
else if(part.first != path.path[i]) return false;
}
return true;
}
RouteServer::RouteServer(std::shared_ptr<IHttpServer> root) : root(root)
{
}
void RouteServer::Add(std::string method, std::string pattern, ServerRequestHandler handler)
{
this->routes.emplace_back(pattern,method,handler);
}
bool RouteServer::Handle(ServerContext& ctx)
{
auto pathArgs = ctx.pathArguments;
auto path = Tesses::Framework::Filesystem::VFSPath::ParseUriPath(ctx.path);
for(auto& svr : this->routes)
{
if(svr.method != ctx.method) continue;
ctx.pathArguments = pathArgs;
if(svr.Equals(path, ctx.pathArguments) && svr.handler && svr.handler(ctx))
return true;
}
ctx.pathArguments = pathArgs;
if(this->root)
return this->root->Handle(ctx);
return false;
}
void RouteServer::Get(std::string pattern, ServerRequestHandler handler)
{
Add("GET",pattern,handler);
}
void RouteServer::Post(std::string pattern, ServerRequestHandler handler)
{
Add("POST",pattern,handler);
}
void RouteServer::Put(std::string pattern, ServerRequestHandler handler)
{
Add("PUT",pattern,handler);
}
void RouteServer::Patch(std::string pattern, ServerRequestHandler handler)
{
Add("PATCH",pattern,handler);
}
void RouteServer::Delete(std::string pattern, ServerRequestHandler handler)
{
Add("DELETE",pattern,handler);
}
void RouteServer::Trace(std::string pattern, ServerRequestHandler handler)
{
Add("TRACE",pattern,handler);
}
void RouteServer::Options(std::string pattern, ServerRequestHandler handler)
{
Add("OPTIONS",pattern,handler);
}
}

View File

@@ -48,8 +48,13 @@ namespace Tesses::Framework::Streams {
if(len < 1024)
read = len;
if(read > 0)
{
read=this->Write(buffer,read);
if(read == 0)
{
throw std::out_of_range("Failed to write!");
}
}
buffer += read;
@@ -109,7 +114,6 @@ namespace Tesses::Framework::Streams {
read = (size_t)std::min(len-offset,(uint64_t)buffSize);
read = this->Read(buffer,read);
strm->WriteBlock(buffer, read);
offset += read;