[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