File: template-processor.hpp

package info (click to toggle)
libzeep 5.1.8-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 3,596 kB
  • sloc: cpp: 27,393; xml: 7,798; javascript: 180; sh: 37; makefile: 8
file content (233 lines) | stat: -rw-r--r-- 7,644 bytes parent folder | download
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

}