Fawkes API  Fawkes Development Version
webview_thread.cpp
1 
2 /***************************************************************************
3  * webview_thread.cpp - Thread that handles web interface requests
4  *
5  * Created: Mon Oct 13 17:51:31 2008 (I5 Developer's Day)
6  * Copyright 2006-2014 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU Library General Public License for more details.
18  *
19  * Read the full text in the LICENSE.GPL file in the doc directory.
20  */
21 
22 #include "webview_thread.h"
23 #include "static_processor.h"
24 #include "blackboard_processor.h"
25 #include "startpage_processor.h"
26 #include "plugins_processor.h"
27 #ifdef HAVE_TF
28 # include "tf_processor.h"
29 #endif
30 #ifdef HAVE_JPEG
31 # include "image_processor.h"
32 #endif
33 #include "service_browse_handler.h"
34 #include "header_generator.h"
35 #include "footer_generator.h"
36 #include "user_verifier.h"
37 
38 #include <core/version.h>
39 #include <core/exceptions/system.h>
40 #include <utils/system/file.h>
41 #include <utils/system/hostinfo.h>
42 #include <webview/request_dispatcher.h>
43 #include <webview/page_reply.h>
44 #include <webview/server.h>
45 #include <webview/url_manager.h>
46 #include <webview/nav_manager.h>
47 #include <utils/misc/string_conversions.h>
48 
49 #include <sys/wait.h>
50 
51 using namespace fawkes;
52 
53 
54 /** Prefix for the WebStaticRequestProcessor. */
55 const char *WebviewThread::STATIC_URL_PREFIX = "/static";
56 /** Prefix for the WebBlackBoardRequestProcessor. */
57 const char *WebviewThread::BLACKBOARD_URL_PREFIX = "/blackboard";
58 /** Prefix for the WebPluginsRequestProcessor. */
59 const char *WebviewThread::PLUGINS_URL_PREFIX = "/plugins";
60 /** Prefix for the WebTfRequestProcessor. */
61 const char *WebviewThread::TF_URL_PREFIX = "/tf";
62 /** Prefix for the WebMJPEGRequestProcessor. */
63 const char *WebviewThread::IMAGE_URL_PREFIX = "/images";
64 
65 /** @class WebviewThread "webview_thread.h"
66  * Webview Thread.
67  * This thread runs the HTTP server and handles requests via the
68  * WebRequestDispatcher.
69  * @author Tim Niemueller
70  */
71 
72 
73 /** Constructor. */
75  : Thread("WebviewThread", Thread::OPMODE_CONTINUOUS),
76  LoggerAspect(&__cache_logger)
77 {
79 }
80 
81 
82 WebviewThread::~WebviewThread()
83 {
84 }
85 
86 void
88 {
89  __cfg_port = config->get_uint("/webview/port");
90 
91  WebReply::set_caching(config->get_bool("/webview/client_side_caching"));
92 
93  __webview_service = NULL;
94  __service_browse_handler = NULL;
95  __header_gen = NULL;
96  __footer_gen = NULL;
97  __dispatcher = NULL;
98 
99  __cfg_use_ssl = false;
100  try {
101  __cfg_use_ssl = config->get_bool("/webview/use_ssl");
102  } catch (Exception &e) {}
103 
104  __cfg_use_ipv4 = config->get_bool("/network/ipv4/enable");
105  __cfg_use_ipv6 = config->get_bool("/network/ipv6/enable");
106 
107  if (__cfg_use_ssl) {
108  __cfg_ssl_create = false;
109  try {
110  __cfg_ssl_create = config->get_bool("/webview/ssl_create");
111  } catch (Exception &e) {}
112 
113  __cfg_ssl_key = config->get_string("/webview/ssl_key");
114  __cfg_ssl_cert = config->get_string("/webview/ssl_cert");
115 
116  try {
117  __cfg_ssl_cipher_suite = config->get_string("/webview/ssl_cipher_suite");
118  logger->log_debug(name(), "Using cipher suite %s", __cfg_ssl_cipher_suite.c_str());
119  } catch (Exception &e) {}
120 
121  if (__cfg_ssl_key[0] != '/')
122  __cfg_ssl_key = std::string(CONFDIR"/") + __cfg_ssl_key;
123 
124  if (__cfg_ssl_cert[0] != '/')
125  __cfg_ssl_cert = std::string(CONFDIR"/") + __cfg_ssl_cert;
126 
127  logger->log_debug(name(), "Key: %s Cert: %s", __cfg_ssl_key.c_str(),
128  __cfg_ssl_cert.c_str());
129 
130  if (! File::exists(__cfg_ssl_key.c_str())) {
131  if (File::exists(__cfg_ssl_cert.c_str())) {
132  throw Exception("Key file %s does not exist, but certificate file %s "
133  "does", __cfg_ssl_key.c_str(), __cfg_ssl_cert.c_str());
134  } else if (__cfg_ssl_create) {
135  ssl_create(__cfg_ssl_key.c_str(), __cfg_ssl_cert.c_str());
136  } else {
137  throw Exception("Key file %s does not exist", __cfg_ssl_key.c_str());
138  }
139  } else if (! File::exists(__cfg_ssl_cert.c_str())) {
140  throw Exception("Certificate file %s does not exist, but key file %s "
141  "does", __cfg_ssl_key.c_str(), __cfg_ssl_cert.c_str());
142  }
143  }
144 
145  __cfg_use_basic_auth = false;
146  try {
147  __cfg_use_basic_auth = config->get_bool("/webview/use_basic_auth");
148  } catch (Exception &e) {}
149  __cfg_basic_auth_realm = "Fawkes Webview";
150  try {
151  __cfg_basic_auth_realm = config->get_bool("/webview/basic_auth_realm");
152  } catch (Exception &e) {}
153 
154  __cfg_access_log = "";
155  try {
156  __cfg_access_log = config->get_string("/webview/access_log");
157  } catch (Exception &e) {}
158 
159 
160  __cache_logger.clear();
161 
162  __webview_service = new NetworkService(nnresolver, "Fawkes Webview on %h",
163  "_http._tcp", __cfg_port);
164  __webview_service->add_txt("fawkesver=%u.%u.%u",
165  FAWKES_VERSION_MAJOR, FAWKES_VERSION_MINOR,
166  FAWKES_VERSION_MICRO);
167  __service_browse_handler = new WebviewServiceBrowseHandler(logger, __webview_service);
168 
169  __header_gen = new WebviewHeaderGenerator(webview_nav_manager);
170  __footer_gen = new WebviewFooterGenerator(__service_browse_handler);
171 
172  __dispatcher = new WebRequestDispatcher(webview_url_manager,
173  __header_gen, __footer_gen);
174 
175 
176  try {
177  if (__cfg_use_ssl) {
178  __webserver = new WebServer(__cfg_port, __dispatcher,
179  __cfg_ssl_key.c_str(), __cfg_ssl_cert.c_str(),
180  __cfg_ssl_cipher_suite.empty() ? NULL : __cfg_ssl_cipher_suite.c_str(),
181  logger, __cfg_use_ipv4, __cfg_use_ipv6);
182  } else {
183  __webserver = new WebServer(__cfg_port, __dispatcher, logger, __cfg_use_ipv4, __cfg_use_ipv6);
184  }
185 
186  if (__cfg_use_basic_auth) {
187  __user_verifier = new WebviewUserVerifier(config, logger);
188  __webserver->setup_basic_auth(__cfg_basic_auth_realm.c_str(),
189  __user_verifier);
190  }
192 
193  if (__cfg_access_log != "") {
194  logger->log_debug(name(), "Setting up access log %s", __cfg_access_log.c_str());
195  __webserver->setup_access_log(__cfg_access_log.c_str());
196  }
197  } catch (Exception &e) {
198  delete __webview_service;
199  delete __service_browse_handler;
200  delete __header_gen;
201  delete __footer_gen;
202  delete __dispatcher;
203  throw;
204  }
205 
206 
207  __startpage_processor = new WebviewStartPageRequestProcessor(&__cache_logger);
208  // get all directories for the static processor
209  std::vector<std::string> static_dirs = config->get_strings("/webview/static-dirs");
210  static_dirs = StringConversions::resolve_paths(static_dirs);
211  std::vector<const char *> static_dirs_cstr = std::vector<const char *>(static_dirs.size());
212  for(unsigned int i = 0; i < static_dirs.size(); i++)
213  {
214  static_dirs_cstr[i] = static_dirs[i].c_str();
215  }
216  __static_processor = new WebviewStaticRequestProcessor(STATIC_URL_PREFIX, static_dirs_cstr, logger);
219 #ifdef HAVE_TF
220  __tf_processor = new WebviewTfRequestProcessor(TF_URL_PREFIX, tf_listener);
221 #endif
222 #ifdef HAVE_JPEG
223  __image_processor = new WebviewImageRequestProcessor(IMAGE_URL_PREFIX, config,
224  logger, thread_collector);
225 #endif
226  webview_url_manager->register_baseurl("/", __startpage_processor);
230 #ifdef HAVE_TF
232 #endif
233 #ifdef HAVE_JPEG
235 #endif
236 
238 #ifdef HAVE_TF
240 #endif
242 #ifdef HAVE_JPEG
244 #endif
245 
246  std::string afs;
247  if (__cfg_use_ipv4 && __cfg_use_ipv6) {
248  afs = "IPv4,IPv6";
249  } else if (__cfg_use_ipv4) {
250  afs = "IPv4";
251  } else if (__cfg_use_ipv6) {
252  afs = "IPv6";
253  }
254  logger->log_info("WebviewThread", "Listening for HTTP%s connections on port %u (%s)",
255  __cfg_use_ssl ? "S" : "", __cfg_port, afs.c_str());
256 
257  service_publisher->publish_service(__webview_service);
258  service_browser->watch_service("_http._tcp", __service_browse_handler);
259 }
260 
261 
262 void
264 {
265  try {
266  service_publisher->unpublish_service(__webview_service);
267  } catch (Exception &e) {} // ignored, can happen if avahi-daemon not running
268  try {
269  service_browser->unwatch_service("_http._tcp", __service_browse_handler);
270  } catch (Exception &e) {} // ignored, can happen if avahi-daemon not running
271 
277 
278 #ifdef HAVE_TF
280 #endif
281 
284 #ifdef HAVE_TF
286 #endif
287 #ifdef HAVE_JPEG
289 #endif
290 
291  delete __webserver;
292 
293  delete __webview_service;
294  delete __service_browse_handler;
295 
296  delete __dispatcher;
297  delete __static_processor;
298  delete __blackboard_processor;
299  delete __startpage_processor;
300  delete __plugins_processor;
301 #ifdef HAVE_TF
302  delete __tf_processor;
303 #endif
304 #ifdef HAVE_JPEG
305  delete __image_processor;
306 #endif
307  delete __footer_gen;
308  delete __header_gen;
309  __dispatcher = NULL;
310 }
311 
312 
313 void
315 {
316  __webserver->process();
317 }
318 
319 
320 void
321 WebviewThread::ssl_create(const char *ssl_key_file, const char *ssl_cert_file)
322 {
323  logger->log_info(name(), "Creating SSL key and certificate. "
324  "This may take a while...");
325  HostInfo h;
326 
327  char *cmd;
328  if (asprintf(&cmd, "openssl req -new -x509 -batch -nodes -days 365 "
329  "-subj \"/C=XX/L=World/O=Fawkes/CN=%s.local\" "
330  "-out \"%s\" -keyout \"%s\" >/dev/null 2>&1",
331  h.short_name(), ssl_cert_file, ssl_key_file) == -1)
332  {
333  throw OutOfMemoryException("Webview/SSL: Could not generate OpenSSL string");
334  }
335 
336  int status = system(cmd);
337  free(cmd);
338 
339  if (WEXITSTATUS(status) != 0) {
340  throw Exception("Failed to auto-generate key/certificate pair");
341  }
342 }
WebNavManager * webview_nav_manager
Webview navigation manager.
Definition: webview.h:52
Thread aspect that allows to provide a logger to Fawkes.
Definition: logger.h:36
void setup_basic_auth(const char *realm, WebUserVerifier *verifier)
Setup basic authentication.
Definition: server.cpp:221
virtual void unwatch_service(const char *service_type, ServiceBrowseHandler *h)=0
Remove browse handler for specific service.
Web request dispatcher.
PluginManager * plugin_manager
This is the member used to access the PluginManager.
Encapsulation of the libmicrohttpd webserver.
Definition: server.h:43
const char * short_name()
Get short hostname (up to first dot).
Definition: hostinfo.cpp:114
virtual void init()
Initialize the thread.
virtual void finalize()
Finalize the thread.
virtual void log_info(const char *component, const char *format,...)=0
Log informational message.
static const char * TF_URL_PREFIX
Prefix for the WebTfRequestProcessor.
void clear()
Clear messages.
Definition: cache.cpp:75
WebviewThread()
Constructor.
ServicePublisher * service_publisher
Service publisher to publish services on the network.
Definition: network.h:49
virtual void unpublish_service(NetworkService *service)=0
Revoke service publication.
virtual void publish_service(NetworkService *service)=0
Publish service.
Image stream web processor.
static const char * STATIC_URL_PREFIX
Prefix for the WebStaticRequestProcessor.
Fawkes library namespace.
virtual bool get_bool(const char *path)=0
Get value from configuration which is of type bool.
void process()
Process requests.
Definition: server.cpp:271
Thread class encapsulation of pthreads.
Definition: thread.h:42
void set_prepfin_conc_loop(bool concurrent=true)
Set concurrent execution of prepare_finalize() and loop().
Definition: thread.cpp:727
Transfrom data web request processor.
Definition: tf_processor.h:38
Static file web processor.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:44
static const char * IMAGE_URL_PREFIX
Prefix for the WebMJPEGRequestProcessor.
WebRequestManager * webview_request_manager
Webview request manager.
Definition: webview.h:54
Host information.
Definition: hostinfo.h:31
Base class for exceptions in Fawkes.
Definition: exception.h:36
WebUrlManager * webview_url_manager
Webview request processor manager.
Definition: webview.h:50
void unregister_baseurl(const char *url_prefix)
Remove a request processor.
Definition: url_manager.cpp:87
BlackBoard web request processor.
void setup_request_manager(WebRequestManager *request_manager)
Setup this server as request manager.
Definition: server.cpp:242
NetworkNameResolver * nnresolver
Network name resolver to lookup IP addresses of hostnames and vice versa.
Definition: network.h:48
Webview user verification.
Definition: user_verifier.h:33
const char * name() const
Get name of thread.
Definition: thread.h:95
static const char * BLACKBOARD_URL_PREFIX
Prefix for the WebBlackBoardRequestProcessor.
void add_nav_entry(std::string baseurl, std::string name)
Add a navigation entry.
Definition: nav_manager.cpp:61
Representation of a service announced or found via service discovery (i.e.
Definition: service.h:37
Web request processor for the start page.
ServiceBrowser * service_browser
Service browser to browse services on the network.
Definition: network.h:50
static const char * PLUGINS_URL_PREFIX
Prefix for the WebPluginsRequestProcessor.
virtual void log_debug(const char *component, const char *format,...)=0
Log debug message.
virtual std::vector< std::string > get_strings(const char *path)=0
Get list of values from configuration which is of type string.
void setup_access_log(const char *filename)
Setup access log.
Definition: server.cpp:231
Webview page footer.
Browse handler to detect other Webview instances on the network.
void remove_nav_entry(std::string baseurl)
Remove a navigation entry.
Definition: nav_manager.cpp:76
Webview page header.
virtual unsigned int get_uint(const char *path)=0
Get value from configuration which is of type unsigned int.
virtual void loop()
Code to execute in the thread.
Configuration * config
This is the Configuration member used to access the configuration.
Definition: configurable.h:44
virtual void watch_service(const char *service_type, ServiceBrowseHandler *h)=0
Add browse handler for specific service.
void register_baseurl(const char *url_prefix, WebRequestProcessor *processor)
Add a request processor.
Definition: url_manager.cpp:64
System ran out of memory and desired operation could not be fulfilled.
Definition: system.h:32
virtual std::string get_string(const char *path)=0
Get value from configuration which is of type string.
BlackBoard * blackboard
This is the BlackBoard instance you can use to interact with the BlackBoard.
Definition: blackboard.h:44
Plugins web request processor.