10 #include <pion/net/HTTPServer.hpp>
11 #include <pion/net/HTTPRequest.hpp>
12 #include <pion/net/HTTPRequestReader.hpp>
13 #include <pion/net/HTTPResponseWriter.hpp>
22 const unsigned int HTTPServer::MAX_REDIRECTS = 10;
29 HTTPRequestReaderPtr reader_ptr;
32 reader_ptr->setMaxContentLength(m_max_content_length);
33 reader_ptr->receive();
37 TCPConnectionPtr& tcp_conn,
const boost::system::error_code& ec)
39 if (ec || ! http_request->isValid()) {
40 tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_CLOSE);
43 PION_LOG_INFO(
m_logger,
"Invalid HTTP request (" << ec.message() <<
")");
44 m_bad_request_handler(http_request, tcp_conn);
53 PION_LOG_DEBUG(
m_logger,
"Received a valid HTTP request");
59 RedirectMap::const_iterator it = m_redirects.find(resource_requested);
60 unsigned int num_redirects = 0;
61 while (it != m_redirects.end()) {
62 if (++num_redirects > MAX_REDIRECTS) {
63 PION_LOG_ERROR(
m_logger,
"Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource: " << http_request->getOriginalResource());
64 m_server_error_handler(http_request, tcp_conn,
"Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource");
67 resource_requested = it->second;
68 http_request->changeResource(resource_requested);
69 it = m_redirects.find(resource_requested);
75 if (! m_auth->handleRequest(http_request, tcp_conn)) {
77 PION_LOG_DEBUG(
m_logger,
"Authentication required for HTTP resource: "
78 << resource_requested);
79 if (http_request->getResource() != http_request->getOriginalResource()) {
80 PION_LOG_DEBUG(
m_logger,
"Original resource requested was: " << http_request->getOriginalResource());
92 request_handler(http_request, tcp_conn);
93 PION_LOG_DEBUG(
m_logger,
"Found request handler for HTTP resource: "
94 << resource_requested);
95 if (http_request->getResource() != http_request->getOriginalResource()) {
96 PION_LOG_DEBUG(
m_logger,
"Original resource requested was: " << http_request->getOriginalResource());
98 }
catch (std::bad_alloc&) {
101 }
catch (std::exception& e) {
103 PION_LOG_ERROR(
m_logger,
"HTTP request handler: " << e.what());
104 m_server_error_handler(http_request, tcp_conn, e.what());
110 PION_LOG_INFO(
m_logger,
"No HTTP request handlers found for resource: "
111 << resource_requested);
112 if (http_request->getResource() != http_request->getOriginalResource()) {
113 PION_LOG_DEBUG(
m_logger,
"Original resource requested was: " << http_request->getOriginalResource());
115 m_not_found_handler(http_request, tcp_conn);
123 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
124 if (m_resources.empty())
128 ResourceMap::const_iterator i = m_resources.upper_bound(resource);
129 while (i != m_resources.begin()) {
132 if (i->first.empty() || resource.compare(0, i->first.size(), i->first) == 0) {
135 if (resource.size() == i->first.size() || resource[i->first.size()]==
'/') {
136 request_handler = i->second;
148 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
150 m_resources.insert(std::make_pair(clean_resource, request_handler));
151 PION_LOG_INFO(
m_logger,
"Added request handler for HTTP resource: " << clean_resource);
156 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
158 m_resources.erase(clean_resource);
159 PION_LOG_INFO(
m_logger,
"Removed request handler for HTTP resource: " << clean_resource);
163 const std::string& new_resource)
165 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
168 m_redirects.insert(std::make_pair(clean_requested_resource, clean_new_resource));
169 PION_LOG_INFO(
m_logger,
"Added redirection for HTTP resource " << clean_requested_resource <<
" to resource " << clean_new_resource);
173 TCPConnectionPtr& tcp_conn)
175 static const std::string BAD_REQUEST_HTML =
177 "<title>400 Bad Request</title>\n"
179 "<h1>Bad Request</h1>\n"
180 "<p>Your browser sent a request that this server could not understand.</p>\n"
184 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_BAD_REQUEST);
185 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_BAD_REQUEST);
186 writer->writeNoCopy(BAD_REQUEST_HTML);
191 TCPConnectionPtr& tcp_conn)
193 static const std::string NOT_FOUND_HTML_START =
195 "<title>404 Not Found</title>\n"
197 "<h1>Not Found</h1>\n"
198 "<p>The requested URL ";
199 static const std::string NOT_FOUND_HTML_FINISH =
200 " was not found on this server.</p>\n"
204 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_NOT_FOUND);
205 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_NOT_FOUND);
206 writer->writeNoCopy(NOT_FOUND_HTML_START);
207 writer << http_request->getResource();
208 writer->writeNoCopy(NOT_FOUND_HTML_FINISH);
213 TCPConnectionPtr& tcp_conn,
214 const std::string& error_msg)
216 static const std::string SERVER_ERROR_HTML_START =
218 "<title>500 Server Error</title>\n"
220 "<h1>Internal Server Error</h1>\n"
221 "<p>The server encountered an internal error: <strong>";
222 static const std::string SERVER_ERROR_HTML_FINISH =
227 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_SERVER_ERROR);
228 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_SERVER_ERROR);
229 writer->writeNoCopy(SERVER_ERROR_HTML_START);
231 writer->writeNoCopy(SERVER_ERROR_HTML_FINISH);
236 TCPConnectionPtr& tcp_conn,
237 const std::string& error_msg)
239 static const std::string FORBIDDEN_HTML_START =
241 "<title>403 Forbidden</title>\n"
243 "<h1>Forbidden</h1>\n"
244 "<p>User not authorized to access the requested URL ";
245 static const std::string FORBIDDEN_HTML_MIDDLE =
247 static const std::string FORBIDDEN_HTML_FINISH =
252 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_FORBIDDEN);
253 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_FORBIDDEN);
254 writer->writeNoCopy(FORBIDDEN_HTML_START);
255 writer << http_request->getResource();
256 writer->writeNoCopy(FORBIDDEN_HTML_MIDDLE);
258 writer->writeNoCopy(FORBIDDEN_HTML_FINISH);
263 TCPConnectionPtr& tcp_conn,
264 const std::string& allowed_methods)
266 static const std::string NOT_ALLOWED_HTML_START =
268 "<title>405 Method Not Allowed</title>\n"
270 "<h1>Not Allowed</h1>\n"
271 "<p>The requested method ";
272 static const std::string NOT_ALLOWED_HTML_FINISH =
273 " is not allowed on this server.</p>\n"
277 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_METHOD_NOT_ALLOWED);
278 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_METHOD_NOT_ALLOWED);
279 if (! allowed_methods.empty())
280 writer->getResponse().addHeader(
"Allow", allowed_methods);
281 writer->writeNoCopy(NOT_ALLOWED_HTML_START);
282 writer << http_request->getMethod();
283 writer->writeNoCopy(NOT_ALLOWED_HTML_FINISH);
virtual void handleConnection(TCPConnectionPtr &tcp_conn)
void addRedirect(const std::string &requested_resource, const std::string &new_resource)
static void handleBadRequest(HTTPRequestPtr &http_request, TCPConnectionPtr &tcp_conn)
static std::string stripTrailingSlash(const std::string &str)
static void handleServerError(HTTPRequestPtr &http_request, TCPConnectionPtr &tcp_conn, const std::string &error_msg)
boost::function2< void, HTTPRequestPtr &, TCPConnectionPtr & > RequestHandler
type of function that is used to handle requests
static boost::shared_ptr< HTTPRequestReader > create(TCPConnectionPtr &tcp_conn, FinishedHandler handler)
void addResource(const std::string &resource, RequestHandler request_handler)
PionLogger m_logger
primary logging interface used by this class
static void handleForbiddenRequest(HTTPRequestPtr &http_request, TCPConnectionPtr &tcp_conn, const std::string &error_msg)
static void handleMethodNotAllowed(HTTPRequestPtr &http_request, TCPConnectionPtr &tcp_conn, const std::string &allowed_methods="")
unsigned int getPort(void) const
returns tcp port number that the server listens for connections on
virtual bool findRequestHandler(const std::string &resource, RequestHandler &request_handler) const
static ErrorCategory & getErrorCategory(void)
returns an instance of HTTPParser::ErrorCategory
static void handleNotFoundRequest(HTTPRequestPtr &http_request, TCPConnectionPtr &tcp_conn)
void removeResource(const std::string &resource)
static boost::shared_ptr< HTTPResponseWriter > create(TCPConnectionPtr &tcp_conn, HTTPResponsePtr &http_response, FinishedHandler handler=FinishedHandler())
virtual void handleRequest(HTTPRequestPtr &http_request, TCPConnectionPtr &tcp_conn, const boost::system::error_code &ec)