[Libreoffice-commits] online.git: loolwsd/LOOLWSD.cpp loolwsd/LOOLWSD.hpp loolwsd/MasterProcessSession.cpp

Ashod Nakashian ashod.nakashian at collabora.co.uk
Wed Jan 6 21:57:43 PST 2016


 loolwsd/LOOLWSD.cpp              |    4 +
 loolwsd/LOOLWSD.hpp              |  118 +++++++++++++++++++++++++++++++++++++++
 loolwsd/MasterProcessSession.cpp |   69 ++++------------------
 3 files changed, 136 insertions(+), 55 deletions(-)

New commits:
commit a7556a7c1e298e40de55e915017a9fad4e0d519c
Author: Ashod Nakashian <ashod.nakashian at collabora.co.uk>
Date:   Thu Jan 7 00:16:47 2016 -0500

    loolwsd: new Document class to manage the lifetime of a document
    
    Change-Id: I8596d0f2514106e384bc6519ce05028753026678
    Reviewed-on: https://gerrit.libreoffice.org/21184
    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 7117cb3..5afeb6d 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -151,6 +151,10 @@ using Poco::NamedMutex;
 using Poco::ProcessHandle;
 using Poco::URI;
 
+// Document management mutex.
+std::mutex Document::DocumentsMutex;
+std::map<std::string, std::shared_ptr<Document>> Document::UriToDocumentMap;
+
 /// Handles the filename part of the convert-to POST request payload.
 class ConvertToPartHandler : public Poco::Net::PartHandler
 {
diff --git a/loolwsd/LOOLWSD.hpp b/loolwsd/LOOLWSD.hpp
index f8e8f63..44ad381 100644
--- a/loolwsd/LOOLWSD.hpp
+++ b/loolwsd/LOOLWSD.hpp
@@ -23,8 +23,126 @@
 #include <Poco/SharedMemory.h>
 #include <Poco/NamedMutex.h>
 
+#include "Common.hpp"
 #include "Util.hpp"
 
+// A Document as mananged by us.
+// Contains URI, physical path, etc.
+class Document
+{
+public:
+
+    static
+    std::shared_ptr<Document> create(const std::string& url,
+                                     const std::string& jailRoot,
+                                     const std::string& childId)
+    {
+        // TODO: Sanitize the url and limit access!
+        auto uriPublic = Poco::URI(url);
+        uriPublic.normalize();
+
+        const auto publicFilePath = uriPublic.getPath();
+
+        if (publicFilePath.empty())
+            throw std::runtime_error("Invalid URL.");
+
+        // This lock could become a bottleneck.
+        // In that case, we can use a pool and index by publicPath.
+        std::unique_lock<std::mutex> lock(DocumentsMutex);
+
+        // Find the document if already open.
+        auto it = UriToDocumentMap.lower_bound(publicFilePath);
+        if (it != UriToDocumentMap.end())
+        {
+            Log::info("Document [" + it->first + "] found.");
+            return it->second;
+        }
+
+        // The URL is the publicly visible one, not visible in the chroot jail.
+        // We need to map it to a jailed path and copy the file there.
+        auto uriJailed = uriPublic;
+        if (uriPublic.isRelative() || uriPublic.getScheme() == "file")
+        {
+            // chroot/jailId/user/doc
+            const auto jailedDocRoot = Poco::Path(jailRoot, JailedDocumentRoot);
+
+            // chroot/jailId/user/doc/childId
+            const auto docPath = Poco::Path(jailedDocRoot, childId);
+            Poco::File(docPath).createDirectories();
+
+            const auto filename = Poco::Path(uriPublic.getPath()).getFileName();
+
+            // chroot/jailId/user/doc/childId/file.ext
+            const auto jailedFilePath = Poco::Path(docPath, filename).toString();
+
+            uriJailed = Poco::URI(Poco::URI("file://"), jailedFilePath);
+
+            Log::info("Public URI [" + uriPublic.toString() +
+                      "] jailed to [" + uriJailed.toString() + "].");
+
+#ifdef __linux
+            Log::info("Linking " + publicFilePath + " to " + jailedFilePath);
+            if (!Poco::File(jailedFilePath).exists() && link(publicFilePath.c_str(), jailedFilePath.c_str()) == -1)
+            {
+                // Failed
+                Log::error("link(\"" + publicFilePath + "\", \"" + jailedFilePath + "\") failed.");
+            }
+#endif
+
+            try
+            {
+                // Fallback to copying.
+                if (!Poco::File(jailedFilePath).exists())
+                {
+                    Log::info("Copying " + publicFilePath + " to " + jailedFilePath);
+                    Poco::File(publicFilePath).copyTo(jailedFilePath);
+                }
+            }
+            catch (const Poco::Exception& exc)
+            {
+                Log::error("copyTo(\"" + publicFilePath + "\", \"" + jailedFilePath + "\") failed: " + exc.displayText());
+                throw;
+            }
+        }
+        else
+        {
+            Log::info("Public URI [" + uriPublic.toString() +
+                      "] is not a file.");
+        }
+
+        auto document = std::shared_ptr<Document>(new Document(uriPublic, uriJailed, childId));
+
+        Log::info("Document [" + publicFilePath + "] created.");
+        it = UriToDocumentMap.emplace_hint(it, publicFilePath, document);
+        return it->second;
+    }
+
+    Poco::URI getPublicUri() const { return _uriPublic; }
+    Poco::URI getJailedUri() const { return _uriJailed; }
+    std::string getChildId() const { return _childId; }
+
+private:
+    Document(const Poco::URI& uriPublic,
+             const Poco::URI& uriJailed,
+             const std::string& childId) :
+       _uriPublic(uriPublic),
+       _uriJailed(uriJailed),
+       _childId(childId)
+    {
+    }
+
+private:
+
+    // Document management mutex.
+    static std::mutex DocumentsMutex;
+    static std::map<std::string, std::shared_ptr<Document>> UriToDocumentMap;
+
+private:
+    const Poco::URI _uriPublic;
+    const Poco::URI _uriJailed;
+    const std::string _childId;
+};
+
 class LOOLWSD: public Poco::Util::ServerApplication
 {
 public:
diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp
index 99db723..902b56f 100644
--- a/loolwsd/MasterProcessSession.cpp
+++ b/loolwsd/MasterProcessSession.cpp
@@ -617,67 +617,26 @@ void MasterProcessSession::dispatchChild()
         return;
     }
 
-    // Assume a valid URI
-    URI aUri(_docURL);
+    const auto jailRoot = Poco::Path(LOOLWSD::childRoot, LOOLWSD::jailId);
+    const auto childId = std::to_string(childSession->_pidChild);
 
-    if (aUri.isRelative())
-        aUri = URI( URI("file://"), aUri.toString() );
+    auto document = Document::create(_docURL, jailRoot.toString(), childId);
 
-    // Copy document into jail using the fixed name
-    if (!aUri.empty() && aUri.getScheme() == "file")
-    {
-        const std::string aJailDoc = JailedDocumentRoot.substr(1) + Path::separator() + std::to_string(childSession->_pidChild);
-        const Path aSrcFile(aUri.getPath());
-        const Path aDstPath(getJailPath(childSession->_childId), aJailDoc);
-        const Path aDstFile(aDstPath, aSrcFile.getFileName());
-        const Path aJailFile(aJailDoc, aSrcFile.getFileName());
-
-        Log::debug("JailDoc: " + aJailDoc);
-        Log::debug("SrcFile: " + aSrcFile.toString());
-        Log::debug("DstFile: " + aDstFile.toString());
-        Log::debug("JailFile: " + aJailFile.toString());
-
-        try
-        {
-            File(aDstPath).createDirectories();
-        }
-        catch (const Exception& exc)
-        {
-            Log::error(getName() + ": createDirectories(\"" + aDstPath.toString() + "\") failed: " + exc.displayText() );
-        }
+    _peer = childSession;
+    childSession->_peer = shared_from_this();
 
-        // cleanup potential leftovers from the last time
-        Util::removeFile(aDstFile);
+    std::ostringstream oss;
+    oss << "load";
+    oss << " url=" << document->getPublicUri().toString();
+    oss << " jail=" << document->getJailedUri().toString();
 
-#ifdef __linux
-        Log::info("Linking " + aSrcFile.toString() + " to " + aDstFile.toString());
-        if (!File(aDstFile).exists() && link(aSrcFile.toString().c_str(), aDstFile.toString().c_str()) == -1)
-        {
-            // Failed
-            Log::error(getName() + ": link(\"" + aSrcFile.toString() + "\",\"" + aDstFile.toString() + "\") failed.");
-        }
-#endif
+    if (_loadPart >= 0)
+        oss << " part=" + _loadPart;
 
-        try
-        {
-            //fallback
-            if (!File(aDstFile).exists())
-            {
-                Log::info("Copying " + aSrcFile.toString() + " to " + aDstFile.toString());
-                File(aSrcFile).copyTo(aDstFile.toString());
-            }
-        }
-        catch (const Exception& exc)
-        {
-            Log::error(getName() + ": copyTo(\"" + aSrcFile.toString() + "\",\"" + aDstFile.toString() + "\") failed: " + exc.displayText());
-        }
-    }
-
-    _peer = childSession;
-    childSession->_peer = shared_from_this();
+    if (!_docOptions.empty())
+        oss << " options=" << _docOptions;
 
-    const std::string loadRequest = "load" + (_loadPart >= 0 ?  " part=" + std::to_string(_loadPart) : "")
-                                  + " url=" + _docURL + (!_docOptions.empty() ? " options=" + _docOptions : "");
+    const auto loadRequest = oss.str();
     forwardToPeer(loadRequest.c_str(), loadRequest.size());
 }
 


More information about the Libreoffice-commits mailing list