http_plugin_server.cpp
// ---------------------------------------------------------------------
// pion: a Boost C++ framework for building lightweight HTTP interfaces
// ---------------------------------------------------------------------
// Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/exception/diagnostic_information.hpp>
#include <pion/error.hpp>
#include <pion/http/plugin_server.hpp>
#include <pion/http/request.hpp>
#include <pion/http/basic_auth.hpp>
#include <pion/http/cookie_auth.hpp>
#include <fstream>
namespace pion { // begin namespace pion
namespace http { // begin namespace http
// plugin_server member functions
void plugin_server::add_service(const std::string& resource, http::plugin_service *service_ptr)
{
plugin_ptr<http::plugin_service> plugin_ptr;
const std::string clean_resource(strip_trailing_slash(resource));
service_ptr->set_resource(clean_resource);
m_services.add(clean_resource, service_ptr);
http::server::add_resource(clean_resource, boost::ref(*service_ptr));
PION_LOG_INFO(m_logger, "Loaded static web service for resource (" << clean_resource << ")");
}
void plugin_server::load_service(const std::string& resource, const std::string& service_name)
{
const std::string clean_resource(strip_trailing_slash(resource));
http::plugin_service *service_ptr;
service_ptr = m_services.load(clean_resource, service_name);
http::server::add_resource(clean_resource, boost::ref(*service_ptr));
service_ptr->set_resource(clean_resource);
PION_LOG_INFO(m_logger, "Loaded web service plug-in for resource (" << clean_resource << "): " << service_name);
}
void plugin_server::set_service_option(const std::string& resource,
const std::string& name, const std::string& value)
{
const std::string clean_resource(strip_trailing_slash(resource));
m_services.run(clean_resource, boost::bind(&http::plugin_service::set_option, _1, name, value));
PION_LOG_INFO(m_logger, "Set web service option for resource ("
<< resource << "): " << name << '=' << value);
}
void plugin_server::load_service_config(const std::string& config_name)
{
std::string config_file;
if (! plugin::find_config_file(config_file, config_name))
BOOST_THROW_EXCEPTION( error::file_not_found() << error::errinfo_file_name(config_name) );
// open the file for reading
std::ifstream config_stream;
config_stream.open(config_file.c_str(), std::ios::in);
if (! config_stream.is_open())
BOOST_THROW_EXCEPTION( error::open_file() << error::errinfo_file_name(config_name) );
// parse the contents of the file
http::auth_ptr my_auth_ptr;
enum ParseState {
PARSE_NEWLINE, PARSE_COMMAND, PARSE_RESOURCE, PARSE_VALUE, PARSE_COMMENT, PARSE_USERNAME
} parse_state = PARSE_NEWLINE;
std::string command_string;
std::string resource_string;
std::string username_string;
std::string value_string;
std::string option_name_string;
std::string option_value_string;
int c = config_stream.get(); // read the first character
while (config_stream) {
switch(parse_state) {
case PARSE_NEWLINE:
// parsing command portion (or beginning of line)
if (c == '#') {
// line is a comment
parse_state = PARSE_COMMENT;
} else if (isalpha(c)) {
// first char in command
parse_state = PARSE_COMMAND;
// ignore case for commands
command_string += tolower(c);
} else if (c != '\r' && c != '\n') { // check for blank lines
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
}
break;
case PARSE_COMMAND:
// parsing command portion (or beginning of line)
if (c == ' ' || c == '\t') {
// command finished -> check if valid
if (command_string=="path" || command_string=="auth" || command_string=="restrict") {
value_string.clear();
parse_state = PARSE_VALUE;
} else if (command_string=="service" || command_string=="option") {
resource_string.clear();
parse_state = PARSE_RESOURCE;
} else if (command_string=="user") {
username_string.clear();
parse_state = PARSE_USERNAME;
} else {
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
}
} else if (! isalpha(c)) {
// commands may only contain alpha chars
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
} else {
// ignore case for commands
command_string += tolower(c);
}
break;
case PARSE_RESOURCE:
// parsing resource portion (/hello)
if (c == ' ' || c == '\t') {
// check for leading whitespace
if (! resource_string.empty()) {
// resource finished
value_string.clear();
parse_state = PARSE_VALUE;
}
} else if (c == '\r' || c == '\n') {
// line truncated before value
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
} else {
// add char to resource
resource_string += c;
}
break;
case PARSE_USERNAME:
// parsing username for user command
if (c == ' ' || c == '\t') {
// check for leading whitespace
if (! username_string.empty()) {
// username finished
value_string.clear();
parse_state = PARSE_VALUE;
}
} else if (c == '\r' || c == '\n') {
// line truncated before value (missing username)
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
} else {
// add char to username
username_string += c;
}
break;
case PARSE_VALUE:
// parsing value portion
if (c == '\r' || c == '\n') {
// value is finished
if (value_string.empty()) {
// value must not be empty
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
} else if (command_string == "path") {
// finished path command
try { plugin::add_plugin_directory(value_string); }
catch (std::exception& e) {
PION_LOG_WARN(m_logger, boost::diagnostic_information(e));
}
} else if (command_string == "auth") {
// finished auth command
user_manager_ptr user_mgr(new user_manager);
if (value_string == "basic"){
my_auth_ptr.reset(new http::basic_auth(user_mgr));
}
else if (value_string == "cookie"){
my_auth_ptr.reset(new http::cookie_auth(user_mgr));
}
else {
// only basic and cookie authentications are supported
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
}
} else if (command_string == "restrict") {
// finished restrict command
if (! my_auth_ptr)
// Authentication type must be defined before restrict
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
else if (value_string.empty())
// No service defined for restrict parameter
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
my_auth_ptr->add_restrict(value_string);
} else if (command_string == "user") {
// finished user command
if (! my_auth_ptr)
// Authentication type must be defined before users
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
else if (value_string.empty())
// No password defined for user parameter
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
my_auth_ptr->add_user(username_string, value_string);
} else if (command_string == "service") {
// finished service command
load_service(resource_string, value_string);
} else if (command_string == "option") {
// finished option command
std::string::size_type pos = value_string.find('=');
if (pos == std::string::npos)
BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) );
option_name_string = value_string.substr(0, pos);
option_value_string = value_string.substr(pos + 1);
set_service_option(resource_string, option_name_string,
option_value_string);
}
command_string.clear();
parse_state = PARSE_NEWLINE;
} else if (c == ' ' || c == '\t') {
// only skip leading whitespace (value may contain spaces, etc)
if (! value_string.empty())
value_string += c;
} else {
// add char to value
value_string += c;
}
break;
case PARSE_COMMENT:
// skipping comment line
if (c == '\r' || c == '\n')
parse_state = PARSE_NEWLINE;
break;
}
// read the next character
c = config_stream.get();
}
// update authentication configuration for the server
set_authentication(my_auth_ptr);
}
} // end namespace http
} // end namespace pion
pion::http::plugin_service
Definition: plugin_service.hpp:29
pion::plugin::find_config_file
static bool find_config_file(std::string &path_to_file, const std::string &name)
Definition: plugin.hpp:53
pion::plugin_manager::run
void run(PluginRunFunction run_func)
Definition: plugin_manager.hpp:337
pion::http::plugin_server::add_service
void add_service(const std::string &resource, http::plugin_service *service_ptr)
Definition: http_plugin_server.cpp:25
pion::plugin::add_plugin_directory
static void add_plugin_directory(const std::string &dir)
appends a directory to the plug-in search path
Definition: plugin.cpp:59
pion::http::plugin_server::set_service_option
void set_service_option(const std::string &resource, const std::string &name, const std::string &value)
Definition: http_plugin_server.cpp:45
pion::http::plugin_service::set_resource
void set_resource(const std::string &str)
sets the URI stem or resource that is bound to the web service
Definition: plugin_service.hpp:65
pion::plugin_ptr
Definition: plugin.hpp:301
pion::plugin_manager::add
void add(const std::string &plugin_id, PluginType *plugin_object_ptr)
Definition: plugin_manager.hpp:188
pion::http::cookie_auth
Definition: cookie_auth.hpp:28
pion::plugin_manager::load
PluginType * load(const std::string &plugin_id, const std::string &plugin_type)
Definition: plugin_manager.hpp:239
pion::http::plugin_service::set_option
virtual void set_option(const std::string &name, const std::string &value)
Definition: plugin_service.hpp:54
pion::user_manager
Definition: user.hpp:167
pion::http::server::add_resource
void add_resource(const std::string &resource, request_handler_t request_handler)
Definition: http_server.cpp:160
pion::http::server::strip_trailing_slash
static std::string strip_trailing_slash(const std::string &str)
Definition: server.hpp:160
pion::error::file_not_found
exception thrown if a file is not found
Definition: error.hpp:167
pion::error::open_file
exception thrown if we failed to open a file
Definition: error.hpp:146
pion
Definition: admin_rights.hpp:19
pion::tcp::server::m_logger
logger m_logger
primary logging interface used by this class
Definition: server.hpp:160
pion::http::basic_auth
Definition: basic_auth.hpp:26
pion::error::bad_config
exception thrown if there is an error parsing a configuration file
Definition: error.hpp:139
pion::http::plugin_server::load_service
void load_service(const std::string &resource, const std::string &service_name)
Definition: http_plugin_server.cpp:35
pion::http::plugin_server::load_service_config
void load_service_config(const std::string &config_name)
Definition: http_plugin_server.cpp:54
pion::http::server::set_authentication
void set_authentication(http::auth_ptr auth)
Definition: server.hpp:221