10 #include <boost/exception/diagnostic_information.hpp>
11 #include <pion/algorithm.hpp>
12 #include <pion/http/server.hpp>
13 #include <pion/http/request.hpp>
14 #include <pion/http/request_reader.hpp>
15 #include <pion/http/response_writer.hpp>
24 const unsigned int server::MAX_REDIRECTS = 10;
31 request_reader_ptr my_reader_ptr;
34 my_reader_ptr->set_max_content_length(m_max_content_length);
35 my_reader_ptr->receive();
39 tcp::connection_ptr& tcp_conn,
const boost::system::error_code& ec)
41 if (ec || ! http_request_ptr->is_valid()) {
42 tcp_conn->set_lifecycle(tcp::connection::LIFECYCLE_CLOSE);
45 PION_LOG_INFO(
m_logger,
"Invalid HTTP request (" << ec.message() <<
")");
46 m_bad_request_handler(http_request_ptr, tcp_conn);
48 static const boost::system::error_condition
49 ERRCOND_CANCELED(boost::system::errc::operation_canceled, boost::system::system_category()),
50 ERRCOND_EOF(boost::asio::error::eof, boost::asio::error::misc_category);
52 if (ec == ERRCOND_CANCELED || ec == ERRCOND_EOF) {
54 PION_LOG_DEBUG(
m_logger,
"Lost connection on port " <<
get_port() <<
" (" << ec.message() <<
")");
56 PION_LOG_INFO(
m_logger,
"Lost connection on port " <<
get_port() <<
" (" << ec.message() <<
")");
64 PION_LOG_DEBUG(
m_logger,
"Received a valid HTTP request");
70 redirect_map_t::const_iterator it = m_redirects.find(resource_requested);
71 unsigned int num_redirects = 0;
72 while (it != m_redirects.end()) {
73 if (++num_redirects > MAX_REDIRECTS) {
74 PION_LOG_ERROR(
m_logger,
"Maximum number of redirects (server::MAX_REDIRECTS) exceeded for requested resource: " << http_request_ptr->get_original_resource());
75 m_server_error_handler(http_request_ptr, tcp_conn,
"Maximum number of redirects (server::MAX_REDIRECTS) exceeded for requested resource");
78 resource_requested = it->second;
79 http_request_ptr->change_resource(resource_requested);
80 it = m_redirects.find(resource_requested);
86 if (! m_auth_ptr->handle_request(http_request_ptr, tcp_conn)) {
88 PION_LOG_DEBUG(
m_logger,
"Authentication required for HTTP resource: "
89 << resource_requested);
90 if (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
91 PION_LOG_DEBUG(
m_logger,
"Original resource requested was: " << http_request_ptr->get_original_resource());
103 request_handler(http_request_ptr, tcp_conn);
104 PION_LOG_DEBUG(
m_logger,
"Found request handler for HTTP resource: "
105 << resource_requested);
106 if (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
107 PION_LOG_DEBUG(
m_logger,
"Original resource requested was: " << http_request_ptr->get_original_resource());
109 }
catch (std::bad_alloc&) {
112 }
catch (std::exception& e) {
114 PION_LOG_ERROR(
m_logger,
"HTTP request handler: " << pion::diagnostic_information(e));
115 m_server_error_handler(http_request_ptr, tcp_conn, e.what());
116 }
catch (boost::exception& e) {
118 PION_LOG_ERROR(
m_logger,
"HTTP request handler: " << pion::diagnostic_information(e));
119 m_server_error_handler(http_request_ptr, tcp_conn, pion::diagnostic_information(e));
125 PION_LOG_INFO(
m_logger,
"No HTTP request handlers found for resource: "
126 << resource_requested);
127 if (http_request_ptr->get_resource() != http_request_ptr->get_original_resource()) {
128 PION_LOG_DEBUG(
m_logger,
"Original resource requested was: " << http_request_ptr->get_original_resource());
130 m_not_found_handler(http_request_ptr, tcp_conn);
138 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
139 if (m_resources.empty())
143 resource_map_t::const_iterator i = m_resources.upper_bound(resource);
144 while (i != m_resources.begin()) {
147 if (i->first.empty() || resource.compare(0, i->first.size(), i->first) == 0) {
150 if (resource.size() == i->first.size() || resource[i->first.size()]==
'/') {
151 request_handler = i->second;
163 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
165 m_resources.insert(std::make_pair(clean_resource, request_handler));
166 PION_LOG_INFO(
m_logger,
"Added request handler for HTTP resource: " << clean_resource);
171 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
173 m_resources.erase(clean_resource);
174 PION_LOG_INFO(
m_logger,
"Removed request handler for HTTP resource: " << clean_resource);
178 const std::string& new_resource)
180 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
183 m_redirects.insert(std::make_pair(clean_requested_resource, clean_new_resource));
184 PION_LOG_INFO(
m_logger,
"Added redirection for HTTP resource " << clean_requested_resource <<
" to resource " << clean_new_resource);
188 tcp::connection_ptr& tcp_conn)
190 static const std::string BAD_REQUEST_HTML =
192 "<title>400 Bad Request</title>\n"
194 "<h1>Bad Request</h1>\n"
195 "<p>Your browser sent a request that this server could not understand.</p>\n"
199 writer->get_response().set_status_code(http::types::RESPONSE_CODE_BAD_REQUEST);
200 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_BAD_REQUEST);
201 writer->write_no_copy(BAD_REQUEST_HTML);
206 tcp::connection_ptr& tcp_conn)
208 static const std::string NOT_FOUND_HTML_START =
210 "<title>404 Not Found</title>\n"
212 "<h1>Not Found</h1>\n"
213 "<p>The requested URL ";
214 static const std::string NOT_FOUND_HTML_FINISH =
215 " was not found on this server.</p>\n"
219 writer->get_response().set_status_code(http::types::RESPONSE_CODE_NOT_FOUND);
220 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_NOT_FOUND);
221 writer->write_no_copy(NOT_FOUND_HTML_START);
223 writer->write_no_copy(NOT_FOUND_HTML_FINISH);
228 tcp::connection_ptr& tcp_conn,
229 const std::string& error_msg)
231 static const std::string SERVER_ERROR_HTML_START =
233 "<title>500 Server Error</title>\n"
235 "<h1>Internal Server Error</h1>\n"
236 "<p>The server encountered an internal error: <strong>";
237 static const std::string SERVER_ERROR_HTML_FINISH =
242 writer->get_response().set_status_code(http::types::RESPONSE_CODE_SERVER_ERROR);
243 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_SERVER_ERROR);
244 writer->write_no_copy(SERVER_ERROR_HTML_START);
246 writer->write_no_copy(SERVER_ERROR_HTML_FINISH);
251 tcp::connection_ptr& tcp_conn,
252 const std::string& error_msg)
254 static const std::string FORBIDDEN_HTML_START =
256 "<title>403 Forbidden</title>\n"
258 "<h1>Forbidden</h1>\n"
259 "<p>User not authorized to access the requested URL ";
260 static const std::string FORBIDDEN_HTML_MIDDLE =
262 static const std::string FORBIDDEN_HTML_FINISH =
267 writer->get_response().set_status_code(http::types::RESPONSE_CODE_FORBIDDEN);
268 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_FORBIDDEN);
269 writer->write_no_copy(FORBIDDEN_HTML_START);
271 writer->write_no_copy(FORBIDDEN_HTML_MIDDLE);
273 writer->write_no_copy(FORBIDDEN_HTML_FINISH);
278 tcp::connection_ptr& tcp_conn,
279 const std::string& allowed_methods)
281 static const std::string NOT_ALLOWED_HTML_START =
283 "<title>405 Method Not Allowed</title>\n"
285 "<h1>Not Allowed</h1>\n"
286 "<p>The requested method ";
287 static const std::string NOT_ALLOWED_HTML_FINISH =
288 " is not allowed on this server.</p>\n"
292 writer->get_response().set_status_code(http::types::RESPONSE_CODE_METHOD_NOT_ALLOWED);
293 writer->get_response().set_status_message(http::types::RESPONSE_MESSAGE_METHOD_NOT_ALLOWED);
294 if (! allowed_methods.empty())
295 writer->get_response().add_header(
"Allow", allowed_methods);
296 writer->write_no_copy(NOT_ALLOWED_HTML_START);
298 writer->write_no_copy(NOT_ALLOWED_HTML_FINISH);
static void handle_not_found_request(http::request_ptr &http_request_ptr, tcp::connection_ptr &tcp_conn)
static boost::shared_ptr< request_reader > create(tcp::connection_ptr &tcp_conn, finished_handler_t handler)
unsigned int get_port(void) const
returns tcp port number that the server listens for connections on
void add_redirect(const std::string &requested_resource, const std::string &new_resource)
virtual void handle_request(http::request_ptr &http_request_ptr, tcp::connection_ptr &tcp_conn, const boost::system::error_code &ec)
boost::function2< void, http::request_ptr &, tcp::connection_ptr & > request_handler_t
type of function that is used to handle requests
void add_resource(const std::string &resource, request_handler_t request_handler)
static std::string strip_trailing_slash(const std::string &str)
static std::string xml_encode(const std::string &str)
TODO: escapes XML/HTML-encoded strings (1 < 2)
static error_category_t & get_error_category(void)
returns an instance of parser::error_category_t
static void handle_method_not_allowed(http::request_ptr &http_request_ptr, tcp::connection_ptr &tcp_conn, const std::string &allowed_methods="")
static void handle_bad_request(http::request_ptr &http_request_ptr, tcp::connection_ptr &tcp_conn)
logger m_logger
primary logging interface used by this class
void remove_resource(const std::string &resource)
static void handle_forbidden_request(http::request_ptr &http_request_ptr, tcp::connection_ptr &tcp_conn, const std::string &error_msg)
static void handle_server_error(http::request_ptr &http_request_ptr, tcp::connection_ptr &tcp_conn, const std::string &error_msg)
virtual void handle_connection(tcp::connection_ptr &tcp_conn)
static boost::shared_ptr< response_writer > create(tcp::connection_ptr &tcp_conn, http::response_ptr &http_response_ptr, finished_handler_t handler=finished_handler_t())
virtual bool find_request_handler(const std::string &resource, request_handler_t &request_handler) const