Line data Source code
1 : // Snap Websites Server -- snap websites server
2 : // Copyright (c) 2011-2019 Made to Order Software Corp. All Rights Reserved
3 : //
4 : // https://snapwebsites.org/
5 : // contact@m2osw.com
6 : //
7 : // This program is free software; you can redistribute it and/or modify
8 : // it under the terms of the GNU General Public License as published by
9 : // the Free Software Foundation; either version 2 of the License, or
10 : // (at your option) any later version.
11 : //
12 : // This program is distributed in the hope that it will be useful,
13 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : // GNU General Public License for more details.
16 : //
17 : // You should have received a copy of the GNU General Public License
18 : // along with this program; if not, write to the Free Software
19 : // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 : #pragma once
21 :
22 : // self
23 : //
24 : #include "snapwebsites/http_strings.h"
25 : #include "snapwebsites/plugins.h"
26 : #include "snapwebsites/snap_child.h"
27 : #include "snapwebsites/snap_communicator.h"
28 : #include "snapwebsites/snap_config.h"
29 : #include "snapwebsites/snap_expr.h"
30 : #include "snapwebsites/snap_pid.h"
31 : #include "snapwebsites/version.h"
32 :
33 : // advgetopt lib
34 : //
35 : #include <advgetopt/advgetopt.h>
36 :
37 : // Qt lib
38 : //
39 : #include <QTranslator>
40 :
41 :
42 : /** \file
43 : * \brief Main header file of the libsnapwebsites library.
44 : *
45 : * This header file defines the server class which is the main
46 : * class in the snapserver daemon. It executes the run() loop.
47 : *
48 : * See the .cpp file for more details.
49 : */
50 :
51 : namespace snap
52 : {
53 :
54 : enum class name_t
55 : {
56 : // low level names
57 : SNAP_NAME_SERVER, // The name of the Snap! Server
58 : SNAP_NAME_CONTEXT, // Cassandra Keyspace
59 : SNAP_NAME_INDEX, // Row used for the domains & websites index
60 : SNAP_NAME_DOMAINS, // Cassandra Table used for domains
61 : SNAP_NAME_WEBSITES, // Cassandra Table used for websites
62 : SNAP_NAME_SITES, // Cassandra Table used for sites (one site per row)
63 : SNAP_NAME_BACKEND, // Cassandra Table used to know where we are with backends
64 : SNAP_NAME_MX, // Cassandra Table used to cache which domains have an MX record and which do not
65 :
66 : // names used by core (server & snap_child)
67 : SNAP_NAME_CORE_ADMINISTRATOR_EMAIL,
68 : SNAP_NAME_CORE_CANONICAL_DOMAIN,
69 : SNAP_NAME_CORE_CONTENT_DISPOSITION,
70 : SNAP_NAME_CORE_CONTENT_LANGUAGE,
71 : SNAP_NAME_CORE_CONTENT_TYPE_HEADER,
72 : SNAP_NAME_CORE_COOKIE_DOMAIN,
73 : SNAP_NAME_CORE_DATA_PATH,
74 : SNAP_NAME_CORE_DATE,
75 : SNAP_NAME_CORE_EMAIL_CONTENT_ENCODING_QUOTED_PRINTABLE,
76 : SNAP_NAME_CORE_EMAIL_CONTENT_TRANSFER_ENCODING,
77 : SNAP_NAME_CORE_EMAIL_FROM,
78 : SNAP_NAME_CORE_EMAIL_IMPORTANCE,
79 : SNAP_NAME_CORE_EMAIL_LIST_UNSUBSCRIBE,
80 : SNAP_NAME_CORE_EMAIL_MESSAGE_ID,
81 : SNAP_NAME_CORE_EMAIL_MIME_VERSION,
82 : SNAP_NAME_CORE_EMAIL_PRECEDENCE,
83 : SNAP_NAME_CORE_EMAIL_PRIORITY_BULK,
84 : SNAP_NAME_CORE_EMAIL_PRIORITY_HIGH,
85 : SNAP_NAME_CORE_EMAIL_PRIORITY_LOW,
86 : SNAP_NAME_CORE_EMAIL_PRIORITY_NORMAL,
87 : SNAP_NAME_CORE_EMAIL_PRIORITY_URGENT,
88 : SNAP_NAME_CORE_EMAIL_REPLY_TO,
89 : SNAP_NAME_CORE_EMAIL_SUBJECT,
90 : SNAP_NAME_CORE_EMAIL_TO,
91 : SNAP_NAME_CORE_EMAIL_X_PRIORITY,
92 : SNAP_NAME_CORE_EMAIL_X_MSMAIL_PRIORITY,
93 : SNAP_NAME_CORE_HTTP_ACCEPT_LANGUAGE,
94 : SNAP_NAME_CORE_HTTP_LINK_HEADER,
95 : SNAP_NAME_CORE_HTTP_USER_AGENT,
96 : SNAP_NAME_CORE_LAST_DYNAMIC_UPDATE,
97 : SNAP_NAME_CORE_LAST_UPDATED,
98 : SNAP_NAME_CORE_LIST_DATA_PATH,
99 : SNAP_NAME_CORE_LIST_DB_PATH,
100 : SNAP_NAME_CORE_LIST_JOURNAL_PATH,
101 : SNAP_NAME_CORE_LOCATION_HEADER,
102 : SNAP_NAME_CORE_MX_LAST_CHECKED,
103 : SNAP_NAME_CORE_MX_RESULT,
104 : SNAP_NAME_CORE_ORIGINAL_RULES,
105 : SNAP_NAME_CORE_PARAM_DEFAULT_PLUGINS,
106 : SNAP_NAME_CORE_PARAM_PLUGINS,
107 : SNAP_NAME_CORE_PARAM_PLUGINS_PATH,
108 : SNAP_NAME_CORE_PARAM_TABLE_SCHEMA_PATH,
109 : SNAP_NAME_CORE_PLUGINS,
110 : SNAP_NAME_CORE_PLUGIN_THRESHOLD,
111 : SNAP_NAME_CORE_REDIRECT,
112 : SNAP_NAME_CORE_REMOTE_ADDR,
113 : SNAP_NAME_CORE_REQUEST_METHOD,
114 : SNAP_NAME_CORE_REQUEST_URI,
115 : SNAP_NAME_CORE_RETRY_AFTER_HEADER,
116 : SNAP_NAME_CORE_RULES,
117 : SNAP_NAME_CORE_SERVER_PROTOCOL,
118 : SNAP_NAME_CORE_SITE_LONG_NAME,
119 : SNAP_NAME_CORE_SITE_NAME,
120 : SNAP_NAME_CORE_SITE_READY,
121 : SNAP_NAME_CORE_SITE_SECURE,
122 : SNAP_NAME_CORE_SITE_SHORT_NAME,
123 : SNAP_NAME_CORE_SITE_STATE,
124 : SNAP_NAME_CORE_SNAPBACKEND,
125 : SNAP_NAME_CORE_STATUS_HEADER,
126 : SNAP_NAME_CORE_TEST_SITE,
127 : SNAP_NAME_CORE_USER_COOKIE_NAME,
128 : SNAP_NAME_CORE_X_POWERED_BY_HEADER
129 : };
130 : char const * get_name(name_t name) __attribute__ ((const));
131 :
132 :
133 :
134 0 : class snapwebsites_exception : public snap_exception
135 : {
136 : public:
137 0 : explicit snapwebsites_exception(char const * whatmsg) : snap_exception("snapwebsites", whatmsg) {}
138 : explicit snapwebsites_exception(std::string const & whatmsg) : snap_exception("snapwebsites", whatmsg) {}
139 0 : explicit snapwebsites_exception(QString const & whatmsg) : snap_exception("snapwebsites", whatmsg) {}
140 : };
141 :
142 0 : class snapwebsites_exception_invalid_parameters : public snapwebsites_exception
143 : {
144 : public:
145 0 : explicit snapwebsites_exception_invalid_parameters(char const * whatmsg) : snapwebsites_exception(whatmsg) {}
146 : explicit snapwebsites_exception_invalid_parameters(std::string const & whatmsg) : snapwebsites_exception(whatmsg) {}
147 0 : explicit snapwebsites_exception_invalid_parameters(QString const & whatmsg) : snapwebsites_exception(whatmsg) {}
148 : };
149 :
150 0 : class snapwebsites_exception_parameter_not_available : public snapwebsites_exception
151 : {
152 : public:
153 0 : explicit snapwebsites_exception_parameter_not_available(char const * whatmsg) : snapwebsites_exception(whatmsg) {}
154 : explicit snapwebsites_exception_parameter_not_available(std::string const & whatmsg) : snapwebsites_exception(whatmsg) {}
155 : explicit snapwebsites_exception_parameter_not_available(QString const & whatmsg) : snapwebsites_exception(whatmsg) {}
156 : };
157 :
158 0 : class snapwebsites_exception_io_error : public snapwebsites_exception
159 : {
160 : public:
161 0 : explicit snapwebsites_exception_io_error(char const * whatmsg) : snapwebsites_exception(whatmsg) {}
162 : explicit snapwebsites_exception_io_error(std::string const & whatmsg) : snapwebsites_exception(whatmsg) {}
163 : explicit snapwebsites_exception_io_error(QString const & whatmsg) : snapwebsites_exception(whatmsg) {}
164 : };
165 :
166 :
167 :
168 :
169 0 : class permission_error_callback
170 : {
171 : public:
172 : class error_by_mime_type
173 : {
174 : public:
175 : virtual ~error_by_mime_type() {}
176 :
177 : virtual void on_handle_error_by_mime_type(snap_child::http_code_t err_code, QString const & err_name, QString const & err_description, QString const & path) = 0;
178 : };
179 :
180 0 : virtual ~permission_error_callback() {}
181 :
182 : virtual void on_error(snap_child::http_code_t const err_code, QString const & err_name, QString const & err_description, QString const & err_details, bool const err_by_mime_type) = 0;
183 : virtual void on_redirect(QString const & err_name, QString const & err_description, QString const & err_details, bool err_security, QString const & path, snap_child::http_code_t const http_code) = 0;
184 : };
185 :
186 : // a simple specialization of the permission_error_callback that quiet
187 : // the errors so they don't get in the way (quiet as in: the end users don't
188 : // see them; it's going to be logged anyway)
189 0 : class quiet_error_callback
190 : : public permission_error_callback
191 : {
192 : public:
193 : quiet_error_callback(snap_child * snap, bool log);
194 : quiet_error_callback(quiet_error_callback const & rhs) = delete;
195 :
196 : quiet_error_callback & operator = (quiet_error_callback const & rhs) = delete;
197 :
198 : virtual void on_error(snap_child::http_code_t const err_code, QString const & err_name, QString const& err_description, QString const & err_details, bool const err_by_mime_type) override;
199 : virtual void on_redirect(QString const & err_name, QString const & err_description, QString const & err_details, bool err_security, QString const & path, snap_child::http_code_t const http_code) override;
200 :
201 : void clear_error();
202 : bool has_error() const;
203 :
204 : private:
205 : snap_child * f_snap = nullptr;
206 : bool f_log = false;
207 : bool f_error = false;
208 : };
209 :
210 :
211 : // implementation specific class
212 : class listener_impl;
213 :
214 :
215 : class server
216 : : public plugins::plugin
217 : {
218 : public:
219 : typedef std::shared_ptr<server> pointer_t;
220 :
221 : // TODO: remove once snapcommunicator is used
222 : typedef QSharedPointer<udp_client_server::udp_server> udp_server_t;
223 :
224 : typedef uint32_t config_flags_t;
225 :
226 : static config_flags_t const SNAP_SERVER_CONFIG_OPTIONAL_SERVER_NAME = 0x01;
227 :
228 : class backend_action
229 : {
230 : public:
231 : virtual ~backend_action() {}
232 : virtual void on_backend_action(QString const & action) = 0;
233 : };
234 :
235 0 : class backend_action_set
236 : {
237 : public:
238 : void add_action(QString const & action, plugins::plugin * p);
239 : bool has_action(QString const & action) const;
240 : void execute_action(QString const & action);
241 : QString get_plugin_name(QString const & action);
242 : void display();
243 :
244 : private:
245 : typedef QMap<QString, backend_action *> actions_map_t;
246 :
247 : actions_map_t f_actions = actions_map_t();
248 : };
249 :
250 : class accessible_flag_t
251 : {
252 : public:
253 0 : accessible_flag_t()
254 : //: f_accessible(false) -- auto-init
255 : //, f_secure(false) -- auto-init
256 0 : {
257 0 : }
258 :
259 0 : bool is_accessible() const { return f_accessible && !f_secure; }
260 : void mark_as_accessible() { f_accessible = true; }
261 : void mark_as_secure() { f_secure = true; }
262 :
263 : private:
264 : // prevent copies or a user could reset the flag!
265 : accessible_flag_t(accessible_flag_t const & rhs) = delete;
266 : accessible_flag_t & operator = (accessible_flag_t const & rhs) = delete;
267 :
268 : bool f_accessible = false;
269 : bool f_secure = false;
270 : };
271 :
272 : static pointer_t instance();
273 : virtual ~server();
274 :
275 : [[noreturn]] static void exit( int const code );
276 :
277 : static char const * version();
278 : static int version_major();
279 : static int version_minor();
280 : static int version_patch();
281 : virtual void show_version();
282 :
283 : static std::string get_server_name();
284 : static void verify_server_name(std::string & server_name);
285 :
286 : // plugins::plugin implementation
287 : virtual QString icon() const;
288 : virtual QString description() const;
289 : virtual QString dependencies() const;
290 : virtual void bootstrap(snap_child * snap);
291 : virtual int64_t do_update(int64_t last_updated);
292 :
293 : [[noreturn]] void usage();
294 : void setup_as_backend();
295 0 : bool is_debug() const { return f_debug; }
296 : bool is_foreground() const { return f_foreground; }
297 : bool is_backend() const { return f_backend; }
298 : static size_t thread_count();
299 : void set_config_filename(std::string const & filename);
300 : void config( int argc, char * argv[] );
301 : void set_translation(QString const xml_data);
302 : QString get_parameter(QString const & param_name) const;
303 : void set_parameter( QString const & param_name, QString const & value );
304 : void prepare_qtapp( int argc, char * argv[] );
305 : bool check_cassandra(QString const & mandatory_table, bool & timer_required);
306 :
307 : void create_messenger_instance( bool const use_thread = false );
308 :
309 : void detach();
310 : void server_loop_ready();
311 : void listen();
312 : void backend();
313 : int snapdbproxy_port() const { return f_snapdbproxy_port; }
314 : QString const & snapdbproxy_addr() const { return f_snapdbproxy_addr; }
315 : void capture_zombies(pid_t child_pid);
316 : void process_message(snap_communicator_message const & message);
317 :
318 : unsigned long connections_count();
319 :
320 : std::string servername() const;
321 : void set_service_name(std::string const & service_name);
322 : std::string const & get_service_name() const;
323 :
324 : void configure_messenger_logging( snap_communicator::snap_tcp_client_permanent_message_connection::pointer_t ptr );
325 :
326 : void udp_ping_server( QString const & service, QString const & uri );
327 : void udp_rusage(QString const & process_name);
328 : static void block_ip( QString const & uri, QString const & period = QString(), QString const & reason = QString() );
329 :
330 : snap_config const & get_parameters() const;
331 :
332 : #ifdef SNAP_NO_FORK
333 : bool nofork() const;
334 : #endif
335 :
336 0 : SNAP_SIGNAL_WITH_MODE(init, (), (), NEITHER);
337 : SNAP_SIGNAL_WITH_MODE(update, (int64_t last_updated), (last_updated), NEITHER);
338 0 : SNAP_SIGNAL_WITH_MODE(process_cookies, (), (), NEITHER);
339 0 : SNAP_SIGNAL_WITH_MODE(attach_to_session, (), (), NEITHER);
340 0 : SNAP_SIGNAL_WITH_MODE(detach_from_session, (), (), NEITHER);
341 0 : SNAP_SIGNAL_WITH_MODE(user_status, (snap_child::user_status_t status, snap_child::user_identifier_t id), (status, id), NEITHER);
342 0 : SNAP_SIGNAL_WITH_MODE(define_locales, (http_strings::WeightedHttpString & locales), (locales), NEITHER);
343 0 : SNAP_SIGNAL_WITH_MODE(process_post, (QString const & url), (url), NEITHER);
344 0 : SNAP_SIGNAL_WITH_MODE(execute, (QString const & url), (url), NEITHER);
345 0 : SNAP_SIGNAL_WITH_MODE(register_backend_cron, (backend_action_set & actions), (actions), NEITHER);
346 0 : SNAP_SIGNAL_WITH_MODE(register_backend_action, (backend_action_set & actions), (actions), NEITHER);
347 0 : SNAP_SIGNAL_WITH_MODE(backend_process, (), (), NEITHER);
348 0 : SNAP_SIGNAL_WITH_MODE(save_content, (), (), NEITHER);
349 : SNAP_SIGNAL_WITH_MODE(xss_filter, (QDomNode & node,
350 : QString const & accepted_tags,
351 : QString const & accepted_attributes),
352 : (node, accepted_tags, accepted_attributes), NEITHER);
353 0 : SNAP_SIGNAL_WITH_MODE(improve_signature, (QString const & path, QDomDocument doc, QDomElement & signature_tag), (path, doc, signature_tag), NEITHER);
354 0 : SNAP_SIGNAL(load_file, (snap_child::post_file_t & file, bool & found), (file, found));
355 0 : SNAP_SIGNAL_WITH_MODE(table_is_accessible, (QString const & table, accessible_flag_t & accessible), (table, accessible), NEITHER);
356 0 : SNAP_SIGNAL_WITH_MODE(add_snap_expr_functions, (snap_expr::functions_t & functions), (functions), NEITHER);
357 0 : SNAP_SIGNAL_WITH_MODE(output_result, (QString const & uri_path, QByteArray & output), (uri_path, output), NEITHER);
358 :
359 : protected:
360 : server();
361 : static server::pointer_t get_instance();
362 : static server::pointer_t set_instance(pointer_t server);
363 :
364 : // See TODO in server::prepare_cassandra()
365 : QString f_snapdbproxy_addr = QString(); // NO DEFAULT, if isEmpty() then we are not connected / cannot connect to snapdbproxy
366 : int32_t f_snapdbproxy_port = 0;
367 : bool f_snaplock = false;
368 : snap_config f_parameters = snap_config();
369 :
370 : private:
371 : typedef std::shared_ptr<advgetopt::getopt> getopt_ptr_t;
372 :
373 : friend class server_interrupt;
374 : friend class listener_impl;
375 :
376 : static void sighandler( int sig );
377 : static void sigloghandler( int sig );
378 :
379 : void process_connection(tcp_client_server::bio_client::pointer_t client);
380 : void stop_thread_func();
381 : void stop(bool quitting);
382 :
383 : static pointer_t g_instance;
384 :
385 : QTranslator f_translator;
386 : QByteArray f_translation_xml = QByteArray();
387 :
388 : std::string f_servername = std::string();
389 : std::string f_service_name = std::string();
390 : snap_pid::pointer_t f_pid_file = snap_pid::pointer_t();
391 : bool f_debug = false;
392 : bool f_foreground = false;
393 : bool f_backend = false;
394 : bool f_force_restart = false;
395 : bool f_firewall_is_active = false;
396 : bool f_firewall_up = false;
397 : //QMap<QString, bool> f_created_table = QMap<QString, bool>();
398 :
399 : uint64_t f_connections_count = 0;
400 : snap_child_vector_t f_children_running = snap_child_vector_t();
401 : snap_child_vector_t f_children_waiting = snap_child_vector_t();
402 :
403 : getopt_ptr_t f_opt = getopt_ptr_t();
404 :
405 : #ifdef SNAP_NO_FORK
406 : bool f_nofork = false;
407 : #endif
408 : };
409 :
410 : } // namespace snap
411 : // vim: ts=4 sw=4 et
|