1
// ---------------------------------------------------------------------
2
// pion: a Boost C++ framework for building lightweight HTTP interfaces
3
// ---------------------------------------------------------------------
4
// Copyright (C) 2007-2012 Cloudmeter, Inc. (http://www.cloudmeter.com)
6
// Distributed under the Boost Software License, Version 1.0.
7
// See http://www.boost.org/LICENSE_1_0.txt
10
#include <boost/exception/diagnostic_information.hpp>
11
#include <pion/error.hpp>
12
#include <pion/http/plugin_server.hpp>
13
#include <pion/http/request.hpp>
14
#include <pion/http/request_reader.hpp>
15
#include <pion/http/response_writer.hpp>
16
#include <pion/http/basic_auth.hpp>
17
#include <pion/http/cookie_auth.hpp>
21
namespace pion { // begin namespace pion
22
namespace http { // begin namespace http
25
// plugin_server member functions
27
void plugin_server::add_service(const std::string& resource, http::plugin_service *service_ptr)
29
plugin_ptr<http::plugin_service> plugin_ptr;
30
const std::string clean_resource(strip_trailing_slash(resource));
31
service_ptr->set_resource(clean_resource);
32
m_services.add(clean_resource, service_ptr);
33
http::server::add_resource(clean_resource, boost::ref(*service_ptr));
34
PION_LOG_INFO(m_logger, "Loaded static web service for resource (" << clean_resource << ")");
37
void plugin_server::load_service(const std::string& resource, const std::string& service_name)
39
const std::string clean_resource(strip_trailing_slash(resource));
40
http::plugin_service *service_ptr;
41
service_ptr = m_services.load(clean_resource, service_name);
42
http::server::add_resource(clean_resource, boost::ref(*service_ptr));
43
service_ptr->set_resource(clean_resource);
44
PION_LOG_INFO(m_logger, "Loaded web service plug-in for resource (" << clean_resource << "): " << service_name);
47
void plugin_server::set_service_option(const std::string& resource,
48
const std::string& name, const std::string& value)
50
const std::string clean_resource(strip_trailing_slash(resource));
51
m_services.run(clean_resource, boost::bind(&http::plugin_service::set_option, _1, name, value));
52
PION_LOG_INFO(m_logger, "Set web service option for resource ("
53
<< resource << "): " << name << '=' << value);
56
void plugin_server::load_service_config(const std::string& config_name)
58
std::string config_file;
59
if (! plugin::find_config_file(config_file, config_name))
60
BOOST_THROW_EXCEPTION( error::file_not_found() << error::errinfo_file_name(config_name) );
62
// open the file for reading
63
std::ifstream config_stream;
64
config_stream.open(config_file.c_str(), std::ios::in);
65
if (! config_stream.is_open())
66
BOOST_THROW_EXCEPTION( error::open_file() << error::errinfo_file_name(config_name) );
68
// parse the contents of the file
69
http::auth_ptr my_auth_ptr;
71
PARSE_NEWLINE, PARSE_COMMAND, PARSE_RESOURCE, PARSE_VALUE, PARSE_COMMENT, PARSE_USERNAME
72
} parse_state = PARSE_NEWLINE;
73
std::string command_string;
74
std::string resource_string;
75
std::string username_string;
76
std::string value_string;
77
std::string option_name_string;
78
std::string option_value_string;
79
int c = config_stream.get(); // read the first character
81
while (config_stream) {
84
// parsing command portion (or beginning of line)
87
parse_state = PARSE_COMMENT;
88
} else if (isalpha(c)) {
89
// first char in command
90
parse_state = PARSE_COMMAND;
91
// ignore case for commands
92
command_string += tolower(c);
93
} else if (c != '\r' && c != '\n') { // check for blank lines
94
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
99
// parsing command portion (or beginning of line)
100
if (c == ' ' || c == '\t') {
101
// command finished -> check if valid
102
if (command_string=="path" || command_string=="auth" || command_string=="restrict") {
103
value_string.clear();
104
parse_state = PARSE_VALUE;
105
} else if (command_string=="service" || command_string=="option") {
106
resource_string.clear();
107
parse_state = PARSE_RESOURCE;
108
} else if (command_string=="user") {
109
username_string.clear();
110
parse_state = PARSE_USERNAME;
112
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
114
} else if (! isalpha(c)) {
115
// commands may only contain alpha chars
116
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
118
// ignore case for commands
119
command_string += tolower(c);
124
// parsing resource portion (/hello)
125
if (c == ' ' || c == '\t') {
126
// check for leading whitespace
127
if (! resource_string.empty()) {
129
value_string.clear();
130
parse_state = PARSE_VALUE;
132
} else if (c == '\r' || c == '\n') {
133
// line truncated before value
134
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
136
// add char to resource
137
resource_string += c;
142
// parsing username for user command
143
if (c == ' ' || c == '\t') {
144
// check for leading whitespace
145
if (! username_string.empty()) {
147
value_string.clear();
148
parse_state = PARSE_VALUE;
150
} else if (c == '\r' || c == '\n') {
151
// line truncated before value (missing username)
152
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
154
// add char to username
155
username_string += c;
160
// parsing value portion
161
if (c == '\r' || c == '\n') {
163
if (value_string.empty()) {
164
// value must not be empty
165
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
166
} else if (command_string == "path") {
167
// finished path command
168
try { plugin::add_plugin_directory(value_string); }
169
catch (std::exception& e) {
170
PION_LOG_WARN(m_logger, boost::diagnostic_information(e));
172
} else if (command_string == "auth") {
173
// finished auth command
174
user_manager_ptr user_mgr(new user_manager);
175
if (value_string == "basic"){
176
my_auth_ptr.reset(new http::basic_auth(user_mgr));
178
else if (value_string == "cookie"){
179
my_auth_ptr.reset(new http::cookie_auth(user_mgr));
182
// only basic and cookie authentications are supported
183
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
185
} else if (command_string == "restrict") {
186
// finished restrict command
188
// Authentication type must be defined before restrict
189
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
190
else if (value_string.empty())
191
// No service defined for restrict parameter
192
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
193
my_auth_ptr->add_restrict(value_string);
194
} else if (command_string == "user") {
195
// finished user command
197
// Authentication type must be defined before users
198
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
199
else if (value_string.empty())
200
// No password defined for user parameter
201
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
202
my_auth_ptr->add_user(username_string, value_string);
203
} else if (command_string == "service") {
204
// finished service command
205
load_service(resource_string, value_string);
206
} else if (command_string == "option") {
207
// finished option command
208
std::string::size_type pos = value_string.find('=');
209
if (pos == std::string::npos)
210
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
211
option_name_string = value_string.substr(0, pos);
212
option_value_string = value_string.substr(pos + 1);
213
set_service_option(resource_string, option_name_string,
214
option_value_string);
216
command_string.clear();
217
parse_state = PARSE_NEWLINE;
218
} else if (c == ' ' || c == '\t') {
219
// only skip leading whitespace (value may contain spaces, etc)
220
if (! value_string.empty())
229
// skipping comment line
230
if (c == '\r' || c == '\n')
231
parse_state = PARSE_NEWLINE;
235
// read the next character
236
c = config_stream.get();
239
// update authentication configuration for the server
240
set_authentication(my_auth_ptr);
243
} // end namespace http
244
} // end namespace pion