DotNetDupe 4.0.6
C++17/20 Implementation of the .NET Base Class Library (BCL)
Loading...
Searching...
No Matches
WebAppServer.cpp
Go to the documentation of this file.
1#include "pch.h"
4#include "System/IO/File.h"
5#include "System/IO/Path.h"
7#include "System/Console.h"
8#include <fstream>
9#include <sstream>
10#include <algorithm>
11#include <filesystem>
12#include <unordered_map>
13
14namespace DotNetDupe {
15 namespace WebAppCore {
16 namespace Server {
17
19 : m_spApp(app), m_sWebRoot(webRoot), m_sDefaultDocument("index.html"), m_bStaticFilesEnabled(true) {
21 if (app.IsNull()) {
22 throw DotNetDupe::System::ArgumentException("WebApplication cannot be null");
23 }
24 }
25
27 : m_spApp(std::move(other.m_spApp)),
28 m_sWebRoot(std::move(other.m_sWebRoot)),
29 m_sDefaultDocument(std::move(other.m_sDefaultDocument)),
30 m_bStaticFilesEnabled(other.m_bStaticFilesEnabled) {
31 }
32
35 if (this != &other) {
37 m_spApp = std::move(other.m_spApp);
38 m_sWebRoot = std::move(other.m_sWebRoot);
39 m_sDefaultDocument = std::move(other.m_sDefaultDocument);
40 m_bStaticFilesEnabled = other.m_bStaticFilesEnabled;
41 }
43 return *this;
44 }
45
48 m_bStaticFilesEnabled = true;
49 m_sDefaultDocument = defaultDocument;
50 }
51
55 std::string s = ext.GetRawString();
56 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
57 if (s.rfind('.', 0) == 0) s = s.substr(1);
58
60 static const std::unordered_map<std::string, const char*> mimeMap = {
61 {"html", "text/html; charset=utf-8"}, {"htm", "text/html; charset=utf-8"},
62 {"css", "text/css; charset=utf-8"}, {"js", "application/javascript; charset=utf-8"},
63 {"json", "application/json; charset=utf-8"}, {"png", "image/png"},
64 {"jpg", "image/jpeg"}, {"jpeg", "image/jpeg"}, {"gif", "image/gif"},
65 {"svg", "image/svg+xml"}, {"ico", "image/x-icon"}, {"txt", "text/plain; charset=utf-8"},
66 {"pdf", "application/pdf"}, {"woff", "font/woff"}, {"woff2", "font/woff2"}
67 };
68 auto it = mimeMap.find(s);
70 return (it != mimeMap.end()) ? it->second : "application/octet-stream";
71 }
72
75 std::string rel = reqPath.GetRawString();
76 if (!rel.empty() && (rel[0] == '/' || rel[0] == '\\')) rel = rel.substr(1);
77 if (rel.empty()) rel = defaultDoc.GetRawString();
78 if (rel.find("..") != std::string::npos) return "";
79
83 if (DotNetDupe::System::IO::File::GetAttributes(target, attr) && (static_cast<int>(attr) & static_cast<int>(DotNetDupe::System::IO::FileAttributes::Directory)) != 0) {
84 target = DotNetDupe::System::IO::Path::Combine({target, defaultDoc});
85 }
87 return target;
88 }
89
92 DotNetDupe::System::String target = ResolveStaticPath(spContext->GetRequest()->GetPath(), webRoot, defaultDoc);
93 if (target.IsEmpty()) {
94 spContext->GetResponse()->SetStatusCode(403); spContext->GetResponse()->SetContentType("text/plain");
95 return "403 Forbidden: Invalid file path";
96 }
99 spContext->GetResponse()->SetStatusCode(404); spContext->GetResponse()->SetContentType("text/plain");
100 return "404 Not Found";
101 }
103 try {
105 spContext->GetResponse()->SetStatusCode(200);
106 spContext->GetResponse()->SetContentType(WebAppServer::GetMimeType(target));
107 spContext->GetResponse()->GetHeaders()["Content-Disposition"] = "inline";
108 return content;
109 } catch (...) {
110 spContext->GetResponse()->SetStatusCode(500); spContext->GetResponse()->SetContentType("text/plain");
111 return "500 Internal Server Error: Unable to open file";
112 }
113 }
114
117 if (spApp->HasWebSocketRoute(ctx->GetRequest()->GetPath())) {
118 ctx->GetResponse()->SetStatusCode(426);
119 ctx->GetResponse()->SetContentType("text/plain");
120 ctx->GetResponse()->GetHeaders()["Upgrade"] = "websocket";
121 ctx->GetResponse()->GetHeaders()["Connection"] = "Upgrade";
122 return "426 Upgrade Required";
123 }
125 return ServeStaticFile(ctx, webRoot, defaultDoc);
126 }
127
128 void WebAppServer::Run(const DotNetDupe::System::String& url, int threadCount) {
130 if (m_bStaticFilesEnabled) {
131 m_spApp->MapGet("/{*filepath}", [this](DotNetDupe::System::SmartPointer<Http::HttpContext> ctx) {
132 return HandleStaticRouteOrWebSocket(m_spApp, ctx, m_sWebRoot, m_sDefaultDocument);
133 });
134 }
136 m_spApp->Run(url, threadCount);
137 }
138
141 m_spApp->Stop();
142 }
143
144 }
145 }
146}
Defines the exception thrown when an invalid argument is provided to a method.
Represents standard input, output, and error streams for console applications.
Provides static methods for the creation, copying, deletion, moving, and opening of a single file.
HTTP request, response, and context abstractions for WebAppCore processing pipelines.
Static file web server and application hosting wrapper for WebApplication.
static bool GetAttributes(const String &sPath, FileAttributes &attrAttributes)
Definition File.cpp:167
static bool Exists(const String &sPath)
Determines whether the specified file exists.
Definition File.cpp:31
static String ReadAllText(const String &sPath)
Opens a text file, reads all the text in the file, and then closes the file.
Definition File.cpp:36
static String GetExtension(const String &sFilePath)
Returns the extension of the specified path string.
Definition Path.cpp:111
static String Combine(const std::initializer_list< String > sPaths)
Combines an array of strings into a path.
Definition Path.cpp:63
A unified smart pointer that supports both unique and shared ownership semantics.
bool IsNull() const noexcept
Checks if the SmartPointer is null.
Represents text as a sequence of UTF-8 code units with culture-invariant operations.
Definition String.h:74
const char * GetRawString() const
Definition String.cpp:230
WebAppServer(const DotNetDupe::System::SmartPointer< Builder::WebApplication > &app, const DotNetDupe::System::String &webRoot="wwwroot")
Constructs a WebAppServer wrapping the specified WebApplication host and web root path.
static DotNetDupe::System::String GetMimeType(const DotNetDupe::System::String &filePath)
Resolves the standard MIME content type string based on a file path extension.
WebAppServer & operator=(const WebAppServer &)=delete
void EnableStaticFiles(const DotNetDupe::System::String &defaultDocument="index.html")
Enables static file serving with the specified default document fallback.
void Stop()
Stops the running web server and active TCP listener.
void Run(const DotNetDupe::System::String &url="http://localhost:8080/index.html", int threadCount=10)
Starts the underlying WebApplication server listener on the specified URL and thread pool size.
FileAttributes
Provides attributes for files and directories.
Definition File.h:16
static DotNetDupe::System::String HandleStaticRouteOrWebSocket(const DotNetDupe::System::SmartPointer< Builder::WebApplication > &spApp, const DotNetDupe::System::SmartPointer< Http::HttpContext > &ctx, const DotNetDupe::System::String &webRoot, const DotNetDupe::System::String &defaultDoc)
static DotNetDupe::System::String ServeStaticFile(DotNetDupe::System::SmartPointer< Http::HttpContext > spContext, const DotNetDupe::System::String &webRoot, const DotNetDupe::System::String &defaultDoc)
static DotNetDupe::System::String ResolveStaticPath(const DotNetDupe::System::String &reqPath, const DotNetDupe::System::String &webRoot, const DotNetDupe::System::String &defaultDoc)