[Libreoffice-commits] online.git: loolwsd/LOOLWSD.cpp
Ashod Nakashian
ashod.nakashian at collabora.co.uk
Sun Jan 24 13:11:11 PST 2016
loolwsd/LOOLWSD.cpp | 337 +++++++++++++++++++++++++++-------------------------
1 file changed, 175 insertions(+), 162 deletions(-)
New commits:
commit f9fd4c917a3acb75ee86dfca29e084542a77f756
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date: Sun Jan 24 14:48:09 2016 -0500
loolwsd: refactored HTTP Request Handler
Change-Id: I84685910afa04664639ae674fd66ff888962387e
Reviewed-on: https://gerrit.libreoffice.org/21757
Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
Tested-by: Ashod Nakashian <ashnakash at gmail.com>
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 138fde7..bbb4c84 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -329,206 +329,219 @@ void SocketProcessor(std::shared_ptr<WebSocket> ws,
/// Handle a public connection from a client.
class ClientRequestHandler: public HTTPRequestHandler
{
-public:
+private:
- void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) override
+ void handlePostRequest(HTTPServerRequest& request, HTTPServerResponse& response, const std::string& id)
{
- const auto id = LOOLWSD::GenSessionId();
- const std::string thread_name = "client_ws_" + id;
-
-#ifdef __linux
- if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(thread_name.c_str()), 0, 0, 0) != 0)
- Log::error("Cannot set thread name to " + thread_name + ".");
-#endif
- Log::debug("Thread [" + thread_name + "] started.");
-
- if (!(request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0))
+ Log::info("Post request.");
+ StringTokenizer tokens(request.getURI(), "/?");
+ if (tokens.count() >= 2 && tokens[1] == "convert-to")
{
- Log::info("Post request.");
- StringTokenizer tokens(request.getURI(), "/?");
- if (tokens.count() >= 2 && tokens[1] == "convert-to")
+ Log::info("Conversion request.");
+ std::string fromPath;
+ ConvertToPartHandler handler(fromPath);
+ Poco::Net::HTMLForm form(request, request.stream(), handler);
+ std::string format;
+ if (form.has("format"))
+ format = form.get("format");
+
+ bool sent = false;
+ if (!fromPath.empty())
{
- Log::info("Conversion request.");
- std::string fromPath;
- ConvertToPartHandler handler(fromPath);
- Poco::Net::HTMLForm form(request, request.stream(), handler);
- std::string format;
- if (form.has("format"))
- format = form.get("format");
-
- bool sent = false;
- if (!fromPath.empty())
+ if (!format.empty())
{
- if (!format.empty())
- {
- // Load the document.
- std::shared_ptr<WebSocket> ws;
- const LOOLSession::Kind kind = LOOLSession::Kind::ToClient;
- auto session = std::make_shared<MasterProcessSession>(id, kind, ws);
- const std::string filePrefix("file://");
- std::string encodedFrom;
- URI::encode(filePrefix + fromPath, std::string(), encodedFrom);
- const std::string load = "load url=" + encodedFrom;
- session->handleInput(load.data(), load.size());
-
- // Convert it to the requested format.
- Path toPath(fromPath);
- toPath.setExtension(format);
- std::string toJailURL = filePrefix + JailedDocumentRoot + toPath.getFileName();
- std::string encodedTo;
- URI::encode(toJailURL, std::string(), encodedTo);
+ // Load the document.
+ std::shared_ptr<WebSocket> ws;
+ const LOOLSession::Kind kind = LOOLSession::Kind::ToClient;
+ auto session = std::make_shared<MasterProcessSession>(id, kind, ws);
+ const std::string filePrefix("file://");
+ std::string encodedFrom;
+ URI::encode(filePrefix + fromPath, std::string(), encodedFrom);
+ const std::string load = "load url=" + encodedFrom;
+ session->handleInput(load.data(), load.size());
+
+ // Convert it to the requested format.
+ Path toPath(fromPath);
+ toPath.setExtension(format);
+ std::string toJailURL = filePrefix + JailedDocumentRoot + toPath.getFileName();
+ std::string encodedTo;
+ URI::encode(toJailURL, std::string(), encodedTo);
std::string saveas = "saveas url=" + encodedTo + " format=" + format + " options=";
- session->handleInput(saveas.data(), saveas.size());
+ session->handleInput(saveas.data(), saveas.size());
- std::string toURL = session->getSaveAs();
- std::string resultingURL;
- URI::decode(toURL, resultingURL);
+ std::string toURL = session->getSaveAs();
+ std::string resultingURL;
+ URI::decode(toURL, resultingURL);
- // Send it back to the client.
- if (resultingURL.find(filePrefix) == 0)
- resultingURL = resultingURL.substr(filePrefix.length());
- if (!resultingURL.empty())
- {
- const std::string mimeType = "application/octet-stream";
- response.sendFile(resultingURL, mimeType);
- sent = true;
- }
+ // Send it back to the client.
+ if (resultingURL.find(filePrefix) == 0)
+ resultingURL = resultingURL.substr(filePrefix.length());
+ if (!resultingURL.empty())
+ {
+ const std::string mimeType = "application/octet-stream";
+ response.sendFile(resultingURL, mimeType);
+ sent = true;
}
-
- // Clean up the temporary directory the HTMLForm ctor created.
- Path tempDirectory(fromPath);
- tempDirectory.setFileName("");
- Util::removeFile(tempDirectory, /*recursive=*/true);
}
- if (!sent)
- {
- response.setStatus(HTTPResponse::HTTP_BAD_REQUEST);
- response.setContentLength(0);
- response.send();
- }
+ // Clean up the temporary directory the HTMLForm ctor created.
+ Path tempDirectory(fromPath);
+ tempDirectory.setFileName("");
+ Util::removeFile(tempDirectory, /*recursive=*/true);
}
- else if (tokens.count() >= 2 && tokens[1] == "insertfile")
+
+ if (!sent)
{
- Log::info("Insert file request.");
- response.set("Access-Control-Allow-Origin", "*");
- response.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
- response.set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
+ response.setStatus(HTTPResponse::HTTP_BAD_REQUEST);
+ response.setContentLength(0);
+ response.send();
+ }
+ }
+ else if (tokens.count() >= 2 && tokens[1] == "insertfile")
+ {
+ Log::info("Insert file request.");
+ response.set("Access-Control-Allow-Origin", "*");
+ response.set("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
+ response.set("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
- std::string tmpPath;
- ConvertToPartHandler handler(tmpPath);
- Poco::Net::HTMLForm form(request, request.stream(), handler);
+ std::string tmpPath;
+ ConvertToPartHandler handler(tmpPath);
+ Poco::Net::HTMLForm form(request, request.stream(), handler);
- bool goodRequest = form.has("childid") && form.has("name");
- std::string formChildid(form.get("childid"));
- std::string formName(form.get("name"));
+ bool goodRequest = form.has("childid") && form.has("name");
+ std::string formChildid(form.get("childid"));
+ std::string formName(form.get("name"));
- // protect against attempts to inject something funny here
- if (goodRequest && formChildid.find('/') != std::string::npos && formName.find('/') != std::string::npos)
- goodRequest = false;
+ // protect against attempts to inject something funny here
+ if (goodRequest && formChildid.find('/') != std::string::npos && formName.find('/') != std::string::npos)
+ goodRequest = false;
- if (goodRequest)
+ if (goodRequest)
+ {
+ try
{
- try
- {
- Log::info() << "Perform insertfile: " << formChildid << ", " << formName << Log::end;
- const std::string dirPath = LOOLWSD::ChildRoot + formChildid
- + JailedDocumentRoot + "insertfile";
- File(dirPath).createDirectories();
- std::string fileName = dirPath + Path::separator() + form.get("name");
- File(tmpPath).moveTo(fileName);
-
- response.setStatus(HTTPResponse::HTTP_OK);
- response.send();
- }
- catch (const IOException& exc)
- {
- Log::info() << "IOException: " << exc.message() << Log::end;
- response.setStatus(HTTPResponse::HTTP_BAD_REQUEST);
- response.send();
- }
+ Log::info() << "Perform insertfile: " << formChildid << ", " << formName << Log::end;
+ const std::string dirPath = LOOLWSD::ChildRoot + formChildid
+ + JailedDocumentRoot + "insertfile";
+ File(dirPath).createDirectories();
+ std::string fileName = dirPath + Path::separator() + form.get("name");
+ File(tmpPath).moveTo(fileName);
+
+ response.setStatus(HTTPResponse::HTTP_OK);
+ response.send();
}
- else
+ catch (const IOException& exc)
{
+ Log::info() << "IOException: " << exc.message() << Log::end;
response.setStatus(HTTPResponse::HTTP_BAD_REQUEST);
response.send();
}
}
- else if (tokens.count() >= 4)
+ else
{
- Log::info("File download request.");
- // The user might request a file to download
- const std::string dirPath = LOOLWSD::ChildRoot + tokens[1]
- + JailedDocumentRoot + tokens[2];
- std::string fileName;
- URI::decode(tokens[3], fileName);
- const std::string filePath = dirPath + Path::separator() + fileName;
- Log::info("HTTP request for: " + filePath);
- File file(filePath);
- if (file.exists())
- {
- response.set("Access-Control-Allow-Origin", "*");
- Poco::Net::HTMLForm form(request);
- std::string mimeType = "application/octet-stream";
- if (form.has("mime_type"))
- mimeType = form.get("mime_type");
- response.sendFile(filePath, mimeType);
- Util::removeFile(dirPath, true);
- }
- else
- {
- response.setStatus(HTTPResponse::HTTP_NOT_FOUND);
- response.setContentLength(0);
- response.send();
- }
+ response.setStatus(HTTPResponse::HTTP_BAD_REQUEST);
+ response.send();
+ }
+ }
+ else if (tokens.count() >= 4)
+ {
+ Log::info("File download request.");
+ // The user might request a file to download
+ const std::string dirPath = LOOLWSD::ChildRoot + tokens[1]
+ + JailedDocumentRoot + tokens[2];
+ std::string fileName;
+ URI::decode(tokens[3], fileName);
+ const std::string filePath = dirPath + Path::separator() + fileName;
+ Log::info("HTTP request for: " + filePath);
+ File file(filePath);
+ if (file.exists())
+ {
+ response.set("Access-Control-Allow-Origin", "*");
+ Poco::Net::HTMLForm form(request);
+ std::string mimeType = "application/octet-stream";
+ if (form.has("mime_type"))
+ mimeType = form.get("mime_type");
+ response.sendFile(filePath, mimeType);
+ Util::removeFile(dirPath, true);
}
else
{
- Log::info("Bad request.");
- response.setStatus(HTTPResponse::HTTP_BAD_REQUEST);
+ response.setStatus(HTTPResponse::HTTP_NOT_FOUND);
response.setContentLength(0);
response.send();
}
- return;
}
-
- try
+ else
{
- Log::info("Get request.");
- auto ws = std::make_shared<WebSocket>(request, response);
- auto session = std::make_shared<MasterProcessSession>(id, LOOLSession::Kind::ToClient, ws);
+ Log::info("Bad request.");
+ response.setStatus(HTTPResponse::HTTP_BAD_REQUEST);
+ response.setContentLength(0);
+ response.send();
+ }
+ }
+
+ void handleGetRequest(HTTPServerRequest& request, HTTPServerResponse& response, const std::string& id)
+ {
+ Log::info("Get request.");
+ auto ws = std::make_shared<WebSocket>(request, response);
+ auto session = std::make_shared<MasterProcessSession>(id, LOOLSession::Kind::ToClient, ws);
- // For ToClient sessions, we store incoming messages in a queue and have a separate
- // thread that handles them. This is so that we can empty the queue when we get a
- // "canceltiles" message.
- BasicTileQueue queue;
- QueueHandler handler(queue, session, "wsd_queue_" + session->getId());
+ // For ToClient sessions, we store incoming messages in a queue and have a separate
+ // thread that handles them. This is so that we can empty the queue when we get a
+ // "canceltiles" message.
+ BasicTileQueue queue;
+ QueueHandler handler(queue, session, "wsd_queue_" + session->getId());
- Thread queueHandlerThread;
- queueHandlerThread.start(handler);
+ Thread queueHandlerThread;
+ queueHandlerThread.start(handler);
- SocketProcessor(ws, response, [&session, &queue](const char* data, const int size, const bool singleLine)
+ SocketProcessor(ws, response, [&session, &queue](const char* data, const int size, const bool singleLine)
+ {
+ // FIXME: There is a race here when a request A gets in the queue and
+ // is processed _after_ a later request B, because B gets processed
+ // synchronously and A is waiting in the queue thread.
+ // The fix is to push everything into the queue
+ // (i.e. change MessageQueue to vector<char>).
+ const std::string firstLine = getFirstLine(data, size);
+ if (singleLine || firstLine.find("paste") == 0)
{
- // FIXME: There is a race here when a request A gets in the queue and
- // is processed _after_ a later request B, because B gets processed
- // synchronously and A is waiting in the queue thread.
- // The fix is to push everything into the queue
- // (i.e. change MessageQueue to vector<char>).
- const std::string firstLine = getFirstLine(data, size);
- if (singleLine || firstLine.find("paste") == 0)
- {
- queue.put(std::string(data, size));
- return true;
- }
- else
- {
- return session->handleInput(data, size);
- }
- });
+ queue.put(std::string(data, size));
+ return true;
+ }
+ else
+ {
+ return session->handleInput(data, size);
+ }
+ });
+
+ queue.clear();
+ queue.put("eof");
+ queueHandlerThread.join();
+ }
+
+public:
+
+ void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) override
+ {
+ const auto id = LOOLWSD::GenSessionId();
+ const std::string thread_name = "client_ws_" + id;
- queue.clear();
- queue.put("eof");
- queueHandlerThread.join();
+#ifdef __linux
+ if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(thread_name.c_str()), 0, 0, 0) != 0)
+ Log::error("Cannot set thread name to " + thread_name + ".");
+#endif
+ Log::debug("Thread [" + thread_name + "] started.");
+
+ try
+ {
+ if (!(request.find("Upgrade") != request.end() && Poco::icompare(request["Upgrade"], "websocket") == 0))
+ {
+ handlePostRequest(request, response, id);
+ }
+ else
+ {
+ handleGetRequest(request, response, id);
+ }
}
catch (const Exception& exc)
{
More information about the Libreoffice-commits
mailing list