nb: serve files using non-blocking sockets

Change-Id: I254288980f72f197d29b7b57ec9c88a01a5a1d03
This commit is contained in:
Ashod Nakashian 2017-02-27 08:28:04 -05:00 committed by Jan Holesovsky
parent ba8d3c8eb1
commit 1bb29282f1
3 changed files with 45 additions and 62 deletions

View file

@ -12,6 +12,8 @@
#include <string>
#include <vector>
#include <Poco/DateTimeFormat.h>
#include <Poco/DateTimeFormatter.h>
#include <Poco/Exception.h>
#include <Poco/FileStream.h>
#include <Poco/Net/HTTPCookie.h>
@ -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<StreamSocket>& 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<StreamSocket>& 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: */

View file

@ -18,40 +18,20 @@
#include <Poco/Net/HTTPServerRequest.h>
#include <Poco/Net/HTTPServerResponse.h>
/// 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<StreamSocket>& 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<StreamSocket>& socket);
};
#endif

View file

@ -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)