void HTTPServer::handleNotFoundRequest(HTTPRequestPtr& http_request, TCPConnectionPtr& tcp_conn) { static const std::string NOT_FOUND_HTML_START = "<html><head>\n" "<title>404 Not Found</title>\n" "</head><body>\n" "<h1>Not Found</h1>\n" "<p>The requested URL "; static const std::string NOT_FOUND_HTML_FINISH = " was not found on this server.</p>\n" "</body></html>\n"; HTTPResponseWriterPtr writer(HTTPResponseWriter::create(tcp_conn, *http_request, boost::bind(&TCPConnection::finish, tcp_conn))); writer->getResponse().setStatusCode(HTTPTypes::RESPONSE_CODE_NOT_FOUND); writer->getResponse().setStatusMessage(HTTPTypes::RESPONSE_MESSAGE_NOT_FOUND); writer->writeNoCopy(NOT_FOUND_HTML_START); writer << http_request->getResource(); writer->writeNoCopy(NOT_FOUND_HTML_FINISH); writer->send(); }
bool HTTPCookieAuth::handleRequest(HTTPRequestPtr& request, TCPConnectionPtr& tcp_conn) { if (processLogin(request,tcp_conn)) { return false; // we processed login/logout request, no future processing for this request permitted } if (!needAuthentication(request)) { return true; // this request does not require authentication } // check if it is redirection page.. If yes, then do not test its credentials ( as used for login) if (!m_redirect.empty() && m_redirect==request->getResource()) { return true; // this request does not require authentication } // check cache for expiration PionDateTime time_now(boost::posix_time::second_clock::universal_time()); expireCache(time_now); // if we are here, we need to check if access authorized... const std::string auth_cookie(request->getCookie(AUTH_COOKIE_NAME)); if (! auth_cookie.empty()) { // check if this cookie is in user cache boost::mutex::scoped_lock cache_lock(m_cache_mutex); PionUserCache::iterator user_cache_itr=m_user_cache.find(auth_cookie); if (user_cache_itr != m_user_cache.end()) { // we find those credential in our cache... // we can approve authorization now! request->setUser(user_cache_itr->second.second); // and update cache timeout user_cache_itr->second.first = time_now; return true; } } // user not found handleUnauthorized(request,tcp_conn); return false; }
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); } }
/// handles requests for EchoService void EchoService::operator()(HTTPRequestPtr& request, TCPConnectionPtr& tcp_conn) { // this web service uses static text to test the mixture of "copied" with // "static" (no-copy) text static const std::string REQUEST_ECHO_TEXT("[Request Echo]"); static const std::string REQUEST_HEADERS_TEXT("[Request Headers]"); static const std::string QUERY_PARAMS_TEXT("[Query Parameters]"); static const std::string COOKIE_PARAMS_TEXT("[Cookie Parameters]"); static const std::string POST_CONTENT_TEXT("[POST Content]"); static const std::string USER_INFO_TEXT("[USER Info]"); // Set Content-type to "text/plain" (plain ascii text) HTTPResponseWriterPtr writer(HTTPResponseWriter::create(tcp_conn, *request, boost::bind(&TCPConnection::finish, tcp_conn))); writer->getResponse().setContentType(HTTPTypes::CONTENT_TYPE_TEXT); // write request information writer->writeNoCopy(REQUEST_ECHO_TEXT); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer << "Request method: " << request->getMethod() << HTTPTypes::STRING_CRLF << "Resource originally requested: " << request->getOriginalResource() << HTTPTypes::STRING_CRLF << "Resource delivered: " << request->getResource() << HTTPTypes::STRING_CRLF << "Query string: " << request->getQueryString() << HTTPTypes::STRING_CRLF << "HTTP version: " << request->getVersionMajor() << '.' << request->getVersionMinor() << HTTPTypes::STRING_CRLF << "Content length: " << (unsigned long)request->getContentLength() << HTTPTypes::STRING_CRLF << HTTPTypes::STRING_CRLF; // write request headers writer->writeNoCopy(REQUEST_HEADERS_TEXT); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer->writeNoCopy(HTTPTypes::STRING_CRLF); std::for_each(request->getHeaders().begin(), request->getHeaders().end(), boost::bind(&writeDictionaryTerm, writer, _1, false)); writer->writeNoCopy(HTTPTypes::STRING_CRLF); // write query parameters writer->writeNoCopy(QUERY_PARAMS_TEXT); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer->writeNoCopy(HTTPTypes::STRING_CRLF); std::for_each(request->getQueryParams().begin(), request->getQueryParams().end(), boost::bind(&writeDictionaryTerm, writer, _1, true)); writer->writeNoCopy(HTTPTypes::STRING_CRLF); // write cookie parameters writer->writeNoCopy(COOKIE_PARAMS_TEXT); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer->writeNoCopy(HTTPTypes::STRING_CRLF); std::for_each(request->getCookieParams().begin(), request->getCookieParams().end(), boost::bind(&writeDictionaryTerm, writer, _1, false)); writer->writeNoCopy(HTTPTypes::STRING_CRLF); // write POST content writer->writeNoCopy(POST_CONTENT_TEXT); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer->writeNoCopy(HTTPTypes::STRING_CRLF); if (request->getContentLength() != 0) { writer->write(request->getContent(), request->getContentLength()); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer->writeNoCopy(HTTPTypes::STRING_CRLF); } // if authenticated, write user info PionUserPtr user = request->getUser(); if (user) { writer->writeNoCopy(USER_INFO_TEXT); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer->writeNoCopy(HTTPTypes::STRING_CRLF); writer << "User authenticated, username: " << user->getUsername(); writer->writeNoCopy(HTTPTypes::STRING_CRLF); } // send the writer writer->send(); }
bool HTTPCookieAuth::processLogin(HTTPRequestPtr& http_request, TCPConnectionPtr& tcp_conn) { // strip off trailing slash if the request has one std::string resource(HTTPServer::stripTrailingSlash(http_request->getResource())); if (resource != m_login && resource != m_logout) { return false; // no login processing done } std::string redirect_url = HTTPTypes::url_decode(http_request->getQuery("url")); std::string new_cookie; bool delete_cookie = false; if (resource == m_login) { // process login // check username std::string username = HTTPTypes::url_decode(http_request->getQuery("user")); std::string password = HTTPTypes::url_decode(http_request->getQuery("pass")); // match username/password PionUserPtr user=m_user_manager->getUser(username,password); if (!user) { // authentication failed, process as in case of failed authentication... handleUnauthorized(http_request,tcp_conn); return true; } // ok we have a new user session, create a new cookie, add to cache // create random cookie std::string rand_binary; rand_binary.reserve(RANDOM_COOKIE_BYTES); for (unsigned int i=0; i<RANDOM_COOKIE_BYTES ; i++) { rand_binary += static_cast<unsigned char>(m_random_die()); } HTTPTypes::base64_encode(rand_binary, new_cookie); // add new session to cache PionDateTime time_now(boost::posix_time::second_clock::universal_time()); boost::mutex::scoped_lock cache_lock(m_cache_mutex); m_user_cache.insert(std::make_pair(new_cookie,std::make_pair(time_now,user))); } else { // process logout sequence // if auth cookie presented - clean cache out const std::string auth_cookie(http_request->getCookie(AUTH_COOKIE_NAME)); if (! auth_cookie.empty()) { boost::mutex::scoped_lock cache_lock(m_cache_mutex); PionUserCache::iterator user_cache_itr=m_user_cache.find(auth_cookie); if (user_cache_itr!=m_user_cache.end()) { m_user_cache.erase(user_cache_itr); } } // and remove cookie from browser delete_cookie = true; } // if redirect defined - send redirect if (! redirect_url.empty()) { handleRedirection(http_request,tcp_conn,redirect_url,new_cookie,delete_cookie); } else { // otherwise - OK handleOk(http_request,tcp_conn,new_cookie,delete_cookie); } // yes, we processed login/logout somehow return true; }