1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233
|
// Copyright Maarten L. Hekkelman, 2014-2022
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#pragma once
/// \file
/// definition of the zeep::template_processor class. This class
/// handles the loading and processing of XHTML files.
#include <zeep/config.hpp>
#include <set>
#include <filesystem>
#include <zeep/http/el-processing.hpp>
#include <zeep/http/reply.hpp>
#include <zeep/http/tag-processor.hpp>
// --------------------------------------------------------------------
//
namespace zeep::http
{
class html_controller;
// -----------------------------------------------------------------------
/// \brief abstract base class for a resource loader
///
/// A resource loader is used to fetch the resources a webapp can serve
/// This is an abstract base class, use either file_loader to load files
/// from a 'docroot' directory or rsrc_loader to load files from compiled in
/// resources. (See https://github.com/mhekkel/mrc for more info on resources)
class resource_loader
{
public:
virtual ~resource_loader() {}
resource_loader(const resource_loader&) = delete;
resource_loader& operator=(const resource_loader&) = delete;
/// \brief return last_write_time of \a file
virtual std::filesystem::file_time_type file_time(const std::string& file, std::error_code& ec) noexcept = 0;
/// \brief basic loader, returns error in ec if file was not found
virtual std::istream* load_file(const std::string& file, std::error_code& ec) noexcept = 0;
protected:
resource_loader() {}
};
// -----------------------------------------------------------------------
/// \brief actual implementation of a zeep::resource_loader that loads files from disk
///
/// Load the resources from the directory specified in the docroot constructor parameter.
class file_loader : public resource_loader
{
public:
/// \brief constructor
///
/// \param docroot Path to the directory where the 'resources' are located
///
/// Throws a runtime_error if the docroot does not exist
file_loader(const std::filesystem::path& docroot = ".");
/// \brief return last_write_time of \a file
virtual std::filesystem::file_time_type file_time(const std::string& file, std::error_code& ec) noexcept;
/// \brief basic loader, returns error in ec if file was not found
virtual std::istream* load_file(const std::string& file, std::error_code& ec) noexcept;
private:
std::filesystem::path m_docroot;
};
// -----------------------------------------------------------------------
/// \brief actual implementation of a zeep::resource_loader that loads resources from memory
///
/// Load the resources from resource data created with mrc (see https://github.com/mhekkel/mrc )
class rsrc_loader : public resource_loader
{
public:
/// \brief constructor
///
/// The parameter is not used
rsrc_loader(const std::string&);
/// \brief return last_write_time of \a file
virtual std::filesystem::file_time_type file_time(const std::string& file, std::error_code& ec) noexcept;
/// \brief basic loader, returns error in ec if file was not found
virtual std::istream* load_file(const std::string& file, std::error_code& ec) noexcept;
private:
std::filesystem::file_time_type mRsrcWriteTime = {};
};
// --------------------------------------------------------------------
/// \brief base class for template processors
///
/// template_processor is used to create XHTML web pages based on the contents of a
/// template file and the parameters passed in the request and calculated data stored
/// in a scope object.
class basic_template_processor
{
public:
basic_template_processor(const std::string& docroot)
: m_docroot(docroot) {}
virtual ~basic_template_processor() {}
/// \brief set the docroot for this processor
virtual void set_docroot(const std::filesystem::path& docroot);
/// \brief get the current docroot of this processor
std::filesystem::path get_docroot() const { return m_docroot; }
// --------------------------------------------------------------------
// tag processor support
/// \brief process all the tags in this node
virtual void process_tags(xml::node* node, const scope& scope);
protected:
std::map<std::string,std::function<tag_processor*(const std::string&)>> m_tag_processor_creators;
/// \brief process only the tags with the specified namespace prefixes
virtual void process_tags(xml::element* node, const scope& scope, std::set<std::string> registeredNamespaces);
public:
/// \brief Use to register a new tag_processor and couple it to a namespace
template<typename TagProcessor>
void register_tag_processor(const std::string& ns = TagProcessor::ns())
{
m_tag_processor_creators.emplace(ns, [](const std::string& ns) { return new TagProcessor(ns.c_str()); });
}
/// \brief Create a tag_processor
tag_processor* create_tag_processor(const std::string& ns) const
{
return m_tag_processor_creators.at(ns)(ns);
}
// --------------------------------------------------------------------
/// \brief Default handler for serving files out of our doc root
virtual void handle_file(const request& request, const scope& scope, reply& reply);
public:
/// \brief return last_write_time of \a file
virtual std::filesystem::file_time_type file_time(const std::string& file, std::error_code& ec) noexcept = 0;
/// \brief return error in ec if file was not found
virtual std::istream* load_file(const std::string& file, std::error_code& ec) noexcept = 0;
public:
/// \brief Use load_template to fetch the XHTML template file
virtual void load_template(const std::string& file, xml::document& doc);
/// \brief Check if the argument \a file contains a valid reference to an XHTML template file and return the path, if any.
virtual std::tuple<bool, std::filesystem::path> is_template_file(const std::string& file);
/// \brief create a reply based on a template
virtual void create_reply_from_template(const std::string& file, const scope& scope, reply& reply);
/// \brief Initialize the scope object
virtual void init_scope(scope& scope);
protected:
std::string m_ns;
std::filesystem::path m_docroot;
};
// --------------------------------------------------------------------
/// \brief actual implementation of the abstract basic_template_processor
template<typename Loader>
class html_template_processor : public basic_template_processor
{
public:
html_template_processor(const std::string& docroot = "", bool addDefaultTagProcessors = true)
: basic_template_processor(docroot), m_loader(docroot)
{
if (addDefaultTagProcessors)
{
register_tag_processor<tag_processor_v1>();
register_tag_processor<tag_processor_v2>();
}
}
virtual ~html_template_processor() {}
/// return last_write_time of \a file
virtual std::filesystem::file_time_type file_time(const std::string& file, std::error_code& ec) noexcept
{
return m_loader.file_time(file, ec);
}
// basic loader, returns error in ec if file was not found
virtual std::istream* load_file(const std::string& file, std::error_code& ec) noexcept
{
return m_loader.load_file(file, ec);
}
protected:
Loader m_loader;
};
using file_based_html_template_processor = html_template_processor<file_loader>;
using rsrc_based_html_template_processor = html_template_processor<rsrc_loader>;
/// \brief the actual definition of zeep::template_processor
#if WEBAPP_USES_RESOURCES
using template_processor = rsrc_based_html_template_processor;
#else
using template_processor = file_based_html_template_processor;
#endif
}
|