4#include "Stroika/Frameworks/StroikaPreComp.h"
8#include "Stroika/Foundation/Characters/String2Int.h"
12#include "Stroika/Foundation/Execution/CommandLine.h"
13#include "Stroika/Foundation/Execution/Module.h"
14#include "Stroika/Foundation/Execution/SignalHandlers.h"
15#include "Stroika/Foundation/Execution/TimeOutException.h"
16#include "Stroika/Foundation/Execution/WaitableEvent.h"
17#include "Stroika/Foundation/IO/Network/HTTP/Exception.h"
18#include "Stroika/Foundation/IO/Network/HTTP/Headers.h"
19#include "Stroika/Foundation/IO/Network/HTTP/Methods.h"
23#include "Stroika/Frameworks/WebServer/ConnectionManager.h"
24#include "Stroika/Frameworks/WebServer/FileSystemRequestHandler.h"
25#include "Stroika/Frameworks/WebServer/Router.h"
27#include "AppVersion.h"
42using Stroika::Frameworks::WebServer::Response;
51 const FileSystemRequestHandler::Options kFileSystemRouterOptions_{[] () {
54 return FileSystemRequestHandler::Options{.fURLPrefix2Strip =
"/Files/"_k,
56 .fCacheControlSettings = cacheControlSettings};
62 const Headers kDefaultResponseHeaders_{[] () {
64 h.
server =
"Stroika-Sample-WebServer/"_k + AppVersion::kVersion.AsMajorMinorString ();
88 MyWebServer_ (uint16_t portNumber)
96 Route{
""_RegEx, DefaultPage_}
102 Route{HTTP::MethodsRegEx::kPost,
"SetAppState"_RegEx, SetAppState_}
108 Route{
"FRED/?"_RegEx,
109 [] (
Request&, Response& response) {
110 response.contentType = DataExchange::InternetMediaTypes::kText_PLAIN;
111 response.write (
"FRED"sv);
124 Route{
"stats"_RegEx, [
this] (
Message& m) { PrintServerStats_ (m); }}
130 cerr <<
"Listening on {}..."_f(fConnectionMgr_.bindings ()) << endl;
134 static void DefaultPage_ (
Request& request, Response& response)
139 if (request.
url ().LookupQueryArg (
"useChunked"sv) ==
"true"sv) {
140 response.automaticTransferChunkSize = 25;
142 else if (request.
url ().LookupQueryArg (
"useChunked"sv) ==
"false"sv) {
143 response.automaticTransferChunkSize = Response::kNoChunkedTransfer;
149 response.contentType = DataExchange::InternetMediaTypes::kHTML;
153 response.writeln (
"<html><body>"sv);
154 response.writeln (
"<p>Run the service (under the debugger if you wish)</p>"sv);
155 response.writeln (
"<ul>"sv);
156 response.writeln (
"<li>curl -v http://localhost:8080/ OR</li>"sv);
157 response.writeln (
"<li>curl -v http://localhost:8080/?useChunked=true OR</li>"sv);
158 response.writeln (
"<li>curl -v http://localhost:8080/FRED OR (to see error handling)</li>"sv);
159 response.writeln (
"<li>curl -v -H \"Content-Type: application/json\" -X POST -d '{\"AppState\":\"Start\"}' http://localhost:8080/SetAppState</li>"sv);
160 response.writeln (
"<li>curl -v http://localhost:8080/Files/index.html</li>"sv);
161 response.writeln (
"<li>curl -v http://localhost:8080/stats OR</li>"sv);
162 response.writeln (
"</ul>"sv);
163 response.writeln (
"</body></html>"sv);
165 void PrintServerStats_ (
Message& m)
167 auto stats = this->fConnectionMgr_.statistics ();
168 auto connections = this->fConnectionMgr_.connections ();
170 r.contentType = DataExchange::InternetMediaTypes::kText_PLAIN;
171 r.writeln (
"statistics: {");
172 r.writeln (
" {},"_f(stats));
174 r.writeln (
"connections: [");
175 for (
auto s : connections) {
178 r.writeln (
" {},"_f(s));
183 static void SetAppState_ (
Message& message)
185 message.
rwResponse ().contentType = DataExchange::InternetMediaTypes::kHTML;
187 message.
rwResponse ().writeln (
"<html><body><p>Hi SetAppState ("sv + argsAsString +
")</p></body></html>");
192int main (
int argc,
const char* argv[])
197#if qStroika_Foundation_Common_Platform_POSIX
201 uint16_t portNumber = 8080;
204 .fLongName =
"port"sv, .fSupportsArgument =
true, .fHelpOptionText =
"specify webserver listen port (default {})"_f(portNumber)};
206 .fLongName =
"quit-after"sv, .fSupportsArgument =
true, .fHelpOptionText =
"automatically quit after <argument> seconds"sv};
210 cmdLine.Validate (kAllOptions_);
213 cerr << Characters::ToString (current_exception ()) << endl;
214 cerr << cmdLine.GenerateUsage (kAllOptions_) << endl;
217 if (cmdLine.Has (StandardCommandLineOptions::kHelp)) {
218 cerr << cmdLine.GenerateUsage (kAllOptions_) << endl;
224 if (
auto o = cmdLine.GetArgument (kPortO_)) {
225 portNumber = Characters::String2Int<uint16_t> (*o);
227 if (
auto o = cmdLine.GetArgument (kQuitAfterO_)) {
228 quitAfter =
Time::DurationSeconds{Characters::FloatConversion::ToFloat<Time::DurationSeconds::rep> (*o)};
230 MyWebServer_ myWebServer{portNumber};
234 cerr <<
"Timed out - so - exiting..." << endl;
238 cerr <<
"Error encountered: " << Characters::ToString (current_exception ()) <<
" - terminating..." << endl;
chrono::duration< double > DurationSeconds
chrono::duration<double> - a time span (length of time) measured in seconds, but high precision.
RegularExpression is a compiled regular expression which can be used to match on a String class.
String is like std::u32string, except it is much easier to use, often much more space efficient,...
A generalization of a vector: a container whose elements are keyed by the natural numbers.
nonvirtual void SetSignalHandlers(SignalID signal)
static const SignalHandler kIGNORED
static SignalHandlerRegistry sThe
nonvirtual void Wait(Time::DurationSeconds timeout=Time::kInfinity)
Common::Property< URI > url
Duration is a chrono::duration<double> (=.
Common::ReadOnlyProperty< Response & > rwResponse
Common::ReadOnlyProperty< Request & > rwRequest
this represents a HTTP request object for the WebServer module
filesystem::path GetEXEDir()
Traversal::Iterable< SocketAddress > SocketAddresses(const Traversal::Iterable< InternetAddress > &internetAddresses, PortType portNumber)
Traversal::Iterable< InternetAddress > InternetAddresses_Any(InternetProtocol::IP::IPVersionSupport ipSupport=InternetProtocol::IP::IPVersionSupport::eDEFAULT)
Ptr New(const InputStream::Ptr< byte > &src, optional< AutomaticCodeCvtFlags > codeCvtFlags={}, optional< SeekableFlag > seekable={}, ReadAhead readAhead=eReadAheadAllowed)
Create an InputStream::Ptr<Character> from the arguments (usually binary source) - which can be used ...
optional< uint32_t > fMaxAge
ConnectionManager::Options specify things like default headers, caching policies, binding flags (not ...
optional< Socket::BindFlags > fBindFlags