00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <pion/net/HTTPServer.hpp>
00011 #include <pion/net/HTTPRequest.hpp>
00012 #include <pion/net/HTTPRequestReader.hpp>
00013 #include <pion/net/HTTPResponseWriter.hpp>
00014
00015
00016 namespace pion {
00017 namespace net {
00018
00019
00020
00021
00022 const unsigned int HTTPServer::MAX_REDIRECTS = 10;
00023
00024
00025
00026
00027 void HTTPServer::handleConnection(TCPConnectionPtr& tcp_conn)
00028 {
00029 HTTPRequestReaderPtr reader_ptr;
00030 reader_ptr = HTTPRequestReader::create(tcp_conn, boost::bind(&HTTPServer::handleRequest,
00031 this, _1, _2));
00032 reader_ptr->setMaxContentLength(m_max_content_length);
00033 reader_ptr->receive();
00034 }
00035
00036 void HTTPServer::handleRequest(HTTPRequestPtr& http_request,
00037 TCPConnectionPtr& tcp_conn)
00038 {
00039 if (! http_request->isValid()) {
00040
00041 PION_LOG_INFO(m_logger, "Received an invalid HTTP request");
00042 m_bad_request_handler(http_request, tcp_conn);
00043 return;
00044 }
00045
00046 PION_LOG_DEBUG(m_logger, "Received a valid HTTP request");
00047
00048
00049 std::string resource_requested(stripTrailingSlash(http_request->getResource()));
00050
00051
00052 RedirectMap::const_iterator it = m_redirects.find(resource_requested);
00053 unsigned int num_redirects = 0;
00054 while (it != m_redirects.end()) {
00055 if (++num_redirects > MAX_REDIRECTS) {
00056 PION_LOG_ERROR(m_logger, "Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource: " << http_request->getOriginalResource());
00057 m_server_error_handler(http_request, tcp_conn, "Maximum number of redirects (HTTPServer::MAX_REDIRECTS) exceeded for requested resource");
00058 return;
00059 }
00060 resource_requested = it->second;
00061 http_request->changeResource(resource_requested);
00062 it = m_redirects.find(resource_requested);
00063 }
00064
00065
00066 if (m_auth) {
00067
00068 if (! m_auth->handleRequest(http_request, tcp_conn)) {
00069
00070 PION_LOG_DEBUG(m_logger, "Authentication required for HTTP resource: "
00071 << resource_requested);
00072 if (http_request->getResource() != http_request->getOriginalResource()) {
00073 PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource());
00074 }
00075 return;
00076 }
00077 }
00078
00079
00080 RequestHandler request_handler;
00081 if (findRequestHandler(resource_requested, request_handler)) {
00082
00083
00084 try {
00085 request_handler(http_request, tcp_conn);
00086 PION_LOG_DEBUG(m_logger, "Found request handler for HTTP resource: "
00087 << resource_requested);
00088 if (http_request->getResource() != http_request->getOriginalResource()) {
00089 PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource());
00090 }
00091 } catch (HTTPResponseWriter::LostConnectionException& e) {
00092
00093 PION_LOG_WARN(m_logger, "HTTP request handler: " << e.what());
00094 tcp_conn->setLifecycle(TCPConnection::LIFECYCLE_CLOSE);
00095 tcp_conn->finish();
00096 } catch (std::bad_alloc&) {
00097
00098 throw;
00099 } catch (std::exception& e) {
00100
00101 PION_LOG_ERROR(m_logger, "HTTP request handler: " << e.what());
00102 m_server_error_handler(http_request, tcp_conn, e.what());
00103 }
00104
00105 } else {
00106
00107
00108 PION_LOG_INFO(m_logger, "No HTTP request handlers found for resource: "
00109 << resource_requested);
00110 if (http_request->getResource() != http_request->getOriginalResource()) {
00111 PION_LOG_DEBUG(m_logger, "Original resource requested was: " << http_request->getOriginalResource());
00112 }
00113 m_not_found_handler(http_request, tcp_conn);
00114 }
00115 }
00116
00117 bool HTTPServer::findRequestHandler(const std::string& resource,
00118 RequestHandler& request_handler) const
00119 {
00120
00121 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
00122 if (m_resources.empty())
00123 return false;
00124
00125
00126 ResourceMap::const_iterator i = m_resources.upper_bound(resource);
00127 while (i != m_resources.begin()) {
00128 --i;
00129
00130 if (i->first.empty() || resource.compare(0, i->first.size(), i->first) == 0) {
00131
00132
00133 if (resource.size() == i->first.size() || resource[i->first.size()]=='/') {
00134 request_handler = i->second;
00135 return true;
00136 }
00137 }
00138 }
00139
00140 return false;
00141 }
00142
00143 void HTTPServer::addResource(const std::string& resource,
00144 RequestHandler request_handler)
00145 {
00146 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
00147 const std::string clean_resource(stripTrailingSlash(resource));
00148 m_resources.insert(std::make_pair(clean_resource, request_handler));
00149 PION_LOG_INFO(m_logger, "Added request handler for HTTP resource: " << clean_resource);
00150 }
00151
00152 void HTTPServer::removeResource(const std::string& resource)
00153 {
00154 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
00155 const std::string clean_resource(stripTrailingSlash(resource));
00156 m_resources.erase(clean_resource);
00157 PION_LOG_INFO(m_logger, "Removed request handler for HTTP resource: " << clean_resource);
00158 }
00159
00160 void HTTPServer::addRedirect(const std::string& requested_resource,
00161 const std::string& new_resource)
00162 {
00163 boost::mutex::scoped_lock resource_lock(m_resource_mutex);
00164 const std::string clean_requested_resource(stripTrailingSlash(requested_resource));
00165 const std::string clean_new_resource(stripTrailingSlash(new_resource));
00166 m_redirects.insert(std::make_pair(clean_requested_resource, clean_new_resource));
00167 PION_LOG_INFO(m_logger, "Added redirection for HTTP resource " << clean_requested_resource << " to resource " << clean_new_resource);
00168 }
00169
00170 void HTTPServer::handleBadRequest(HTTPRequestPtr& http_request,
00171 TCPConnectionPtr& tcp_conn)
00172 {
00173 static const std::string BAD_REQUEST_HTML =
00174 "<html><head>\n"
00175 "<title>400 Bad Request</title>\n"
00176 "</head><body>\n"
00177 "<h1>Bad Request</h1>\n"
00178 "<p>Your browser sent a request that this server could not understand.</p>\n"
00179 "</body></html>\n";
00180 HTTPResponseWriterPtr writer(HTTPResponseWriter::create(tcp_conn, *http_request,
00181 boost::bind(&TCPConnection::finish, tcp_conn)));
00182 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_BAD_REQUEST);
00183 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_BAD_REQUEST);
00184 writer->writeNoCopy(BAD_REQUEST_HTML);
00185 writer->send();
00186 }
00187
00188 void HTTPServer::handleNotFoundRequest(HTTPRequestPtr& http_request,
00189 TCPConnectionPtr& tcp_conn)
00190 {
00191 static const std::string NOT_FOUND_HTML_START =
00192 "<html><head>\n"
00193 "<title>404 Not Found</title>\n"
00194 "</head><body>\n"
00195 "<h1>Not Found</h1>\n"
00196 "<p>The requested URL ";
00197 static const std::string NOT_FOUND_HTML_FINISH =
00198 " was not found on this server.</p>\n"
00199 "</body></html>\n";
00200 HTTPResponseWriterPtr writer(HTTPResponseWriter::create(tcp_conn, *http_request,
00201 boost::bind(&TCPConnection::finish, tcp_conn)));
00202 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_NOT_FOUND);
00203 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_NOT_FOUND);
00204 writer->writeNoCopy(NOT_FOUND_HTML_START);
00205 writer << http_request->getResource();
00206 writer->writeNoCopy(NOT_FOUND_HTML_FINISH);
00207 writer->send();
00208 }
00209
00210 void HTTPServer::handleServerError(HTTPRequestPtr& http_request,
00211 TCPConnectionPtr& tcp_conn,
00212 const std::string& error_msg)
00213 {
00214 static const std::string SERVER_ERROR_HTML_START =
00215 "<html><head>\n"
00216 "<title>500 Server Error</title>\n"
00217 "</head><body>\n"
00218 "<h1>Internal Server Error</h1>\n"
00219 "<p>The server encountered an internal error: <strong>";
00220 static const std::string SERVER_ERROR_HTML_FINISH =
00221 "</strong></p>\n"
00222 "</body></html>\n";
00223 HTTPResponseWriterPtr writer(HTTPResponseWriter::create(tcp_conn, *http_request,
00224 boost::bind(&TCPConnection::finish, tcp_conn)));
00225 writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_SERVER_ERROR);
00226 writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_SERVER_ERROR);
00227 writer->writeNoCopy(SERVER_ERROR_HTML_START);
00228 writer << error_msg;
00229 writer->writeNoCopy(SERVER_ERROR_HTML_FINISH);
00230 writer->send();
00231 }
00232
00233 }
00234 }
00235