4#include "Stroika/Frameworks/StroikaPreComp.h"
10#include "Stroika/Foundation/IO/FileSystem/Common.h"
12#include "Stroika/Foundation/IO/Network/HTTP/ClientErrorException.h"
15#include "FileSystemRequestHandler.h"
24using namespace Stroika::Foundation::Memory;
25using namespace Stroika::Foundation::Streams;
27using namespace Stroika::Frameworks;
37 filesystem::path fFSRoot_;
40 vector<pair<RegularExpression, CacheControl>> fCacheControlSettings;
41 optional<filesystem::path> fFallbackFile_;
43 FSRouterRep_ (
const filesystem::path& filesystemRoot,
const optional<String>& urlPrefix2Strip,
const Sequence<filesystem::path>& defaultIndexFileNames,
44 const optional<
Sequence<pair<RegularExpression, CacheControl>>>& cacheControlSettings,
const optional<filesystem::path>& fallbackFile)
45 : fFSRoot_{filesystem::canonical (filesystemRoot)}
46 , fURLPrefix2Strip_{urlPrefix2Strip.value_or (
"/"sv)}
47 , fDefaultIndexFileNames{defaultIndexFileNames}
48 , fFallbackFile_{fallbackFile}
50 if (cacheControlSettings) {
51 for (
const auto& i : *cacheControlSettings) {
56 void HandleMessage (
Message& m,
bool& handled)
58#if qStroika_Foundation_Debug_DefaultTracingOn
66 if (optional<String> urlHostRelPath = ExtractURLHostRelPath_ (m)) {
67 filesystem::path fn{fFSRoot_ / urlHostRelPath->As<filesystem::path> ()};
68 if (fFallbackFile_ and not filesystem::exists (fn)) {
69 fn = fFSRoot_ / *fFallbackFile_;
72#if USE_NOISY_TRACE_IN_THIS_MODULE_
75 m.
request ().url ().GetAuthorityRelativeResource (), fn)};
80 if (optional<InternetMediaType> oMediaType = InternetMediaTypeRegistry::sThe->GetAssociatedContentType (fn.extension ())) {
81 response.contentType = *oMediaType;
82#if USE_NOISY_TRACE_IN_THIS_MODULE_
83 DbgTrace (
"content-type: {}"_f, *oMediaType);
86 ApplyCacheControl_ (response, *urlHostRelPath);
87 response.write (in.ReadAll ());
90 catch (
const system_error& e) {
91 if (e.code () == errc::no_such_file_or_directory) {
101 void ApplyCacheControl_ (Response& r,
const String& urlRelPath)
const
103 for (
const auto& i : fCacheControlSettings) {
104 if (urlRelPath.
Matches (i.first)) {
105 r.rwHeaders ().cacheControl = i.second;
110 optional<String> ExtractURLHostRelPath_ (
const Message& m)
const
113 String urlHostRelPath = request.
url ().Normalize (URI::NormalizationStyle::eAggressive).GetAbsPath<
String> ();
114 Assert (not urlHostRelPath.
Contains (
"/../"));
115 if (not fURLPrefix2Strip_.empty ()) {
116 if (urlHostRelPath.
StartsWith (fURLPrefix2Strip_)) {
117 urlHostRelPath = urlHostRelPath.
SubString (fURLPrefix2Strip_.
length ());
119 urlHostRelPath = urlHostRelPath.
SubString (1);
126 if ((urlHostRelPath.empty () or urlHostRelPath.
EndsWith (
'/')) and not fDefaultIndexFileNames.
empty ()) {
128 urlHostRelPath = urlHostRelPath +
String{fDefaultIndexFileNames[0]};
130 return urlHostRelPath;
141 :
RequestHandler{[rep = make_shared<FSRouterRep_> (filesystemRoot, options.fURLPrefix2Strip, Memory::
NullCoalesce (options.fDefaultIndexFileNames),
142 options.fCacheControlSettings, options.fFallbackFile)] (
145 DbgTrace (
"fDefaultIndexFileNames={}"_f, options.fDefaultIndexFileNames);
const OT & NullCoalesce(const OT &l, const OT &r)
return one of l, or r, with first preference for which is engaged, and second preference for left-to-...
#define Stroika_Foundation_Debug_OptionalizeTraceArgs(...)
String is like std::u32string, except it is much easier to use, often much more space efficient,...
nonvirtual bool Contains(Character c, CompareOptions co=eWithCase) const
nonvirtual size_t length() const noexcept
nonvirtual bool Matches(const RegularExpression ®Ex) const
nonvirtual bool EndsWith(const Character &c, CompareOptions co=eWithCase) const
nonvirtual String SubString(SZ from) const
nonvirtual bool StartsWith(const Character &c, CompareOptions co=eWithCase) const
A generalization of a vector: a container whose elements are keyed by the natural numbers.
nonvirtual void push_back(ArgByValueType< value_type > item)
ClientErrorException is to capture exceptions caused by a bad (e.g ill-formed) request.
Common::Property< URI > url
nonvirtual bool empty() const
Returns true iff size() == 0.
FileSystemRequestHandler(const filesystem::path &filesystemRoot, const Options &options=kDefaultOptions)
Common::ReadOnlyProperty< Response & > rwResponse
Common::ReadOnlyProperty< const Request & > request
this represents a HTTP request object for the WebServer module
Create a format-string (see std::wformat_string or Stroika FormatString, or python 'f' strings.
ConnectionManager::Options specify things like default headers, caching policies, binding flags (not ...