Fawkes API  Fawkes Development Version
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
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-2008 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include "webview_thread.h"
24 #include "static_processor.h"
25 #include "blackboard_processor.h"
26 #include "startpage_processor.h"
27 #include "plugins_processor.h"
28 #include "service_browse_handler.h"
29 #include "header_generator.h"
30 #include "footer_generator.h"
31 #include "user_verifier.h"
32 
33 #include <core/version.h>
34 #include <core/exceptions/system.h>
35 #include <utils/system/file.h>
36 #include <utils/system/hostinfo.h>
37 #include <webview/request_dispatcher.h>
38 #include <webview/page_reply.h>
39 #include <webview/server.h>
40 #include <webview/url_manager.h>
41 #include <webview/nav_manager.h>
42 
43 #include <sys/wait.h>
44 
45 using namespace fawkes;
46 
47 
48 /** Prefix for the WebStaticRequestProcessor. */
49 const char *WebviewThread::STATIC_URL_PREFIX = "/static";
50 /** Prefix for the WebBlackBoardRequestProcessor. */
51 const char *WebviewThread::BLACKBOARD_URL_PREFIX = "/blackboard";
52 /** Prefix for the WebPluginsRequestProcessor. */
53 const char *WebviewThread::PLUGINS_URL_PREFIX = "/plugins";
54 
55 /** @class WebviewThread "webview_thread.h"
56  * Webview Thread.
57  * This thread runs the HTTP server and handles requests via the
58  * WebRequestDispatcher.
59  * @author Tim Niemueller
60  */
61 
62 
63 /** Constructor. */
65  : Thread("WebviewThread", Thread::OPMODE_CONTINUOUS),
66  LoggerAspect(&__cache_logger)
67 {
69 }
70 
71 
72 WebviewThread::~WebviewThread()
73 {
74 }
75 
76 void
78 {
79  __cfg_port = config->get_uint("/webview/port");
80 
81  bool __cfg_use_ssl = false;
82  try {
83  __cfg_use_ssl = config->get_bool("/webview/use_ssl");
84  } catch (Exception &e) {}
85 
86  if (__cfg_use_ssl) {
87  __cfg_ssl_create = false;
88  try {
89  __cfg_ssl_create = config->get_bool("/webview/ssl_create");
90  } catch (Exception &e) {}
91 
92  __cfg_ssl_key = config->get_string("/webview/ssl_key");
93  __cfg_ssl_cert = config->get_string("/webview/ssl_cert");
94 
95  if (__cfg_ssl_key[0] != '/')
96  __cfg_ssl_key = std::string(CONFDIR"/") + __cfg_ssl_key;
97 
98  if (__cfg_ssl_cert[0] != '/')
99  __cfg_ssl_cert = std::string(CONFDIR"/") + __cfg_ssl_cert;
100 
101  logger->log_debug(name(), "Key: %s Cert: %s", __cfg_ssl_key.c_str(),
102  __cfg_ssl_cert.c_str());
103 
104  if (! File::exists(__cfg_ssl_key.c_str())) {
105  if (File::exists(__cfg_ssl_cert.c_str())) {
106  throw Exception("Key file %s does not exist, but certificate file %s "
107  "does", __cfg_ssl_key.c_str(), __cfg_ssl_cert.c_str());
108  } else if (__cfg_ssl_create) {
109  ssl_create(__cfg_ssl_key.c_str(), __cfg_ssl_cert.c_str());
110  } else {
111  throw Exception("Key file %s does not exist", __cfg_ssl_key.c_str());
112  }
113  } else if (! File::exists(__cfg_ssl_cert.c_str())) {
114  throw Exception("Certificate file %s does not exist, but key file %s "
115  "does", __cfg_ssl_key.c_str(), __cfg_ssl_cert.c_str());
116  }
117  }
118 
119  bool __cfg_use_basic_auth = false;
120  try {
121  __cfg_use_basic_auth = config->get_bool("/webview/use_basic_auth");
122  } catch (Exception &e) {}
123  __cfg_basic_auth_realm = "Fawkes Webview";
124  try {
125  __cfg_basic_auth_realm = config->get_bool("/webview/basic_auth_realm");
126  } catch (Exception &e) {}
127 
128 
129  __cache_logger.clear();
130 
131  __webview_service = new NetworkService(nnresolver, "Fawkes Webview on %h",
132  "_http._tcp", __cfg_port);
133  __webview_service->add_txt("fawkesver=%u.%u.%u",
134  FAWKES_VERSION_MAJOR, FAWKES_VERSION_MINOR,
135  FAWKES_VERSION_MICRO);
136  __service_browse_handler = new WebviewServiceBrowseHandler(logger, __webview_service);
137 
138  __header_gen = new WebviewHeaderGenerator(webview_nav_manager);
139  __footer_gen = new WebviewFooterGenerator(__service_browse_handler);
140 
141  __dispatcher = new WebRequestDispatcher(webview_url_manager,
142  __header_gen, __footer_gen);
143 
144 
145  try {
146  if (__cfg_use_ssl) {
147  __webserver = new WebServer(__cfg_port, __dispatcher, __cfg_ssl_key.c_str(),
148  __cfg_ssl_cert.c_str(), logger);
149  } else {
150  __webserver = new WebServer(__cfg_port, __dispatcher, logger);
151  }
152 
153  if (__cfg_use_basic_auth) {
154  __user_verifier = new WebviewUserVerifier(config, logger);
155  __webserver->setup_basic_auth(__cfg_basic_auth_realm.c_str(),
156  __user_verifier);
157  }
158  } catch (Exception &e) {
159  delete __webview_service;
160  delete __service_browse_handler;
161  delete __header_gen;
162  delete __footer_gen;
163  delete __dispatcher;
164  throw;
165  }
166 
167 
168  __startpage_processor = new WebviewStartPageRequestProcessor(&__cache_logger);
169  __static_processor = new WebviewStaticRequestProcessor(STATIC_URL_PREFIX, RESDIR"/webview", logger);
172  webview_url_manager->register_baseurl("/", __startpage_processor);
176 
179 
180  logger->log_info("WebviewThread", "Listening for HTTP connections on port %u", __cfg_port);
181 
182  service_publisher->publish_service(__webview_service);
183  service_browser->watch_service("_http._tcp", __service_browse_handler);
184 
185 }
186 
187 void
189 {
190  service_publisher->unpublish_service(__webview_service);
191  service_browser->unwatch_service("_http._tcp", __service_browse_handler);
192 
197 
200 
201  delete __webserver;
202 
203  delete __webview_service;
204  delete __service_browse_handler;
205 
206  delete __dispatcher;
207  delete __static_processor;
208  delete __blackboard_processor;
209  delete __startpage_processor;
210  delete __plugins_processor;
211  delete __footer_gen;
212  delete __header_gen;
213  __dispatcher = NULL;
214 }
215 
216 
217 void
219 {
220  __webserver->process();
221 }
222 
223 
224 void
225 WebviewThread::ssl_create(const char *ssl_key_file, const char *ssl_cert_file)
226 {
227  logger->log_info(name(), "Creating SSL key and certificate. "
228  "This may take a while...");
229  HostInfo h;
230 
231  char *cmd;
232  if (asprintf(&cmd, "openssl req -new -x509 -batch -nodes -days 365 "
233  "-subj \"/C=XX/L=World/O=Fawkes/CN=%s.local\" "
234  "-out \"%s\" -keyout \"%s\" >/dev/null 2>&1",
235  h.short_name(), ssl_cert_file, ssl_key_file) == -1)
236  {
237  throw OutOfMemoryException("Webview/SSL: Could not generate OpenSSL string");
238  }
239 
240  int status = system(cmd);
241  free(cmd);
242 
243  if (WEXITSTATUS(status) != 0) {
244  throw Exception("Failed to auto-generate key/certificate pair");
245  }
246 }