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); }
void HTTPServer::handleRequest(HTTPRequestPtr& http_request, TCPConnectionPtr& tcp_conn) { if (! http_request->isValid()) { // the request is invalid or an error occured PION_LOG_INFO(m_logger, "Received an invalid HTTP request"); m_bad_request_handler(http_request, tcp_conn); return; } PION_LOG_DEBUG(m_logger, "Received a valid HTTP request"); // strip off trailing slash if the request has one std::string resource_requested(stripTrailingSlash(http_request->getResource())); // apply any redirection RedirectMap::const_iterator it = m_redirects.find(resource_requested); unsigned int num_redirects = 0; while (it != m_redirects.end()) { if (++num_redirects > MAX_REDIRECTS) { PION_LOG_ERROR(m_logger, "Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource: " << http_request->getOriginalResource()); m_server_error_handler(http_request, tcp_conn, "Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource"); return; } resource_requested = it->second; http_request->changeResource(resource_requested); it = m_redirects.find(resource_requested); } // if authentication activated, check current request if (m_auth) { // try to verify authentication if (! m_auth->handleRequest(http_request, tcp_conn)) { // the HTTP 401 message has already been sent by the authentication object PION_LOG_DEBUG(m_logger, "Authentication required for HTTP resource: " << resource_requested); if (http_request->getResource() != http_request->getOriginalResource()) { PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource()); } return; } } // search for a handler matching the resource requested RequestHandler request_handler; if (findRequestHandler(resource_requested, request_handler)) { // try to handle the request try { request_handler(http_request, tcp_conn); PION_LOG_DEBUG(m_logger, "Found request handler for HTTP resource: " << resource_requested); if (http_request->getResource() != http_request->getOriginalResource()) { PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource()); } } catch (HTTPResponseWriter::LostConnectionException& e) { // the connection was lost while or before sending the response PION_LOG_WARN(m_logger, "HTTP request handler: " << e.what()); tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_CLOSE); // make sure it will get closed tcp_conn->finish(); } catch (std::bad_alloc&) { // propagate memory errors (FATAL) throw; } catch (std::exception& e) { // recover gracefully from other exceptions thrown request handlers PION_LOG_ERROR(m_logger, "HTTP request handler: " << e.what()); m_server_error_handler(http_request, tcp_conn, e.what()); } } else { // no web services found that could handle the request PION_LOG_INFO(m_logger, "No HTTP request handlers found for resource: " << resource_requested); if (http_request->getResource() != http_request->getOriginalResource()) { PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource()); } m_not_found_handler(http_request, tcp_conn); } }