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.nakash...@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 <ashnak...@gmail.com> Tested-by: Ashod Nakashian <ashnak...@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()); } _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits