pion
5.0.6
|
00001 // --------------------------------------------------------------------- 00002 // pion: a Boost C++ framework for building lightweight HTTP interfaces 00003 // --------------------------------------------------------------------- 00004 // Copyright (C) 2007-2014 Splunk Inc. (https://github.com/splunk/pion) 00005 // 00006 // Distributed under the Boost Software License, Version 1.0. 00007 // See http://www.boost.org/LICENSE_1_0.txt 00008 // 00009 00010 #include <boost/exception/diagnostic_information.hpp> 00011 #include <pion/error.hpp> 00012 #include <pion/http/plugin_server.hpp> 00013 #include <pion/http/request.hpp> 00014 #include <pion/http/basic_auth.hpp> 00015 #include <pion/http/cookie_auth.hpp> 00016 #include <fstream> 00017 00018 00019 namespace pion { // begin namespace pion 00020 namespace http { // begin namespace http 00021 00022 00023 // plugin_server member functions 00024 00025 void plugin_server::add_service(const std::string& resource, http::plugin_service *service_ptr) 00026 { 00027 plugin_ptr<http::plugin_service> plugin_ptr; 00028 const std::string clean_resource(strip_trailing_slash(resource)); 00029 service_ptr->set_resource(clean_resource); 00030 m_services.add(clean_resource, service_ptr); 00031 http::server::add_resource(clean_resource, boost::ref(*service_ptr)); 00032 PION_LOG_INFO(m_logger, "Loaded static web service for resource (" << clean_resource << ")"); 00033 } 00034 00035 void plugin_server::load_service(const std::string& resource, const std::string& service_name) 00036 { 00037 const std::string clean_resource(strip_trailing_slash(resource)); 00038 http::plugin_service *service_ptr; 00039 service_ptr = m_services.load(clean_resource, service_name); 00040 http::server::add_resource(clean_resource, boost::ref(*service_ptr)); 00041 service_ptr->set_resource(clean_resource); 00042 PION_LOG_INFO(m_logger, "Loaded web service plug-in for resource (" << clean_resource << "): " << service_name); 00043 } 00044 00045 void plugin_server::set_service_option(const std::string& resource, 00046 const std::string& name, const std::string& value) 00047 { 00048 const std::string clean_resource(strip_trailing_slash(resource)); 00049 m_services.run(clean_resource, boost::bind(&http::plugin_service::set_option, _1, name, value)); 00050 PION_LOG_INFO(m_logger, "Set web service option for resource (" 00051 << resource << "): " << name << '=' << value); 00052 } 00053 00054 void plugin_server::load_service_config(const std::string& config_name) 00055 { 00056 std::string config_file; 00057 if (! plugin::find_config_file(config_file, config_name)) 00058 BOOST_THROW_EXCEPTION( error::file_not_found() << error::errinfo_file_name(config_name) ); 00059 00060 // open the file for reading 00061 std::ifstream config_stream; 00062 config_stream.open(config_file.c_str(), std::ios::in); 00063 if (! config_stream.is_open()) 00064 BOOST_THROW_EXCEPTION( error::open_file() << error::errinfo_file_name(config_name) ); 00065 00066 // parse the contents of the file 00067 http::auth_ptr my_auth_ptr; 00068 enum ParseState { 00069 PARSE_NEWLINE, PARSE_COMMAND, PARSE_RESOURCE, PARSE_VALUE, PARSE_COMMENT, PARSE_USERNAME 00070 } parse_state = PARSE_NEWLINE; 00071 std::string command_string; 00072 std::string resource_string; 00073 std::string username_string; 00074 std::string value_string; 00075 std::string option_name_string; 00076 std::string option_value_string; 00077 int c = config_stream.get(); // read the first character 00078 00079 while (config_stream) { 00080 switch(parse_state) { 00081 case PARSE_NEWLINE: 00082 // parsing command portion (or beginning of line) 00083 if (c == '#') { 00084 // line is a comment 00085 parse_state = PARSE_COMMENT; 00086 } else if (isalpha(c)) { 00087 // first char in command 00088 parse_state = PARSE_COMMAND; 00089 // ignore case for commands 00090 command_string += tolower(c); 00091 } else if (c != '\r' && c != '\n') { // check for blank lines 00092 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00093 } 00094 break; 00095 00096 case PARSE_COMMAND: 00097 // parsing command portion (or beginning of line) 00098 if (c == ' ' || c == '\t') { 00099 // command finished -> check if valid 00100 if (command_string=="path" || command_string=="auth" || command_string=="restrict") { 00101 value_string.clear(); 00102 parse_state = PARSE_VALUE; 00103 } else if (command_string=="service" || command_string=="option") { 00104 resource_string.clear(); 00105 parse_state = PARSE_RESOURCE; 00106 } else if (command_string=="user") { 00107 username_string.clear(); 00108 parse_state = PARSE_USERNAME; 00109 } else { 00110 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00111 } 00112 } else if (! isalpha(c)) { 00113 // commands may only contain alpha chars 00114 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00115 } else { 00116 // ignore case for commands 00117 command_string += tolower(c); 00118 } 00119 break; 00120 00121 case PARSE_RESOURCE: 00122 // parsing resource portion (/hello) 00123 if (c == ' ' || c == '\t') { 00124 // check for leading whitespace 00125 if (! resource_string.empty()) { 00126 // resource finished 00127 value_string.clear(); 00128 parse_state = PARSE_VALUE; 00129 } 00130 } else if (c == '\r' || c == '\n') { 00131 // line truncated before value 00132 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00133 } else { 00134 // add char to resource 00135 resource_string += c; 00136 } 00137 break; 00138 00139 case PARSE_USERNAME: 00140 // parsing username for user command 00141 if (c == ' ' || c == '\t') { 00142 // check for leading whitespace 00143 if (! username_string.empty()) { 00144 // username finished 00145 value_string.clear(); 00146 parse_state = PARSE_VALUE; 00147 } 00148 } else if (c == '\r' || c == '\n') { 00149 // line truncated before value (missing username) 00150 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00151 } else { 00152 // add char to username 00153 username_string += c; 00154 } 00155 break; 00156 00157 case PARSE_VALUE: 00158 // parsing value portion 00159 if (c == '\r' || c == '\n') { 00160 // value is finished 00161 if (value_string.empty()) { 00162 // value must not be empty 00163 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00164 } else if (command_string == "path") { 00165 // finished path command 00166 try { plugin::add_plugin_directory(value_string); } 00167 catch (std::exception& e) { 00168 PION_LOG_WARN(m_logger, boost::diagnostic_information(e)); 00169 } 00170 } else if (command_string == "auth") { 00171 // finished auth command 00172 user_manager_ptr user_mgr(new user_manager); 00173 if (value_string == "basic"){ 00174 my_auth_ptr.reset(new http::basic_auth(user_mgr)); 00175 } 00176 else if (value_string == "cookie"){ 00177 my_auth_ptr.reset(new http::cookie_auth(user_mgr)); 00178 } 00179 else { 00180 // only basic and cookie authentications are supported 00181 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00182 } 00183 } else if (command_string == "restrict") { 00184 // finished restrict command 00185 if (! my_auth_ptr) 00186 // Authentication type must be defined before restrict 00187 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00188 else if (value_string.empty()) 00189 // No service defined for restrict parameter 00190 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00191 my_auth_ptr->add_restrict(value_string); 00192 } else if (command_string == "user") { 00193 // finished user command 00194 if (! my_auth_ptr) 00195 // Authentication type must be defined before users 00196 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00197 else if (value_string.empty()) 00198 // No password defined for user parameter 00199 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00200 my_auth_ptr->add_user(username_string, value_string); 00201 } else if (command_string == "service") { 00202 // finished service command 00203 load_service(resource_string, value_string); 00204 } else if (command_string == "option") { 00205 // finished option command 00206 std::string::size_type pos = value_string.find('='); 00207 if (pos == std::string::npos) 00208 BOOST_THROW_EXCEPTION( error::bad_config() << error::errinfo_file_name(config_name) ); 00209 option_name_string = value_string.substr(0, pos); 00210 option_value_string = value_string.substr(pos + 1); 00211 set_service_option(resource_string, option_name_string, 00212 option_value_string); 00213 } 00214 command_string.clear(); 00215 parse_state = PARSE_NEWLINE; 00216 } else if (c == ' ' || c == '\t') { 00217 // only skip leading whitespace (value may contain spaces, etc) 00218 if (! value_string.empty()) 00219 value_string += c; 00220 } else { 00221 // add char to value 00222 value_string += c; 00223 } 00224 break; 00225 00226 case PARSE_COMMENT: 00227 // skipping comment line 00228 if (c == '\r' || c == '\n') 00229 parse_state = PARSE_NEWLINE; 00230 break; 00231 } 00232 00233 // read the next character 00234 c = config_stream.get(); 00235 } 00236 00237 // update authentication configuration for the server 00238 set_authentication(my_auth_ptr); 00239 } 00240 00241 } // end namespace http 00242 } // end namespace pion