From 1bb29282f1870070fa95b70f391252c79a3e3235 Mon Sep 17 00:00:00 2001 From: Ashod Nakashian Date: Mon, 27 Feb 2017 08:28:04 -0500 Subject: [PATCH] nb: serve files using non-blocking sockets Change-Id: I254288980f72f197d29b7b57ec9c88a01a5a1d03 --- wsd/FileServer.cpp | 68 ++++++++++++++++++++++++---------------------- wsd/FileServer.hpp | 36 ++++++------------------ wsd/LOOLWSD.cpp | 3 +- 3 files changed, 45 insertions(+), 62 deletions(-) diff --git a/wsd/FileServer.cpp b/wsd/FileServer.cpp index c91fdf1c8..35e0a8d96 100644 --- a/wsd/FileServer.cpp +++ b/wsd/FileServer.cpp @@ -12,6 +12,8 @@ #include #include +#include +#include #include #include #include @@ -106,7 +108,7 @@ bool FileServerRequestHandler::isAdminLoggedIn(HTTPServerRequest& request, HTTPS return false; } -void FileServerRequestHandler::handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) +void FileServerRequestHandler::handleRequest(const HTTPRequest& request, const std::shared_ptr& socket) { try { @@ -126,7 +128,7 @@ void FileServerRequestHandler::handleRequest(HTTPServerRequest& request, HTTPSer const std::string endPoint = requestSegments[requestSegments.size() - 1]; if (endPoint == loleafletHtml) { - preprocessFile(request, response); + preprocessFile(request, socket); return; } @@ -136,7 +138,8 @@ void FileServerRequestHandler::handleRequest(HTTPServerRequest& request, HTTPSer endPoint == "adminSettings.html" || endPoint == "adminAnalytics.html") { - if (!FileServerRequestHandler::isAdminLoggedIn(request, response)) + // FIXME: support admin console. + //if (!FileServerRequestHandler::isAdminLoggedIn(request, response)) throw Poco::Net::NotAuthenticatedException("Invalid admin login"); } @@ -167,35 +170,34 @@ void FileServerRequestHandler::handleRequest(HTTPServerRequest& request, HTTPSer else mimeType = "text/plain"; - response.setContentType(mimeType); - response.sendFile(filepath, mimeType); + HttpHelper::sendFile(socket, filepath, mimeType); } } catch (const Poco::Net::NotAuthenticatedException& exc) { LOG_ERR("FileServerRequestHandler::NotAuthenticated: " << exc.displayText()); - response.set("WWW-Authenticate", "Basic realm=\"online\""); - response.setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED); - response.setContentLength(0); - response.send(); + // response.set("WWW-Authenticate", "Basic realm=\"online\""); + // response.setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED); + // response.setContentLength(0); + // response.send(); } catch (const Poco::FileAccessDeniedException& exc) { LOG_ERR("FileServerRequestHandler: " << exc.displayText()); - response.setStatusAndReason(HTTPResponse::HTTP_FORBIDDEN); - response.setContentLength(0); // TODO return some 403 page? - response.send(); + // response.setStatusAndReason(HTTPResponse::HTTP_FORBIDDEN); + // response.setContentLength(0); // TODO return some 403 page? + // response.send(); } catch (const Poco::FileNotFoundException& exc) { LOG_ERR("FileServerRequestHandler: " << exc.displayText()); - response.setStatusAndReason(HTTPResponse::HTTP_NOT_FOUND); - response.setContentLength(0); // TODO return some 404 page? - response.send(); + // response.setStatusAndReason(HTTPResponse::HTTP_NOT_FOUND); + // response.setContentLength(0); // TODO return some 404 page? + // response.send(); } } -std::string FileServerRequestHandler::getRequestPathname(const HTTPServerRequest& request) +std::string FileServerRequestHandler::getRequestPathname(const HTTPRequest& request) { Poco::URI requestUri(request.getURI()); // avoid .'s and ..'s @@ -209,10 +211,8 @@ std::string FileServerRequestHandler::getRequestPathname(const HTTPServerRequest return path; } -void FileServerRequestHandler::preprocessFile(HTTPServerRequest& request, HTTPServerResponse& response) throw(Poco::FileAccessDeniedException) +void FileServerRequestHandler::preprocessFile(const HTTPRequest& request, const std::shared_ptr& socket) { - HTMLForm form(request, request.stream()); - const auto host = ((LOOLWSD::isSSLEnabled() || LOOLWSD::isSSLTermination()) ? "wss://" : "ws://") + (LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName); const auto path = Poco::Path(LOOLWSD::FileServerRoot, getRequestPathname(request)); LOG_DBG("Preprocessing file: " << path.toString()); @@ -220,9 +220,9 @@ void FileServerRequestHandler::preprocessFile(HTTPServerRequest& request, HTTPSe if (!Poco::File(path).exists()) { LOG_ERR("File [" << path.toString() << "] does not exist."); - response.setStatusAndReason(HTTPResponse::HTTP_NOT_FOUND); - response.setContentLength(0); // TODO return some 404 page? - response.send(); + // response.setStatusAndReason(HTTPResponse::HTTP_NOT_FOUND); + // response.setContentLength(0); // TODO return some 404 page? + // response.send(); return; } @@ -231,8 +231,8 @@ void FileServerRequestHandler::preprocessFile(HTTPServerRequest& request, HTTPSe StreamCopier::copyToString(file, preprocess); file.close(); - const std::string& accessToken = form.get("access_token", ""); - const std::string& accessTokenTtl = form.get("access_token_ttl", ""); + const std::string& accessToken = request.get("access_token", ""); + const std::string& accessTokenTtl = request.get("access_token_ttl", ""); // Escape bad characters in access token. // This is placed directly in javascript in loleaflet.html, we need to make sure @@ -269,17 +269,19 @@ void FileServerRequestHandler::preprocessFile(HTTPServerRequest& request, HTTPSe const auto loleafletLogging = config.getString("loleaflet_logging", "false"); Poco::replaceInPlace(preprocess, std::string("%LOLEAFLET_LOGGING%"), loleafletLogging); - response.setContentType("text/html"); - response.setContentLength(preprocess.length()); - response.setChunkedTransferEncoding(false); + const std::string mimeType = "text/html"; - std::ostream& ostr = response.send(); - ostr << preprocess; -} + std::ostringstream oss; + oss << "HTTP/1.1 200 OK\r\n" + << "Last-Modified: " << Poco::DateTimeFormatter::format(Poco::Timestamp(), Poco::DateTimeFormat::HTTP_FORMAT) << "\r\n" + << "User-Agent: LOOLWSD WOPI Agent\r\n" + << "Content-Length: " << preprocess.size() << "\r\n" + << "Content-Type: " << mimeType << "\r\n" + << "\r\n" + << preprocess; -FileServer::FileServer() -{ - LOG_INF("FileServer ctor."); + socket->send(oss.str()); + LOG_DBG("Sent file: " << path.toString()); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/wsd/FileServer.hpp b/wsd/FileServer.hpp index a9f56cdd9..773896859 100644 --- a/wsd/FileServer.hpp +++ b/wsd/FileServer.hpp @@ -18,40 +18,20 @@ #include #include -/// Handles file requests over HTTP(S). -class FileServerRequestHandler : public Poco::Net::HTTPRequestHandler -{ - static std::string getRequestPathname(const Poco::Net::HTTPServerRequest& request); +#include "Socket.hpp" - static void preprocessFile(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) throw(Poco::FileAccessDeniedException); +/// Handles file requests over HTTP(S). +class FileServerRequestHandler +{ + static std::string getRequestPathname(const Poco::Net::HTTPRequest& request); + + static void preprocessFile(const Poco::Net::HTTPRequest& request, const std::shared_ptr& socket); public: /// Evaluate if the cookie exists, and if not, ask for the credentials. static bool isAdminLoggedIn(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response); - void handleRequest(Poco::Net::HTTPServerRequest& request, Poco::Net::HTTPServerResponse& response) override; -}; - -/// Singleton class to serve files over HTTP(S). -class FileServer -{ -public: - static FileServer& instance() - { - static FileServer fileServer; - return fileServer; - } - - static FileServerRequestHandler* createRequestHandler() - { - return new FileServerRequestHandler(); - } - - FileServer(FileServer const&) = delete; - void operator=(FileServer const&) = delete; - -private: - FileServer(); + static void handleRequest(const Poco::Net::HTTPRequest& request, const std::shared_ptr& socket); }; #endif diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp index 1b71f6df3..c4aa71a3c 100644 --- a/wsd/LOOLWSD.cpp +++ b/wsd/LOOLWSD.cpp @@ -2762,7 +2762,8 @@ private: void handleFileServerRequest(const Poco::Net::HTTPRequest& request) { LOG_ERR("FileServer request: " << request.getURI()); - // requestHandler = FileServer::createRequestHandler(); + auto socket = _socket.lock(); + FileServerRequestHandler::handleRequest(request, socket); } void handleAdminRequest(const Poco::Net::HTTPRequest& request)