[Libreoffice-commits] online.git: Branch 'private/mmeeks/unitbits' - 262 commits - loleaflet/dist loleaflet/.gitattributes loleaflet/.gitignore loleaflet/loleaflet.spec.in loleaflet/Makefile loleaflet/reference.html loleaflet/src loolwsd/Admin.cpp loolwsd/Admin.hpp loolwsd/AdminModel.cpp loolwsd/AdminModel.hpp loolwsd/autogen.sh loolwsd/bundled loolwsd/ChildProcessSession.cpp loolwsd/ChildProcessSession.hpp loolwsd/Common.hpp loolwsd/configure.ac loolwsd/Connect.cpp loolwsd/debian loolwsd/DocumentBroker.cpp loolwsd/DocumentBroker.hpp loolwsd/etc loolwsd/FileServer.hpp loolwsd/.gitignore loolwsd/IoUtil.cpp loolwsd/IoUtil.hpp loolwsd/Log.cpp loolwsd/Log.hpp loolwsd/LOKitClient.cpp loolwsd/LOKitHelper.hpp loolwsd/LOOLForKit.cpp loolwsd/LOOLKit.cpp loolwsd/LOOLKit.hpp loolwsd/loolmount.c loolwsd/LOOLProtocol.hpp loolwsd/LOOLSession.cpp loolwsd/LOOLSession.hpp loolwsd/loolstat loolwsd/LOOLTool.cpp loolwsd/LOOLWSD.cpp loolwsd/LOOLWSD.hpp loolwsd/loolwsd.service loolwsd/loolwsd.spec.in loolwsd/loolwsd-s ystemplate-setup loolwsd/loolwsd.xml loolwsd/loolwsd.xml.in loolwsd/Makefile.am loolwsd/MasterProcessSession.cpp loolwsd/MasterProcessSession.hpp loolwsd/PROBLEMS loolwsd/protocol.txt loolwsd/QueueHandler.hpp loolwsd/README loolwsd/README.vars loolwsd/security.h loolwsd/Storage.cpp loolwsd/Storage.hpp loolwsd/test loolwsd/TileCache.cpp loolwsd/TileCache.hpp loolwsd/Unit.cpp loolwsd/Unit.hpp loolwsd/UnitHTTP.hpp loolwsd/Util.cpp loolwsd/Util.hpp scripts/logparse.pl scripts/segv-catch.pl

Michael Meeks (via logerrit) logerrit at kemper.freedesktop.org
Sat Dec 7 01:50:36 UTC 2019


Rebased ref, commits from common ancestor:
commit c06a7caf61b69ad2de74b07310570503a17c2400
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Sat Apr 16 20:44:53 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Sat Apr 16 20:44:53 2016 +0100

    Attempt at a --nocaps argument to run with no caps, ie. under valgrind.

diff --git a/loolwsd/LOOLForKit.cpp b/loolwsd/LOOLForKit.cpp
index ffebf5652..4d7ba5f28 100644
--- a/loolwsd/LOOLForKit.cpp
+++ b/loolwsd/LOOLForKit.cpp
@@ -44,6 +44,7 @@ using Poco::Thread;
 using Poco::Timestamp;
 using Poco::Util::Application;
 
+static bool NoCapsForKit = false;
 static std::string UnitTestLibrary;
 static std::atomic<unsigned> ForkCounter( 0 );
 
@@ -117,7 +118,7 @@ static int createLibreOfficeKit(const std::string& childRoot,
             Thread::sleep(std::stoul(std::getenv("SLEEPKITFORDEBUGGER")) * 1000);
         }
 
-        lokit_main(childRoot, sysTemplate, loTemplate, loSubPath);
+        lokit_main(childRoot, sysTemplate, loTemplate, loSubPath, NoCapsForKit);
     }
     else
     {
@@ -213,6 +214,11 @@ int main(int argc, char** argv)
             eq = std::strchr(cmd, '=');
             UnitTestLibrary = std::string(eq+1);
         }
+        // we are running in no-privilege mode - with no chroot etc.
+        else if (std::strstr(cmd, "--nocaps") == cmd)
+        {
+            NoCapsForKit = true;
+        }
 #endif
     }
 
diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp
index 7f55ec966..1a91bb636 100644
--- a/loolwsd/LOOLKit.cpp
+++ b/loolwsd/LOOLKit.cpp
@@ -847,7 +847,8 @@ namespace {
 void lokit_main(const std::string& childRoot,
                 const std::string& sysTemplate,
                 const std::string& loTemplate,
-                const std::string& loSubPath)
+                const std::string& loSubPath,
+                bool noCapabilities)
 {
     // Reinitialize logging when forked.
     Log::initialize("kit");
@@ -874,102 +875,112 @@ void lokit_main(const std::string& childRoot,
     Util::setTerminationSignals();
     Util::setFatalSignals();
 
-    static const std::string instdir_path = "/" + loSubPath + "/program";
-    LibreOfficeKit* loKit = nullptr;
+    std::string instdir_path;
 
+    Path jailPath;
+    bool bRunInsideJail = !noCapabilities;
     try
     {
-        const Path jailPath = Path::forDirectory(childRoot + Path::separator() + jailId);
-        Log::info("Jail path: " + jailPath.toString());
-        File(jailPath).createDirectories();
+        if (bRunInsideJail)
+        {
+            instdir_path = "/" + loSubPath + "/program";
 
-        // Create a symlink inside the jailPath so that the absolute pathname loTemplate, when
-        // interpreted inside a chroot at jailPath, points to loSubPath (relative to the chroot).
-        symlinkPathToJail(jailPath, loTemplate, loSubPath);
+            jailPath = Path::forDirectory(childRoot + Path::separator() + jailId);
+            Log::info("Jail path: " + jailPath.toString());
+            File(jailPath).createDirectories();
 
-        // Font paths can end up as realpaths so match that too.
-        char *resolved = realpath(loTemplate.c_str(), NULL);
-        if (resolved)
-        {
-            if (strcmp(loTemplate.c_str(), resolved))
-                symlinkPathToJail(jailPath, std::string(resolved), loSubPath);
-            free (resolved);
-        }
+            // Create a symlink inside the jailPath so that the absolute pathname loTemplate, when
+            // interpreted inside a chroot at jailPath, points to loSubPath (relative to the chroot).
+            symlinkPathToJail(jailPath, loTemplate, loSubPath);
 
-        Path jailLOInstallation(jailPath, loSubPath);
-        jailLOInstallation.makeDirectory();
-        File(jailLOInstallation).createDirectory();
+            // Font paths can end up as realpaths so match that too.
+            char *resolved = realpath(loTemplate.c_str(), NULL);
+            if (resolved)
+            {
+                if (strcmp(loTemplate.c_str(), resolved))
+                    symlinkPathToJail(jailPath, std::string(resolved), loSubPath);
+                free (resolved);
+            }
 
-        // Copy (link) LO installation and other necessary files into it from the template.
-        bool bLoopMounted = false;
-        if (getenv("LOOL_BIND_MOUNT"))
-        {
-            Path usrSrcPath(sysTemplate, "usr");
-            Path usrDestPath(jailPath, "usr");
-            File(usrDestPath).createDirectory();
-            std::string mountCommand =
-                std::string("loolmount ") +
-                usrSrcPath.toString() +
-                std::string(" ") +
-                usrDestPath.toString();
-            Log::debug("Initializing jail bind mount.");
-            bLoopMounted = !system(mountCommand.c_str());
-            Log::debug("Initialized jail bind mount.");
-        }
-        linkOrCopy(sysTemplate, jailPath,
-                   bLoopMounted ? COPY_NO_USR : COPY_ALL);
-        linkOrCopy(loTemplate, jailLOInstallation, COPY_LO);
+            Path jailLOInstallation(jailPath, loSubPath);
+            jailLOInstallation.makeDirectory();
+            File(jailLOInstallation).createDirectory();
 
-        // We need this because sometimes the hostname is not resolved
-        const auto networkFiles = {"/etc/host.conf", "/etc/hosts", "/etc/nsswitch.conf", "/etc/resolv.conf"};
-        for (const auto& filename : networkFiles)
-        {
-            const auto etcPath = Path(jailPath, filename).toString();
-            const File networkFile(filename);
-            if (networkFile.exists() && !File(etcPath).exists())
+            // Copy (link) LO installation and other necessary files into it from the template.
+            bool bLoopMounted = false;
+            if (getenv("LOOL_BIND_MOUNT"))
             {
-                networkFile.copyTo(etcPath);
+                Path usrSrcPath(sysTemplate, "usr");
+                Path usrDestPath(jailPath, "usr");
+                File(usrDestPath).createDirectory();
+                std::string mountCommand =
+                    std::string("loolmount ") +
+                    usrSrcPath.toString() +
+                    std::string(" ") +
+                    usrDestPath.toString();
+                Log::debug("Initializing jail bind mount.");
+                bLoopMounted = !system(mountCommand.c_str());
+                Log::debug("Initialized jail bind mount.");
             }
-        }
+            linkOrCopy(sysTemplate, jailPath,
+                       bLoopMounted ? COPY_NO_USR : COPY_ALL);
+            linkOrCopy(loTemplate, jailLOInstallation, COPY_LO);
 
-        Log::debug("Initialized jail files.");
+            // We need this because sometimes the hostname is not resolved
+            const auto networkFiles = {"/etc/host.conf", "/etc/hosts", "/etc/nsswitch.conf", "/etc/resolv.conf"};
+            for (const auto& filename : networkFiles)
+            {
+                const auto etcPath = Path(jailPath, filename).toString();
+                const File networkFile(filename);
+                if (networkFile.exists() && !File(etcPath).exists())
+                {
+                    networkFile.copyTo(etcPath);
+                }
+            }
 
-        // Create the urandom and random devices
-        File(Path(jailPath, "/dev")).createDirectory();
-        if (mknod((jailPath.toString() + "/dev/random").c_str(),
-                  S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
-                  makedev(1, 8)) != 0)
-        {
-            Log::syserror("mknod(" + jailPath.toString() + "/dev/random) failed.");
+            Log::debug("Initialized jail files.");
 
-        }
-        if (mknod((jailPath.toString() + "/dev/urandom").c_str(),
-                  S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
-                  makedev(1, 9)) != 0)
-        {
-            Log::syserror("mknod(" + jailPath.toString() + "/dev/urandom) failed.");
-        }
+            // Create the urandom and random devices
+            File(Path(jailPath, "/dev")).createDirectory();
+            if (mknod((jailPath.toString() + "/dev/random").c_str(),
+                      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
+                      makedev(1, 8)) != 0)
+            {
+                Log::syserror("mknod(" + jailPath.toString() + "/dev/random) failed.");
+            }
+            if (mknod((jailPath.toString() + "/dev/urandom").c_str(),
+                      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
+                      makedev(1, 9)) != 0)
+            {
+                Log::syserror("mknod(" + jailPath.toString() + "/dev/urandom) failed.");
+            }
 
-        Log::info("chroot(\"" + jailPath.toString() + "\")");
-        if (chroot(jailPath.toString().c_str()) == -1)
-        {
-            Log::syserror("chroot(\"" + jailPath.toString() + "\") failed.");
-            std::_Exit(Application::EXIT_SOFTWARE);
-        }
+            Log::info("chroot(\"" + jailPath.toString() + "\")");
+            if (chroot(jailPath.toString().c_str()) == -1)
+            {
+                Log::syserror("chroot(\"" + jailPath.toString() + "\") failed.");
+                std::_Exit(Application::EXIT_SOFTWARE);
+            }
 
-        if (chdir("/") == -1)
-        {
-            Log::syserror("chdir(\"/\") in jail failed.");
-            std::_Exit(Application::EXIT_SOFTWARE);
-        }
+            if (chdir("/") == -1)
+            {
+                Log::syserror("chdir(\"/\") in jail failed.");
+                std::_Exit(Application::EXIT_SOFTWARE);
+            }
 
-        dropCapability(CAP_SYS_CHROOT);
-        dropCapability(CAP_MKNOD);
-        dropCapability(CAP_FOWNER);
+            dropCapability(CAP_SYS_CHROOT);
+            dropCapability(CAP_MKNOD);
+            dropCapability(CAP_FOWNER);
 
-        Log::debug("Initialized jail nodes, dropped caps.");
+            Log::debug("Initialized jail nodes, dropped caps.");
+        }
+        else // noCapabilities set
+        {
+            Log::info("Using template " + loTemplate + " as install subpath - skipping jail setup");
+            instdir_path = "/" + loTemplate + "/program";
+        }
 
-        loKit = lok_init_2(instdir_path.c_str(), "file:///user");
+        LibreOfficeKit* loKit = lok_init_2(instdir_path.c_str(), "file:///user");
         if (loKit == nullptr)
         {
             Log::error("LibreOfficeKit initialization failed. Exiting.");
@@ -1042,8 +1053,11 @@ void lokit_main(const std::string& childRoot,
                     return TerminationFlag;
                 });
 
-        // Cleanup jail.
-        Util::removeFile(jailPath, true);
+        // Cleanup a jail if we created one
+        if (bRunInsideJail && !jailPath.isRelative())
+        {
+            Util::removeFile(jailPath, true);
+        }
     }
     catch (const Exception& exc)
     {
diff --git a/loolwsd/LOOLKit.hpp b/loolwsd/LOOLKit.hpp
index a8981662d..2f4302248 100644
--- a/loolwsd/LOOLKit.hpp
+++ b/loolwsd/LOOLKit.hpp
@@ -12,7 +12,8 @@
 void lokit_main(const std::string& childRoot,
                 const std::string& sysTemplate,
                 const std::string& loTemplate,
-                const std::string& loSubPath);
+                const std::string& loSubPath,
+                bool noCapabilities);
 
 bool globalPreinit(const std::string &loTemplate);
 
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 802850b44..0b0155cc4 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -147,6 +147,7 @@ int ClientPortNumber = DEFAULT_CLIENT_PORT_NUMBER;
 /// New LOK child processes ready to host documents.
 //TODO: Move to a more sensible namespace.
 static bool DisplayVersion = false;
+static bool NoCapsForKit = false;
 static std::vector<std::shared_ptr<ChildProcess>> newChildren;
 static std::mutex newChildrenMutex;
 static std::condition_variable newChildrenCV;
@@ -1216,6 +1217,11 @@ void LOOLWSD::defineOptions(OptionSet& optionSet)
                         .repeatable(false)
                         .argument("unitlib"));
 
+    optionSet.addOption(Option("nocaps", "", "Use a non-privileged forkit for valgrinding.")
+                        .required(false)
+                        .repeatable(false)
+                        .argument("nocaps"));
+
     optionSet.addOption(Option("careerspan", "", "How many seconds to run.")
                         .required(false)
                         .repeatable(false)
@@ -1258,6 +1264,8 @@ void LOOLWSD::handleOption(const std::string& optionName,
 #if ENABLE_DEBUG
     else if (optionName == "unitlib")
         UnitTestLibrary = value;
+    else if (optionName == "nocaps")
+        NoCapsForKit = true;
     else if (optionName == "careerspan")
         careerSpanSeconds = std::stoi(value);
 #endif
@@ -1286,7 +1294,13 @@ Process::PID LOOLWSD::createForKit()
     if (DisplayVersion)
         args.push_back("--version");
 
-    const std::string forKitPath = Path(Application::instance().commandPath()).parent().toString() + "loolforkit";
+    std::string forKitPath = Path(Application::instance().commandPath()).parent().toString() + "loolforkit";
+
+    if (NoCapsForKit)
+    {
+        forKitPath = forKitPath + std::string("-nocaps");
+        args.push_back("--nocaps");
+    }
 
     Log::info("Launching forkit process: " + forKitPath + " " +
               Poco::cat(std::string(" "), args.begin(), args.end()));
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index e3c5f7a88..39c5071ed 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -49,7 +49,8 @@ loolwsd_SOURCES = Admin.cpp \
 
 noinst_PROGRAMS = connect \
                   loadtest \
-                  lokitclient
+                  lokitclient \
+		  loolforkit-nocaps
 
 loadtest_SOURCES = LoadTest.cpp \
                    Log.cpp \
@@ -71,6 +72,9 @@ loolforkit_SOURCES = LOOLForKit.cpp \
                      LOOLKit.cpp \
                      $(shared_sources)
 
+# build a binary with no caps to help debugging
+loolforkit_nocaps_SOURCES = $(loolforkit_SOURCES)
+
 loolmount_SOURCES = loolmount.c
 
 loolmap_SOURCES = loolmap.c
commit a66e73aeb0789a87c6948e6c1e9a2fc3e13b3aa1
Author:     Henry Castro <hcastro at collabora.com>
AuthorDate: Sat Apr 16 13:29:00 2016 -0400
Commit:     Henry Castro <hcastro at collabora.com>
CommitDate: Sat Apr 16 13:32:44 2016 -0400

    loolwsd: fail when document broker cannot get a child

diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index a60d90d09..802850b44 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -543,10 +543,10 @@ private:
             if (!child)
             {
                 // Let the client know we can't serve now.
-                response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_SERVICE_UNAVAILABLE);
-                response.setContentLength(0);
-                response.send();
-                return;
+                status = "statusindicator: fail";
+                ws->sendFrame(status.data(), (int) status.size());
+                ws->shutdown();
+                throw WebSocketException("Failed to get new child. Client cannot serve now.", WebSocket::WS_ENDPOINT_GOING_AWAY);
             }
 
             // Set one we just created.
@@ -575,7 +575,6 @@ private:
 
         if (!waitBridgeCompleted(session, docBroker))
         {
-            Log::error(session->getName() + ": Failed to connect to lokit process. Client cannot serve now.");
             // Let the client know we can't serve now.
             status = "statusindicator: fail";
             ws->sendFrame(status.data(), (int) status.size());
diff --git a/loolwsd/test/httpwstest.cpp b/loolwsd/test/httpwstest.cpp
index 91dfb79bf..cdaeeee82 100644
--- a/loolwsd/test/httpwstest.cpp
+++ b/loolwsd/test/httpwstest.cpp
@@ -209,29 +209,39 @@ void HTTPWSTest::testHandShake()
         CPPUNIT_ASSERT(payload.compare(0, payload.size(), buffer, 0, bytes) == 0);
         CPPUNIT_ASSERT(flags == Poco::Net::WebSocket::FRAME_TEXT);
 
-        // After document broker finish searching it sends editlok
-        // it should be at end on handshake
         bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
-        CPPUNIT_ASSERT(prefixEdit.compare(0, prefixEdit.size(), buffer, 0, prefixEdit.size()) == 0);
-        CPPUNIT_ASSERT(flags == Poco::Net::WebSocket::FRAME_TEXT);
-
-        payload = "statusindicator: connect";
-        bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
-        CPPUNIT_ASSERT_EQUAL((int) payload.size(), bytes);
-        CPPUNIT_ASSERT(payload.compare(0, payload.size(), buffer, 0, bytes) == 0);
-        CPPUNIT_ASSERT(flags == Poco::Net::WebSocket::FRAME_TEXT);
-
-        bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
-        if (std::strstr(buffer, fail))
+        if (!std::strstr(buffer, fail))
         {
-            payload = "statusindicator: fail";
+            // After document broker finish searching it sends editlok
+            // it should be at end on handshake
+            CPPUNIT_ASSERT(prefixEdit.compare(0, prefixEdit.size(), buffer, 0, prefixEdit.size()) == 0);
+            CPPUNIT_ASSERT(flags == Poco::Net::WebSocket::FRAME_TEXT);
+
+            payload = "statusindicator: connect";
+            bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
             CPPUNIT_ASSERT_EQUAL((int) payload.size(), bytes);
             CPPUNIT_ASSERT(payload.compare(0, payload.size(), buffer, 0, bytes) == 0);
             CPPUNIT_ASSERT(flags == Poco::Net::WebSocket::FRAME_TEXT);
+
+            bytes = socket.receiveFrame(buffer, sizeof(buffer), flags);
+            if (!std::strstr(buffer, fail))
+            {
+                payload = "statusindicator: ready";
+                CPPUNIT_ASSERT_EQUAL((int) payload.size(), bytes);
+                CPPUNIT_ASSERT(payload.compare(0, payload.size(), buffer, 0, bytes) == 0);
+                CPPUNIT_ASSERT(flags == Poco::Net::WebSocket::FRAME_TEXT);
+            }
+            else
+            {
+                payload = "statusindicator: fail";
+                CPPUNIT_ASSERT_EQUAL((int) payload.size(), bytes);
+                CPPUNIT_ASSERT(payload.compare(0, payload.size(), buffer, 0, bytes) == 0);
+                CPPUNIT_ASSERT(flags == Poco::Net::WebSocket::FRAME_TEXT);
+            }
         }
         else
         {
-            payload = "statusindicator: ready";
+            payload = "statusindicator: fail";
             CPPUNIT_ASSERT_EQUAL((int) payload.size(), bytes);
             CPPUNIT_ASSERT(payload.compare(0, payload.size(), buffer, 0, bytes) == 0);
             CPPUNIT_ASSERT(flags == Poco::Net::WebSocket::FRAME_TEXT);
commit 4254ddad7752663915a58f5ec87213a027a6b69a
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 16 12:28:55 2016 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Sat Apr 16 17:29:35 2016 +0000

    loolwsd: consistently set HTTP status and reason everywhere
    
    Change-Id: Ie538e4907e3a3a514918000bb585d2aaf182e468
    Reviewed-on: https://gerrit.libreoffice.org/24132
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/Admin.cpp b/loolwsd/Admin.cpp
index e647ae74b..3ba553aee 100644
--- a/loolwsd/Admin.cpp
+++ b/loolwsd/Admin.cpp
@@ -310,7 +310,7 @@ void AdminRequestHandler::handleWSRequests(HTTPServerRequest& request, HTTPServe
     {
         Log::info("NotAuthenticatedException");
         response.set("WWW-Authenticate", "Basic realm=\"ws-online\"");
-        response.setStatus(HTTPResponse::HTTP_UNAUTHORIZED);
+        response.setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
         response.setContentLength(0);
         response.send();
     }
@@ -350,13 +350,13 @@ void AdminRequestHandler::handleRequest(HTTPServerRequest& request, HTTPServerRe
     {
         Log::info("Admin::NotAuthenticated");
         response.set("WWW-Authenticate", "Basic realm=\"online\"");
-        response.setStatus(HTTPResponse::HTTP_UNAUTHORIZED);
+        response.setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
         response.setContentLength(0);
         response.send();
     }
     catch (const std::exception& exc)
     {
-        Log::info("Unknown Exception caught");
+        Log::info(std::string("Admin::handleRequest: Exception: ") + exc.what());
         response.setStatusAndReason(HTTPResponse::HTTP_BAD_REQUEST);
         response.setContentLength(0);
         response.send();
diff --git a/loolwsd/Common.hpp b/loolwsd/Common.hpp
index 43a67e967..d287736cb 100644
--- a/loolwsd/Common.hpp
+++ b/loolwsd/Common.hpp
@@ -11,8 +11,6 @@
 #ifndef INCLUDED_COMMON_HPP
 #define INCLUDED_COMMON_HPP
 
-#include <string>
-
 // The maximum number of client connections we can accept.
 constexpr int MAX_SESSIONS = 1024;
 
diff --git a/loolwsd/FileServer.hpp b/loolwsd/FileServer.hpp
index 293e34e25..d869e1199 100644
--- a/loolwsd/FileServer.hpp
+++ b/loolwsd/FileServer.hpp
@@ -171,14 +171,14 @@ public:
         {
             Log::error("FileServerRequestHandler::NotAuthenticated: " + exc.displayText());
             response.set("WWW-Authenticate", "Basic realm=\"online\"");
-            response.setStatus(HTTPResponse::HTTP_UNAUTHORIZED);
+            response.setStatusAndReason(HTTPResponse::HTTP_UNAUTHORIZED);
             response.setContentLength(0);
             response.send();
         }
         catch (const Poco::FileNotFoundException& exc)
         {
             Log::error("FileServerRequestHandler: " + exc.displayText());
-            response.setStatus(HTTPResponse::HTTP_NOT_FOUND);
+            response.setStatusAndReason(HTTPResponse::HTTP_NOT_FOUND);
             response.setContentLength(0);
             response.send();
         }
commit fe952794f0a7f04d6ae7a788e1352da00fe1159a
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 16 12:26:26 2016 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Sat Apr 16 17:29:11 2016 +0000

    loolwsd: don't expose private members
    
    Change-Id: I049c92d0ddb296058fad283fffc291348b4608b1
    Reviewed-on: https://gerrit.libreoffice.org/24131
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/FileServer.hpp b/loolwsd/FileServer.hpp
index 6338989f2..293e34e25 100644
--- a/loolwsd/FileServer.hpp
+++ b/loolwsd/FileServer.hpp
@@ -54,6 +54,7 @@ using Poco::Util::Application;
 class FileServerRequestHandler: public HTTPRequestHandler
 {
 public:
+
     /// Evaluate if the cookie exists, and if not, ask for the credentials.
     static bool isAdminLoggedIn(HTTPServerRequest& request, HTTPServerResponse& response)
     {
@@ -108,35 +109,6 @@ public:
         return false;
     }
 
-    void preprocessFile(HTTPServerRequest& request, HTTPServerResponse& response)
-    {
-        HTMLForm form(request, request.stream());
-
-        std::string preprocess;
-        const auto host = (LOOLWSD::SSLEnabled? "wss://": "ws://") + request.getHost();
-
-        Poco::URI requestUri(request.getURI());
-        requestUri.normalize(); // avoid .'s and ..'s
-        const auto path = Poco::Path(LOOLWSD::FileServerRoot, requestUri.getPath());
-
-        Log::debug("Preprocessing file: " + path.toString());
-
-        FileInputStream file(path.toString());
-        StreamCopier::copyToString(file, preprocess);
-        file.close();
-
-        Poco::replaceInPlace(preprocess, std::string("%ACCESS_TOKEN%"), form.get("access_token", ""));
-        Poco::replaceInPlace(preprocess, std::string("%ACCESS_TOKEN_TTL%"), form.get("access_token_ttl", ""));
-        Poco::replaceInPlace(preprocess, std::string("%HOST%"), host);
-
-        response.setContentType("text/html");
-        response.setContentLength(preprocess.length());
-        response.setChunkedTransferEncoding(false);
-
-        std::ostream& ostr = response.send();
-        ostr << preprocess;
-    }
-
     void handleRequest(HTTPServerRequest& request, HTTPServerResponse& response) override
     {
         try
@@ -211,6 +183,37 @@ public:
             response.send();
         }
     }
+
+private:
+
+    void preprocessFile(HTTPServerRequest& request, HTTPServerResponse& response)
+    {
+        HTMLForm form(request, request.stream());
+
+        std::string preprocess;
+        const auto host = (LOOLWSD::SSLEnabled? "wss://": "ws://") + request.getHost();
+
+        Poco::URI requestUri(request.getURI());
+        requestUri.normalize(); // avoid .'s and ..'s
+        const auto path = Poco::Path(LOOLWSD::FileServerRoot, requestUri.getPath());
+
+        Log::debug("Preprocessing file: " + path.toString());
+
+        FileInputStream file(path.toString());
+        StreamCopier::copyToString(file, preprocess);
+        file.close();
+
+        Poco::replaceInPlace(preprocess, std::string("%ACCESS_TOKEN%"), form.get("access_token", ""));
+        Poco::replaceInPlace(preprocess, std::string("%ACCESS_TOKEN_TTL%"), form.get("access_token_ttl", ""));
+        Poco::replaceInPlace(preprocess, std::string("%HOST%"), host);
+
+        response.setContentType("text/html");
+        response.setContentLength(preprocess.length());
+        response.setChunkedTransferEncoding(false);
+
+        std::ostream& ostr = response.send();
+        ostr << preprocess;
+    }
 };
 
 class FileServer
commit 93d3f806e1bed9f5c43cf16f3c824a5fcb962f3d
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 16 08:10:52 2016 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Sat Apr 16 17:28:45 2016 +0000

    loolwsd: logging and cosmetics
    
    Change-Id: I413a2e40f480ba41e37c7442724c3f037528f89b
    Reviewed-on: https://gerrit.libreoffice.org/24130
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/Admin.cpp b/loolwsd/Admin.cpp
index d5d4557e9..e647ae74b 100644
--- a/loolwsd/Admin.cpp
+++ b/loolwsd/Admin.cpp
@@ -403,7 +403,7 @@ void MemoryStats::run()
     AdminModel& model = _admin->getModel();
     unsigned totalMem = _admin->getTotalMemoryUsage(model);
 
-    Log::info("Total memory used: " + std::to_string(totalMem));
+    Log::trace("Total memory used: " + std::to_string(totalMem));
     model.addMemStats(totalMem);
 }
 
diff --git a/loolwsd/FileServer.hpp b/loolwsd/FileServer.hpp
index a749f065d..6338989f2 100644
--- a/loolwsd/FileServer.hpp
+++ b/loolwsd/FileServer.hpp
@@ -148,7 +148,7 @@ public:
             requestUri.getPathSegments(requestSegments);
             if (requestSegments.size() < 1)
             {
-                throw Poco::FileNotFoundException("Invalid file.");
+                throw Poco::FileNotFoundException("Invalid URI request: [" + requestUri.toString() + "].");
             }
 
             const std::string endPoint = requestSegments[requestSegments.size() - 1];
@@ -173,7 +173,7 @@ public:
                 if (filepath.find(LOOLWSD::FileServerRoot) != 0)
                 {
                     // Accessing unauthorized path.
-                    throw Poco::FileNotFoundException("Invalid file path.");
+                    throw Poco::FileNotFoundException("Invalid or forbidden file path: [" + filepath + "].");
                 }
 
                 const std::size_t extPoint = endPoint.find_last_of(".");
@@ -195,17 +195,17 @@ public:
                 response.sendFile(filepath, mimeType);
             }
         }
-        catch (Poco::Net::NotAuthenticatedException& exc)
+        catch (const Poco::Net::NotAuthenticatedException& exc)
         {
-            Log::error("FileServerRequestHandler::NotAuthenticated");
+            Log::error("FileServerRequestHandler::NotAuthenticated: " + exc.displayText());
             response.set("WWW-Authenticate", "Basic realm=\"online\"");
             response.setStatus(HTTPResponse::HTTP_UNAUTHORIZED);
             response.setContentLength(0);
             response.send();
         }
-        catch (Poco::FileNotFoundException& exc)
+        catch (const Poco::FileNotFoundException& exc)
         {
-            Log::error("FileServerRequestHandler:: File [" + request.getURI() + "] not found.");
+            Log::error("FileServerRequestHandler: " + exc.displayText());
             response.setStatus(HTTPResponse::HTTP_NOT_FOUND);
             response.setContentLength(0);
             response.send();
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index db27edca1..a60d90d09 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -638,31 +638,31 @@ private:
 
     static void handleGetDiscovery(HTTPServerRequest& request, HTTPServerResponse& response)
     {
-        DOMParser parser;
-        DOMWriter writer;
-
         std::string discoveryPath = Path(Application::instance().commandPath()).parent().toString() + "discovery.xml";
         if (!File(discoveryPath).exists())
         {
             discoveryPath = LOOLWSD_DATADIR "/discovery.xml";
         }
+
         const std::string mediaType = "text/xml";
         const std::string action = "action";
         const std::string urlsrc = "urlsrc";
-        const std::string uriValue = (LOOLWSD::SSLEnabled? "https://": "http://") +
-            (LOOLWSD::ServerName.empty()? request.getHost(): LOOLWSD::ServerName) +
+        const std::string uriValue = (LOOLWSD::SSLEnabled ? "https://" : "http://") +
+            (LOOLWSD::ServerName.empty() ? request.getHost() : LOOLWSD::ServerName) +
             "/loleaflet/dist/loleaflet.html?";
 
         InputSource inputSrc(discoveryPath);
+        DOMParser parser;
         AutoPtr<Poco::XML::Document> docXML = parser.parse(&inputSrc);
         AutoPtr<NodeList> listNodes = docXML->getElementsByTagName(action);
 
-        for (unsigned long it = 0; it < listNodes->length(); it++)
+        for (unsigned long it = 0; it < listNodes->length(); ++it)
         {
             static_cast<Element*>(listNodes->item(it))->setAttribute(urlsrc, uriValue);
         }
 
         std::ostringstream ostrXML;
+        DOMWriter writer;
         writer.writeNode(ostrXML, docXML);
 
         response.set("User-Agent", "LOOLWSD WOPI Agent");
@@ -672,6 +672,7 @@ private:
 
         std::ostream& ostr = response.send();
         ostr << ostrXML.str();
+        Log::debug("Sent discovery.xml successfully.");
     }
 
 public:
@@ -707,7 +708,6 @@ public:
             }
             else
             {
-                //authenticate(request, response, id);
                 handleGetRequest(request, response, id);
             }
         }
diff --git a/loolwsd/LOOLWSD.hpp b/loolwsd/LOOLWSD.hpp
index 556283774..1fcdac6d6 100644
--- a/loolwsd/LOOLWSD.hpp
+++ b/loolwsd/LOOLWSD.hpp
@@ -25,8 +25,6 @@
 #include "DocumentBroker.hpp"
 #include "Util.hpp"
 
-class MasterProcessSession;
-
 class LOOLWSD: public Poco::Util::ServerApplication
 {
 public:
commit c2560725db90e8d5779cfe8fd9e774691c92ad6d
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 16 08:02:15 2016 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Sat Apr 16 17:27:43 2016 +0000

    loolwsd: admin uses config for ssl key
    
    Change-Id: I38b0f59c158698a6eb89d4b671001e1d8cb61673
    Reviewed-on: https://gerrit.libreoffice.org/24129
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/Common.hpp b/loolwsd/Common.hpp
index 2d9db6841..43a67e967 100644
--- a/loolwsd/Common.hpp
+++ b/loolwsd/Common.hpp
@@ -38,7 +38,6 @@ constexpr auto FIFO_LOOLWSD = "loolwsdfifo";
 constexpr auto FIFO_PATH = "pipe";
 constexpr auto JAILED_DOCUMENT_ROOT = "/user/docs/";
 constexpr auto NEW_CHILD_URI = "/loolws/newchild?";
-constexpr auto SSL_KEY_FILE = "key.pem";
 
 // The client port number, both loolwsd and the kits have this.
 extern int ClientPortNumber;
diff --git a/loolwsd/FileServer.hpp b/loolwsd/FileServer.hpp
index 2941c35ec..a749f065d 100644
--- a/loolwsd/FileServer.hpp
+++ b/loolwsd/FileServer.hpp
@@ -57,6 +57,9 @@ public:
     /// Evaluate if the cookie exists, and if not, ask for the credentials.
     static bool isAdminLoggedIn(HTTPServerRequest& request, HTTPServerResponse& response)
     {
+        const auto& config = Application::instance().config();
+        const auto sslKeyPath = config.getString("ssl.key_file_path", "");
+
         if (request.find("Cookie") != request.end())
         {
             // FIXME: Handle other cookie params like '; httponly; secure'
@@ -66,9 +69,7 @@ public:
 
             const std::string jwtToken = request["Cookie"].substr(pos + 1);
             Log::info("Verifying JWT token: " + jwtToken);
-            // TODO: Read key from configuration file
-            const std::string keyPath = "/etc/loolwsd/" + std::string(SSL_KEY_FILE);
-            JWTAuth authAgent(keyPath, "admin", "admin", "admin");
+            JWTAuth authAgent(sslKeyPath, "admin", "admin", "admin");
             if (authAgent.verify(jwtToken))
             {
                 Log::trace("JWT token is valid");
@@ -78,8 +79,8 @@ public:
             Log::info("Invalid JWT token, let the administrator re-login");
         }
 
-        const auto user = Application::instance().config().getString("admin_console_username", "");
-        const auto pass = Application::instance().config().getString("admin_console_password", "");
+        const auto user = config.getString("admin_console_username", "");
+        const auto pass = config.getString("admin_console_password", "");
         if (user.empty() || pass.empty())
         {
             Log::error("Admin Console credentials missing. Denying access until set.");
@@ -92,9 +93,7 @@ public:
         {
             const std::string htmlMimeType = "text/html";
             // generate and set the cookie
-            // TODO: Read key from configuration file
-            const std::string keyPath = "/etc/loolwsd/" + std::string(SSL_KEY_FILE);
-            JWTAuth authAgent(keyPath, "admin", "admin", "admin");
+            JWTAuth authAgent(sslKeyPath, "admin", "admin", "admin");
             const std::string jwtToken = authAgent.getAccessToken();
             Poco::Net::HTTPCookie cookie("jwt", jwtToken);
             cookie.setPath("/adminws/");
commit 8eedd9dfd3ce9e3f46c643898b42dbe4f7721d2d
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Sat Apr 16 08:19:39 2016 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Sat Apr 16 17:24:50 2016 +0000

    loleaflet: gitignore branding files
    
    Change-Id: I78df82004999938e2c9b7aa9935896fd8c195318
    Reviewed-on: https://gerrit.libreoffice.org/24128
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loleaflet/.gitignore b/loleaflet/.gitignore
index 4335c9904..5b195c2aa 100644
--- a/loleaflet/.gitignore
+++ b/loleaflet/.gitignore
@@ -10,6 +10,9 @@ component.json
 
 _site
 dist/*.js
+dist/branding.css
+dist/branding.js
+dist/images/toolbar-bg.png
 dist/admin/*.js
 dist/plugins/
 plugins/draw-0.2.4/dist/*.js
commit 69816395d5a455efb7d884554788e559d8a7d5e3
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Apr 15 22:04:15 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Apr 15 22:04:15 2016 +0100

    Re-enable verbose tracing during unit testing.

diff --git a/loolwsd/test/run_unit.sh.in b/loolwsd/test/run_unit.sh.in
index 7a929e776..a53daec5a 100755
--- a/loolwsd/test/run_unit.sh.in
+++ b/loolwsd/test/run_unit.sh.in
@@ -28,7 +28,7 @@ else
     test_mode=old
 fi
 
-# export LOOL_LOGLEVEL=trace
+export LOOL_LOGLEVEL=trace
 
 if test "z$enable_debug" != "ztrue"; then
     echo ""
commit 448e25f6d81f2c143878a3e6eb269d44049af389
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Apr 15 20:46:44 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Apr 15 21:53:10 2016 +0100

    Make logging signal safe again. snprintf: simpler, safer, faster.

diff --git a/loolwsd/Log.cpp b/loolwsd/Log.cpp
index 48fe800a6..fb85a4846 100644
--- a/loolwsd/Log.cpp
+++ b/loolwsd/Log.cpp
@@ -41,7 +41,27 @@ namespace Log
     };
     static StaticNames Source;
 
-    std::string prefix()
+    // We need a signal safe means of writing messages
+    //   $ man 7 signal
+    void signalLog(const char *message)
+    {
+        while (true) {
+            int length = strlen(message);
+            int written = write (STDERR_FILENO, message, length);
+            if (written < 0)
+            {
+                if (errno == EINTR)
+                    continue; // ignore.
+                else
+                    break;
+            }
+            message += written;
+            if (message[0] == '\0')
+                break;
+        }
+    }
+
+    static void getPrefix(char *buffer)
     {
         Poco::Int64 usec = Poco::Timestamp().epochMicroseconds() - epochStart;
 
@@ -53,19 +73,31 @@ namespace Log
         const Poco::Int64 seconds = usec / (one_s);
         usec %= (one_s);
 
-        std::ostringstream stream;
-        stream << (Source.inited ? Source.id : std::string())
-               << '-' << std::setw(2) << std::setfill('0')
-               << (Poco::Thread::current() ? Poco::Thread::current()->id() : 0) << ' '
-               << std::setw(2) << hours << ':' << std::setw(2) << minutes << ':'
-               << std::setw(2) << seconds << "." << std::setw(6) << usec
-               << ' ';
+        char procName[32]; // we really need only 16
+        if (!prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(procName), 0, 0, 0) == 0)
+            strcpy(procName, "<noid>");
+
+        const char *appName = (Source.inited ? Source.id.c_str() : "<shutdown>");
+        assert(strlen(appName) + 32 + 28 < 1024 - 1);
 
-        char buf[32]; // we really need only 16
-        if (prctl(PR_GET_NAME, reinterpret_cast<unsigned long>(buf), 0, 0, 0) == 0)
-            stream << '[' << std::setw(15) << std::setfill(' ') << std::left << buf << "] ";
+        snprintf(buffer, 4095, "%s-%.2d %.2d:%.2d:%.2d.%.6d [ %s ] ", appName,
+                 (Poco::Thread::current() ? Poco::Thread::current()->id() : 0),
+                 (int)hours, (int)minutes, (int)seconds, (int)usec,
+                 procName);
+    }
+
+    std::string prefix()
+    {
+        char buffer[1024];
+        getPrefix(buffer);
+        return std::string(buffer);
+    }
 
-        return stream.str();
+    void signalLogPrefix()
+    {
+        char buffer[1024];
+        getPrefix(buffer);
+        signalLog(buffer);
     }
 
     void initialize(const std::string& name)
diff --git a/loolwsd/Log.hpp b/loolwsd/Log.hpp
index b64f7662d..cc43baa01 100644
--- a/loolwsd/Log.hpp
+++ b/loolwsd/Log.hpp
@@ -29,6 +29,11 @@ namespace Log
     void error(const std::string& msg);
     void syserror(const std::string& msg);
 
+    /// Signal safe prefix logging
+    void signalLogPrefix();
+    /// Signal safe logging
+    void signalLog(const char *message);
+
     /// The following is to write streaming logs.
     /// Log::info() << "Value: 0x" << std::hex << value
     ///             << ", pointer: " << this << Log::end;
diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp
index 895217984..d30b31a36 100644
--- a/loolwsd/Util.cpp
+++ b/loolwsd/Util.cpp
@@ -253,27 +253,6 @@ namespace Util
         }
     }
 
-    // We need a signal safe means of writing messages
-    //   $ man 7 signal
-    static
-    void log_signal(const char *message)
-    {
-        while (true) {
-            int length = strlen(message);
-            int written = write (STDERR_FILENO, message, length);
-            if (written < 0)
-            {
-                if (errno == EINTR)
-                    continue; // ignore.
-                else
-                    break;
-            }
-            message += written;
-            if (message[0] == '\0')
-                break;
-        }
-    }
-
     static
     void handleTerminationSignal(const int signal)
     {
@@ -281,10 +260,10 @@ namespace Util
         {
             TerminationFlag = true;
 
-            log_signal(Log::prefix().c_str());
-            log_signal(" Termination signal received: ");
-            log_signal(signalName(signal));
-            log_signal("\n");
+            Log::signalLogPrefix();
+            Log::signalLog(" Termination signal received: ");
+            Log::signalLog(signalName(signal));
+            Log::signalLog("\n");
         }
     }
 
@@ -307,14 +286,14 @@ namespace Util
     static
     void handleFatalSignal(const int signal)
     {
-        log_signal(Log::prefix().c_str());
-        log_signal(" Fatal signal received: ");
-        log_signal(signalName(signal));
-        log_signal("\n");
+        Log::signalLogPrefix();
+        Log::signalLog(" Fatal signal received: ");
+        Log::signalLog(signalName(signal));
+        Log::signalLog("\n");
 
         if (std::getenv("LOOL_DEBUG"))
         {
-            log_signal(FatalGdbString);
+            Log::signalLog(FatalGdbString);
             sleep(30);
         }
 
commit 65ee749ce1c90612d04d4aea44318cb53e713031
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Apr 15 16:39:05 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Apr 15 21:52:39 2016 +0100

    Move new unit tests to custom test driver.
    
    Cleaner, and avoids bogus warnings during compile.
    Merge run_test.sh.in into a mode of run_unit.sh - gives the
    chance for nice debug output etc.

diff --git a/loolwsd/configure.ac b/loolwsd/configure.ac
index 48b253919..008308101 100644
--- a/loolwsd/configure.ac
+++ b/loolwsd/configure.ac
@@ -249,7 +249,6 @@ AC_CONFIG_FILES([Makefile
                  loolwsd.spec
                  loolwsd.xml])
 AC_CONFIG_FILES([test/run_unit.sh],[chmod +x test/run_unit.sh])
-AC_CONFIG_FILES([test/run_test.sh],[chmod +x test/run_test.sh])
 
 AC_OUTPUT
 
diff --git a/loolwsd/test/Makefile.am b/loolwsd/test/Makefile.am
index d44e78790..721ec0c04 100644
--- a/loolwsd/test/Makefile.am
+++ b/loolwsd/test/Makefile.am
@@ -28,19 +28,14 @@ else
 SYSTEM_STAMP =
 endif
 
-${top_builddir}/test/run_unit.sh.log ${top_builddir}/test/run_unit.sh.trs : \
-	$(SYSTEM_STAMP) @JAILS_PATH@ \
-	${top_srcdir}/test/run_unit.sh \
-	${top_builddir}/loolwsd ${top_builddir}/loolforkit \
-	$(wildcard *.la)
-	if ${top_srcdir}/test/run_unit.sh; then \
-	   touch ${top_builddir}/test/run_unit.sh.log; \
-	fi
-
 if HAVE_LO_PATH
-TESTS = ${top_srcdir}/test/run_unit.sh ${top_srcdir}/test/run_test.sh
+TESTS = unit-timeout.la unit-fonts.la unit-storage.la unit-prefork.la run_test.sh
 else
 TESTS = ${top_builddir}/test/test
 endif
 
+TEST_EXTENSIONS = .la .sh
+LA_LOG_DRIVER = ${top_srcdir}/test/run_unit.sh
+SH_LOG_DRIVER = ${top_srcdir}/test/run_unit.sh
+
 EXTRA_DIST = data/hello.odt data/hello.txt $(test_SOURCES) run_unit.sh
diff --git a/loolwsd/test/run_test.sh.in b/loolwsd/test/run_test.sh.in
deleted file mode 100755
index f7895c73f..000000000
--- a/loolwsd/test/run_test.sh.in
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/bin/sh
-#
-# DO NOT EDIT - this file is generated from run_test.sh.in.
-#
-
-abs_top_builddir="@abs_top_builddir@"
-test_build="${abs_top_builddir}/test"
-test_output="$test_build/run_test.sh.trs"
-test_log_output="$test_build/test_output"
-
-mkdir -p $test_log_output
-
-if test "z at ENABLE_DEBUG@" != "ztrue"; then
-    echo ""
-    echo "It is necessary to configure with --enable-debug for unit tests to pass"
-    echo ""
-    echo ":test-result: FAIL $tst" > $test_output
-    exit 1;
-fi
-
-echo "Running cppunit test ...";
-
-# result logging
-echo > $test_output
-
-${abs_top_builddir}/loolwsd --systemplate="@SYSTEMPLATE_PATH@" --lotemplate="@LO_PATH@" \
-           --childroot="@JAILS_PATH@" --allowlocalstorage 2>$test_log_output/run_test.log &
-
-echo "  waiting for loolwsd to start"
-sleep 1 # sad - need to add a wait to the start of test.cpp ...
-
-echo "  executing test"
-
-cd $test_build
-if ./test; then
-	echo "Test run_test.sh passed."
-	echo ":test-result: PASS run_test.sh" >> $test_output
-	retval=0
-else
-	cat $test_log_output/run_test.log
-        echo "============================================================="
-	echo "Test failed on unit:"
-        echo "============================================================="
-	echo ":test-result: FAIL run_test.sh" >> $test_output
-	retval=1
-fi
-
-kill $!
-
-exit $retval
diff --git a/loolwsd/test/run_unit.sh.in b/loolwsd/test/run_unit.sh.in
index 5491640b8..7a929e776 100755
--- a/loolwsd/test/run_unit.sh.in
+++ b/loolwsd/test/run_unit.sh.in
@@ -3,16 +3,34 @@
 # DO NOT EDIT - this file is generated from run_unit.sh.in.
 #
 
-export LOOL_LOGLEVEL=trace
+# substituted variables in one place:
+abs_top_builddir="/opt/libreoffice/online/loolwsd"
+systemplate_path="@SYSTEMPLATE_PATH@"
+enable_debug="@ENABLE_DEBUG@"
+jails_path="@JAILS_PATH@"
+lo_path="@LO_PATH@"
 
-abs_top_builddir="@abs_top_builddir@"
-test_build="${abs_top_builddir}/test"
-test_output="$test_build/run_unit.sh.trs"
-test_log_output="$test_build/test_output"
+while test $# -gt 0; do
+  case $1 in
+      --test-name) tst=$2; shift;;
+      --log-file)  tst_log=$2; shift;;
+      --trs-file)  test_output=$2; shift;;
+  -*) ;; # ignore
+  esac
+  shift
+done
+
+test_mode=
+if test "z$tst" != "zrun_test.sh"; then
+    # drop .la suffix
+    tst=`echo $tst | sed s/\.la//`;
+else
+    test_mode=old
+fi
 
-mkdir -p $test_log_output
+# export LOOL_LOGLEVEL=trace
 
-if test "z at ENABLE_DEBUG@" != "ztrue"; then
+if test "z$enable_debug" != "ztrue"; then
     echo ""
     echo "It is necessary to configure with --enable-debug for unit tests to pass"
     echo ""
@@ -21,25 +39,52 @@ if test "z at ENABLE_DEBUG@" != "ztrue"; then
 fi
 
 # result logging
-echo > run_unit.sh.trs
-
-for tst in fonts timeout storage prefork; do
-    tst_log="test_output/$tst.log"
-    echo "Running test: $tst | $tst_log ...";
-    if ${abs_top_builddir}/loolwsd --systemplate="@SYSTEMPLATE_PATH@" \
-                                   --lotemplate="@LO_PATH@" \
-                                   --childroot="@JAILS_PATH@" \
-                                   --unitlib=".libs/unit-$tst.so" 2> "$tst_log"; then
-	echo "Test $tst passed."
-	echo ":test-result: PASS $tst" >> $test_output
+echo > $test_output
+
+if test "z$test_mode" == "zold"; then
+     echo "executing external tests"
+     ${abs_top_builddir}/loolwsd --systemplate="$systemplate_path" \
+                                 --lotemplate="$lo_path" \
+                                 --childroot="$jails_path" \
+                                 --allowlocalstorage  2> "$tst_log" &
+
+     echo "  waiting for loolwsd to start"
+     sleep 1 # sad - need to add a wait to the start of test.cpp ...
+     echo "  executing test"
+
+     oldpath=`pwd`
+     cd "${abs_top_builddir}/test"
+     if ./test; then
+	 echo "Test run_test.sh passed."
+	 echo ":test-result: PASS run_test.sh" >> $oldpath/$test_output
+	 retval=0
+     else
+         echo "============================================================="
+	 echo "Test failed on unit:"
+         echo "============================================================="
+	 echo ":test-result: FAIL run_test.sh" >> $oldpath/$test_output
+	 retval=1
+     fi
+
+     kill $!
+
+     exit $retval
+
+else # newer unit tests.
+    echo "Running $tst | $tst_log ...";
+    if ${abs_top_builddir}/loolwsd --systemplate="$systemplate_path" \
+                                   --lotemplate="$lo_path" \
+                                   --childroot="$jails_path" \
+                                   --unitlib=".libs/$tst.so" 2> "$tst_log"; then
+        echo "Test $tst passed."
+        echo ":test-result: PASS $tst" >> $test_output
     else
-	cat "$tst_log"
-        echo "============================================================="
-	echo "Test failed on unit: $tst re-run with:"
-	echo "   $ gdb --args ../loolwsd --systemplate=\"@SYSTEMPLATE_PATH@\" --lotemplate=\"@LO_PATH@\" \\"
-	echo "         --childroot=\"@JAILS_PATH@\" --unitlib=\".libs/unit-$tst.so\""
+        cat "$tst_log"
         echo "============================================================="
+        echo "Test failed on unit: $tst re-run with:"
+	echo "   $ gdb --args ../loolwsd --systemplate=\"$systemplate_path\" --lotemplate=\"$lo_path\" \\"
+	echo "         --childroot=\"$jails_path\" --unitlib=\".libs/$tst.so\""
+	echo "============================================================="
 	echo ":test-result: FAIL $tst" >> $test_output
     fi
-done
-
+fi
commit ebfa339da02337274d332763b0e1ace952550f2a
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Apr 15 16:16:36 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Apr 15 16:17:04 2016 +0100

    Cleanup symlinking and add realpath symlink if necessary.

diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp
index 18b0da2e9..7f55ec966 100644
--- a/loolwsd/LOOLKit.cpp
+++ b/loolwsd/LOOLKit.cpp
@@ -16,6 +16,9 @@
 #include <sys/capability.h>
 #include <unistd.h>
 #include <utime.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <malloc.h>
 
 #include <atomic>
 #include <cassert>
@@ -820,6 +823,27 @@ private:
     std::atomic_size_t _clientViews;
 };
 
+namespace {
+    void symlinkPathToJail(const Path jailPath, const std::string &loTemplate,
+                           const std::string &loSubPath)
+    {
+        Path symlinkSource(jailPath, Path(loTemplate.substr(1)));
+        File(symlinkSource.parent()).createDirectories();
+
+        std::string symlinkTarget;
+        for (auto i = 0; i < Path(loTemplate).depth(); i++)
+            symlinkTarget += "../";
+        symlinkTarget += loSubPath;
+
+        Log::debug("symlink(\"" + symlinkTarget + "\",\"" + symlinkSource.toString() + "\")");
+        if (symlink(symlinkTarget.c_str(), symlinkSource.toString().c_str()) == -1)
+        {
+            Log::syserror("symlink(\"" + symlinkTarget + "\",\"" + symlinkSource.toString() + "\") failed");
+            throw Exception("symlink() failed");
+        }
+    }
+}
+
 void lokit_main(const std::string& childRoot,
                 const std::string& sysTemplate,
                 const std::string& loTemplate,
@@ -861,19 +885,15 @@ void lokit_main(const std::string& childRoot,
 
         // Create a symlink inside the jailPath so that the absolute pathname loTemplate, when
         // interpreted inside a chroot at jailPath, points to loSubPath (relative to the chroot).
-        Path symlinkSource(jailPath, Path(loTemplate.substr(1)));
-        File(symlinkSource.parent()).createDirectories();
-
-        std::string symlinkTarget;
-        for (auto i = 0; i < Path(loTemplate).depth(); i++)
-            symlinkTarget += "../";
-        symlinkTarget += loSubPath;
+        symlinkPathToJail(jailPath, loTemplate, loSubPath);
 
-        Log::debug("symlink(\"" + symlinkTarget + "\",\"" + symlinkSource.toString() + "\")");
-        if (symlink(symlinkTarget.c_str(), symlinkSource.toString().c_str()) == -1)
+        // Font paths can end up as realpaths so match that too.
+        char *resolved = realpath(loTemplate.c_str(), NULL);
+        if (resolved)
         {
-            Log::syserror("symlink(\"" + symlinkTarget + "\",\"" + symlinkSource.toString() + "\") failed");
-            throw Exception("symlink() failed");
+            if (strcmp(loTemplate.c_str(), resolved))
+                symlinkPathToJail(jailPath, std::string(resolved), loSubPath);
+            free (resolved);
         }
 
         Path jailLOInstallation(jailPath, loSubPath);
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 31ed0d2ce..db27edca1 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -479,6 +479,7 @@ private:
                 response.setStatus(HTTPResponse::HTTP_NOT_FOUND);
                 response.setContentLength(0);
                 response.send();
+                Log::info("file not found.");
             }
         }
         else
diff --git a/loolwsd/loolwsd-systemplate-setup b/loolwsd/loolwsd-systemplate-setup
index d6539e33d..27c760c9c 100755
--- a/loolwsd/loolwsd-systemplate-setup
+++ b/loolwsd/loolwsd-systemplate-setup
@@ -87,14 +87,6 @@ if [ -h usr/share/fonts/ghostscript ]; then
     cp -r -p /usr/share/ghostscript/fonts usr/share/ghostscript
 fi
 
-# Our Libreoffice install often comes with pre-bundled fonts.
-# we need to ensure that there is a link to these with the same
-# path that fontconfig found.
-mkdir -p ./lo
-mkdir -p ./$INSTDIR
-rmdir ./$INSTDIR
-ln -s /lo $CHROOT/$INSTDIR
-
 # Debugging only hackery to avoid confusion.
 if test "z$ENABLE_DEBUG" != "z" -a "z$HOME" != "z"; then
     echo "Copying development users's fonts into systemplate"
commit b1aa059bc35bc6b770bb171fe83416ad415c0893
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Fri Apr 15 17:19:04 2016 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Fri Apr 15 17:19:04 2016 +0300

    I don't have any ~/.fonts

diff --git a/loolwsd/loolwsd-systemplate-setup b/loolwsd/loolwsd-systemplate-setup
index 54a2df02d..d6539e33d 100755
--- a/loolwsd/loolwsd-systemplate-setup
+++ b/loolwsd/loolwsd-systemplate-setup
@@ -99,5 +99,7 @@ ln -s /lo $CHROOT/$INSTDIR
 if test "z$ENABLE_DEBUG" != "z" -a "z$HOME" != "z"; then
     echo "Copying development users's fonts into systemplate"
     mkdir -p $CHROOT/$HOME
-    cp -r -p -L $HOME/.fonts $CHROOT/$HOME
+    test -d $HOME/.fonts && cp -r -p -L $HOME/.fonts $CHROOT/$HOME
 fi
+
+exit 0
commit 947f8bcf138b3eaa01daa2787069528c03defe44
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Fri Apr 15 17:01:02 2016 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Fri Apr 15 17:13:47 2016 +0300

    Test number of loolkit processes also before and after the HTTPPostTest suite

diff --git a/loolwsd/test/countloolkits.hpp b/loolwsd/test/countloolkits.hpp
new file mode 100644
index 000000000..1fb1ba5f6
--- /dev/null
+++ b/loolwsd/test/countloolkits.hpp
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef INCLUDED_COUNTLOOLKITPROCESSES_HPP
+#define INCLUDED_COUNTLOOLKITPROCESSES_HPP
+
+extern int countLoolKitProcesses();
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/test/httpposttest.cpp b/loolwsd/test/httpposttest.cpp
index 525583058..f7eec5554 100644
--- a/loolwsd/test/httpposttest.cpp
+++ b/loolwsd/test/httpposttest.cpp
@@ -26,14 +26,28 @@
 #include <Common.hpp>
 #include <Util.hpp>
 
+#include "countloolkits.hpp"
+
 /// Tests the HTTP POST API of loolwsd. The server has to be started manually before running this test.
 class HTTPPostTest : public CPPUNIT_NS::TestFixture
 {
+    static int _initialLoolKitCount;
+
     CPPUNIT_TEST_SUITE(HTTPPostTest);
+
+    // This should be the first test:
+    CPPUNIT_TEST(testCountHowManyLoolkits);
+
     CPPUNIT_TEST(testConvertTo);
+
+    // This should be the last test:
+    CPPUNIT_TEST(testNoExtraLoolKitsLeft);
+
     CPPUNIT_TEST_SUITE_END();
 
+    void testCountHowManyLoolkits();
     void testConvertTo();
+    void testNoExtraLoolKitsLeft();
 
 #if ENABLE_SSL
 public:
@@ -54,6 +68,14 @@ public:
 #endif
 };
 
+int HTTPPostTest::_initialLoolKitCount = 0;
+
+void HTTPPostTest::testCountHowManyLoolkits()
+{
+    _initialLoolKitCount = countLoolKitProcesses();
+    CPPUNIT_ASSERT(_initialLoolKitCount > 0);
+}
+
 void HTTPPostTest::testConvertTo()
 {
     const auto srcPath = Util::getTempFilePath(TDOC, "hello.odt");
@@ -96,6 +118,13 @@ void HTTPPostTest::testConvertTo()
     CPPUNIT_ASSERT_EQUAL(expectedStream.str(), actualString);
 }
 
+void HTTPPostTest::testNoExtraLoolKitsLeft()
+{
+    int countNow = countLoolKitProcesses();
+
+    CPPUNIT_ASSERT_EQUAL(_initialLoolKitCount, countNow);
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(HTTPPostTest);
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/test/httpwstest.cpp b/loolwsd/test/httpwstest.cpp
index 2d8ef109a..91dfb79bf 100644
--- a/loolwsd/test/httpwstest.cpp
+++ b/loolwsd/test/httpwstest.cpp
@@ -36,6 +36,8 @@
 #include <Util.hpp>
 #include <LOOLProtocol.hpp>
 
+#include "countloolkits.hpp"
+
 /// Tests the HTTP WebSocket API of loolwsd. The server has to be started manually before running this test.
 class HTTPWSTest : public CPPUNIT_NS::TestFixture
 {
@@ -103,9 +105,6 @@ class HTTPWSTest : public CPPUNIT_NS::TestFixture
     connectLOKit(Poco::Net::HTTPRequest& request,
                  Poco::Net::HTTPResponse& response);
 
-    static
-    int countLoolKitProcesses();
-
 public:
     HTTPWSTest()
 #if ENABLE_SSL
@@ -942,10 +941,10 @@ void HTTPWSTest::getResponseMessage(Poco::Net::WebSocket& ws, const std::string&
     }
 }
 
-int HTTPWSTest::countLoolKitProcesses()
+int countLoolKitProcesses()
 {
-    // Give polls in the lool processes time to time out
-    Poco::Thread::sleep(POLL_TIMEOUT_MS*3);
+    // Give polls in the lool processes time to time out etc
+    Poco::Thread::sleep(POLL_TIMEOUT_MS*5);
 
     int result = 0;
 
commit a49f642801ba54ba3dc0692439bdbb9c8cac985a
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Apr 15 15:07:24 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Apr 15 15:07:24 2016 +0100

    Tolerate --version, and add git hash version, print on default start.
    
    Should help diagnosing issues - to have this in our logs.

diff --git a/loolwsd/LOOLForKit.cpp b/loolwsd/LOOLForKit.cpp
index 256a2c3d1..ffebf5652 100644
--- a/loolwsd/LOOLForKit.cpp
+++ b/loolwsd/LOOLForKit.cpp
@@ -202,6 +202,10 @@ int main(int argc, char** argv)
             eq = std::strchr(cmd, '=');
             ClientPortNumber = std::stoll(std::string(eq+1));
         }
+        else if (std::strstr(cmd, "--version") == cmd)
+        {
+            Util::displayVersionInfo("loolforkit");
+        }
 #if ENABLE_DEBUG
         // this process has various privileges - don't run arbitrary code.
         else if (std::strstr(cmd, "--unitlib=") == cmd)
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 9d14ca921..31ed0d2ce 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -146,6 +146,7 @@ int ClientPortNumber = DEFAULT_CLIENT_PORT_NUMBER;
 
 /// New LOK child processes ready to host documents.
 //TODO: Move to a more sensible namespace.
+static bool DisplayVersion = false;
 static std::vector<std::shared_ptr<ChildProcess>> newChildren;
 static std::mutex newChildrenMutex;
 static std::condition_variable newChildrenCV;
@@ -1233,10 +1234,7 @@ void LOOLWSD::handleOption(const std::string& optionName,
         std::exit(Application::EXIT_OK);
     }
     else if (optionName == "version")
-    {
-        displayVersion();
-        std::exit(Application::EXIT_OK);
-    }
+        DisplayVersion = true;
     else if (optionName == "port")
         ClientPortNumber = std::stoi(value);
     else if (optionName == "cache")
@@ -1274,11 +1272,6 @@ void LOOLWSD::displayHelp()
     helpFormatter.format(std::cout);
 }
 
-void LOOLWSD::displayVersion()
-{
-    std::cout << LOOLWSD_VERSION << std::endl;
-}
-
 Process::PID LOOLWSD::createForKit()
 {
     Process::Args args;
@@ -1290,6 +1283,8 @@ Process::PID LOOLWSD::createForKit()
     args.push_back("--clientport=" + std::to_string(ClientPortNumber));
     if (UnitWSD::get().hasKitHooks())
         args.push_back("--unitlib=" + UnitTestLibrary);
+    if (DisplayVersion)
+        args.push_back("--version");
 
     const std::string forKitPath = Path(Application::instance().commandPath()).parent().toString() + "loolforkit";
 
@@ -1305,6 +1300,9 @@ int LOOLWSD::main(const std::vector<std::string>& /*args*/)
 {
     Log::initialize("wsd");
 
+    if (DisplayVersion)
+        Util::displayVersionInfo("loolwsd");
+
     if (geteuid() == 0)
     {
         Log::error("Don't run this as root");
diff --git a/loolwsd/LOOLWSD.hpp b/loolwsd/LOOLWSD.hpp
index ae290e490..556283774 100644
--- a/loolwsd/LOOLWSD.hpp
+++ b/loolwsd/LOOLWSD.hpp
@@ -65,7 +65,6 @@ protected:
 private:
     void initializeSSL();
     void displayHelp();
-    void displayVersion();
     Poco::Process::PID createForKit();
 
     /// Reads and processes path entries with the given property
diff --git a/loolwsd/Util.cpp b/loolwsd/Util.cpp
index 32b90720c..895217984 100644
--- a/loolwsd/Util.cpp
+++ b/loolwsd/Util.cpp
@@ -7,6 +7,8 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
 
+#include "config.h"
+
 #include <execinfo.h>
 #include <sys/poll.h>
 #include <sys/prctl.h>
@@ -15,6 +17,7 @@
 #include <cassert>
 #include <cstdlib>
 #include <cstring>
+#include <iostream>
 #include <iomanip>
 #include <mutex>
 #include <random>
@@ -448,6 +451,13 @@ namespace Util
         if (prctl(PR_SET_NAME, reinterpret_cast<unsigned long>(s.c_str()), 0, 0, 0) != 0)
             Log::syserror("Cannot set thread name to " + s + ".");
     }
+
+    void displayVersionInfo(const char *app)
+    {
+        std::string hash(LOOLWSD_VERSION_HASH);
+        hash.resize(std::min(8, (int)hash.length()));
+        std::cout << app << " " << LOOLWSD_VERSION << " - " << hash << std::endl;
+    }
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/loolwsd/Util.hpp b/loolwsd/Util.hpp
index 46b973be2..223d0fb4a 100644
--- a/loolwsd/Util.hpp
+++ b/loolwsd/Util.hpp
@@ -114,6 +114,9 @@ namespace Util
 
     /// Ensure that we have the correct UID unless in debug mode.
     bool hasCorrectUID();
+
+    /// Display version information
+    void displayVersionInfo(const char *app);
 };
 
 #endif
diff --git a/loolwsd/configure.ac b/loolwsd/configure.ac
index 90a1a46fd..48b253919 100644
--- a/loolwsd/configure.ac
+++ b/loolwsd/configure.ac
@@ -22,6 +22,15 @@ AC_SUBST([LOOLWSD_VERSION])
 
 AC_DEFINE_UNQUOTED([LOOLWSD_VERSION],[["$LOOLWSD_VERSION"]],[LibreOffice On-Line WebSocket server version])
 
+# try to add a git hash for a version if we're developing
+LOOLWSD_VERSION_HASH=package
+git_hash=`cd ${ac_srcdir} && git log -1 --format=%H 2> /dev/null`
+if test "z$git_hash" != "z"; then
+   LOOLWSD_VERSION_HASH=$git_hash
+fi
+
+AC_DEFINE_UNQUOTED([LOOLWSD_VERSION_HASH],[["$LOOLWSD_VERSION_HASH"]],[LibreOffice On-Line git hash if present])
+
 AC_CONFIG_SRCDIR([LOOLWSD.cpp])
 
 AC_CONFIG_HEADERS([config.h])
@@ -260,3 +269,4 @@ echo "    \$ make run # to start loolwsd
 fi
 
 dnl vim:set shiftwidth=4 softtabstop=4 expandtab:
+
diff --git a/loolwsd/loolwsd.service b/loolwsd/loolwsd.service
index fdc32c5ec..13107c128 100644
--- a/loolwsd/loolwsd.service
+++ b/loolwsd/loolwsd.service
@@ -4,7 +4,7 @@ After=network.target
 
 [Service]
 EnvironmentFile=-/etc/sysconfig/loolwsd
-ExecStart=/usr/bin/loolwsd --systemplate=/opt/lool/systemplate --lotemplate=/opt/collaboraoffice5.0 --childroot=/opt/lool/child-roots --numprespawns=5 --fileserverroot=/usr/share/loolwsd
+ExecStart=/usr/bin/loolwsd --version --systemplate=/opt/lool/systemplate --lotemplate=/opt/collaboraoffice5.0 --childroot=/opt/lool/child-roots --numprespawns=5 --fileserverroot=/usr/share/loolwsd
 User=lool
 KillMode=control-group
 Restart=always
diff --git a/loolwsd/test/run_test.sh.in b/loolwsd/test/run_test.sh.in
index c52034e4d..f7895c73f 100755
--- a/loolwsd/test/run_test.sh.in
+++ b/loolwsd/test/run_test.sh.in
@@ -18,16 +18,19 @@ if test "z at ENABLE_DEBUG@" != "ztrue"; then
     exit 1;
 fi
 
+echo "Running cppunit test ...";
+
 # result logging
 echo > $test_output
 
-echo "Running cppunit test ...";
-
 ${abs_top_builddir}/loolwsd --systemplate="@SYSTEMPLATE_PATH@" --lotemplate="@LO_PATH@" \
            --childroot="@JAILS_PATH@" --allowlocalstorage 2>$test_log_output/run_test.log &
 
+echo "  waiting for loolwsd to start"
 sleep 1 # sad - need to add a wait to the start of test.cpp ...
 
+echo "  executing test"
+
 cd $test_build
 if ./test; then
 	echo "Test run_test.sh passed."
commit 7376b7475e0363c766058c6d4bcc29fac12dc2ac
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Apr 15 14:34:23 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Apr 15 14:35:57 2016 +0100

    Font bits: create symlink in jail at OS instdir path, to point at /lo
    
    This ensures that bundled fonts in instdir/share end up resolved to
    the same path that they were in when the forkit font config was setup.
    
    It may also help locate other pre-inited resources.
    
    Also copy in ~/.fonts in debug mode - can't hurt.

diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp
index 7f63ace06..18b0da2e9 100644
--- a/loolwsd/LOOLKit.cpp
+++ b/loolwsd/LOOLKit.cpp
@@ -117,6 +117,7 @@ namespace
         switch (typeflag)
         {
         case FTW_F:
+        case FTW_SLN:
             File(newPath.parent()).createDirectories();
             if (link(fpath, newPath.toString().c_str()) == -1)
             {
@@ -155,9 +156,6 @@ namespace
         case FTW_NS:
             Log::error("nftw: stat failed for '" + std::string(fpath) + "'");
             return 1;
-        case FTW_SLN:
-            Log::error("nftw: symlink to nonexistent file: '" + std::string(fpath) + "', ignored.");
-            break;
         default:
             Log::error("nftw: unexpected type: '" + std::to_string(typeflag));
             assert(false);
diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index abf73a34d..e3c5f7a88 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -131,7 +131,7 @@ clean-local:
 	if test "z at JAILS_PATH@" != "z"; then rm -rf "@JAILS_PATH@"; fi
 	if test "z at SYSTEMPLATE_PATH@" != "z"; then rm -rf "@SYSTEMPLATE_PATH@"; fi
 
-run: @JAILS_PATH@ @SYSTEMPLATE_PATH@/system_stamp
+run: all @JAILS_PATH@ @SYSTEMPLATE_PATH@/system_stamp
 	@echo "Launching loolwsd - launch this in your browser:"
 	@cp $(abs_top_srcdir)/test/data/hello.odt $(abs_top_srcdir)/test/data/hello-world.odt
 	@PROTOCOL="http" ; if test "z at ENABLE_SSL@" != "z"; then PROTOCOL="https" ; fi ; \
diff --git a/loolwsd/loolwsd-systemplate-setup b/loolwsd/loolwsd-systemplate-setup
index 4e6ee2427..54a2df02d 100755
--- a/loolwsd/loolwsd-systemplate-setup
+++ b/loolwsd/loolwsd-systemplate-setup
@@ -88,12 +88,14 @@ if [ -h usr/share/fonts/ghostscript ]; then
 fi
 
 # Our Libreoffice install often comes with pre-bundled fonts.
-mkdir -p $CHROOT/$INSTDIR/share
-cp -r -p -L $INSTDIR/share/fonts $CHROOT/$INSTDIR/share/
-
-#
-# A debugging hackery to avoid confusion.
-#
+# we need to ensure that there is a link to these with the same
+# path that fontconfig found.
+mkdir -p ./lo
+mkdir -p ./$INSTDIR
+rmdir ./$INSTDIR
+ln -s /lo $CHROOT/$INSTDIR
+
+# Debugging only hackery to avoid confusion.
 if test "z$ENABLE_DEBUG" != "z" -a "z$HOME" != "z"; then
     echo "Copying development users's fonts into systemplate"
     mkdir -p $CHROOT/$HOME
commit ab6cc4135bd734d091419e5fe610fef7745fd596
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Apr 15 14:23:44 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Apr 15 14:23:44 2016 +0100

    Copy fonts into systemplate from libreoffice install.

diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index a81842be0..abf73a34d 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -1,5 +1,7 @@
 SUBDIRS = . test
 
+export ENABLE_DEBUG
+
 bin_PROGRAMS = loolwsd loolforkit loolmap loolmount looltool
 
 dist_bin_SCRIPTS = loolwsd-systemplate-setup
@@ -118,7 +120,7 @@ if HAVE_LO_PATH
 
 SYSTEM_STAMP = @SYSTEMPLATE_PATH@/system_stamp
 
-$(SYSTEM_STAMP) :
+$(SYSTEM_STAMP) : ${top_srcdir}/loolwsd-systemplate-setup
 	if test "z at SYSTEMPLATE_PATH@" != "z"; then rm -rf "@SYSTEMPLATE_PATH@"; fi
 	${top_srcdir}/loolwsd-systemplate-setup "@SYSTEMPLATE_PATH@" "@LO_PATH@" && touch $@
 
diff --git a/loolwsd/configure.ac b/loolwsd/configure.ac
index a5cdd3a83..90a1a46fd 100644
--- a/loolwsd/configure.ac
+++ b/loolwsd/configure.ac
@@ -84,9 +84,7 @@ debug_msg="secure mode: product build"
 if test "$enable_debug" = "yes"; then
    AC_DEFINE([ENABLE_DEBUG],1,[Whether to compile in some extra debugging support code and disable some security pieces])
    ENABLE_DEBUG=true
-   if test "$enable_debug" = yes; then
-      debug_msg="low security debugging mode"
-   fi
+   debug_msg="low security debugging mode"
 else
     AC_DEFINE([ENABLE_DEBUG],0,[Whether to compile in some extra debugging support code and disable some security pieces])
 fi
diff --git a/loolwsd/loolwsd-systemplate-setup b/loolwsd/loolwsd-systemplate-setup
index 87af9e0f9..4e6ee2427 100755
--- a/loolwsd/loolwsd-systemplate-setup
+++ b/loolwsd/loolwsd-systemplate-setup
@@ -74,7 +74,7 @@ mkdir -p $CHROOT/tmp
 mkdir -p $CHROOT/usr/bin/
 
 # /usr/share/fonts needs to be taken care of separately because the
-# directory time stamps must be preserved are for fontconfig to trust
+# directory time stamps must be preserved for fontconfig to trust
 # its cache.
 
 cd $CHROOT || exit 1
@@ -86,3 +86,16 @@ if [ -h usr/share/fonts/ghostscript ]; then
     mkdir usr/share/ghostscript || exit 1
     cp -r -p /usr/share/ghostscript/fonts usr/share/ghostscript
 fi
+
+# Our Libreoffice install often comes with pre-bundled fonts.
+mkdir -p $CHROOT/$INSTDIR/share
+cp -r -p -L $INSTDIR/share/fonts $CHROOT/$INSTDIR/share/
+
+#
+# A debugging hackery to avoid confusion.
+#
+if test "z$ENABLE_DEBUG" != "z" -a "z$HOME" != "z"; then
+    echo "Copying development users's fonts into systemplate"
+    mkdir -p $CHROOT/$HOME
+    cp -r -p -L $HOME/.fonts $CHROOT/$HOME
+fi
commit b5e37448a8e3a8af54b9fd1f602542b84a0fd1a5
Author:     Michael Meeks <michael.meeks at collabora.com>
AuthorDate: Fri Apr 15 13:55:34 2016 +0100
Commit:     Michael Meeks <michael.meeks at collabora.com>
CommitDate: Fri Apr 15 13:55:34 2016 +0100

    looltool: get argument array copyies right.

diff --git a/loolwsd/LOOLTool.cpp b/loolwsd/LOOLTool.cpp
index e2d8b4ffc..ffde699c0 100644
--- a/loolwsd/LOOLTool.cpp
+++ b/loolwsd/LOOLTool.cpp
@@ -239,7 +239,7 @@ int Tool::main(const std::vector<std::string>& args)
         if (toCopy > 0)
         {
             std::vector< std::string > files( toCopy );
-            std::copy( args.begin() + offset, args.begin() + offset + chunk, files.begin() );
+            std::copy( args.begin() + offset, args.begin() + offset + toCopy, files.begin() );
             offset += toCopy;
             clients[i]->start(*(new Worker(*this, files)));
         }
commit 7df929cb7762e8d596d30ae7f28bec5302cdd1dd
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu Apr 14 23:12:25 2016 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Fri Apr 15 11:54:30 2016 +0000

    loolwsd: use SocketProcessor in kit
    
    SocketProcessor doesn't need to take response
    instance, since by the time it is called we
    are already upgraded to WebSocket and it's
    too late to set a request-level status.
    
    Change-Id: Id95087e60354a50148c88427130613356679cf82
    Reviewed-on: https://gerrit.libreoffice.org/24110
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/IoUtil.cpp b/loolwsd/IoUtil.cpp
index 081e13e41..f024055b6 100644
--- a/loolwsd/IoUtil.cpp
+++ b/loolwsd/IoUtil.cpp
@@ -18,7 +18,6 @@
 #include <string>
 
 #include <Poco/StringTokenizer.h>
-#include <Poco/Net/HTTPServerResponse.h>
 #include <Poco/Net/Socket.h>
 #include <Poco/Net/WebSocket.h>
 #include <Poco/Net/NetException.h>
@@ -41,7 +40,6 @@ namespace IoUtil
 // Synchronously process WebSocket requests and dispatch to handler.
 // Handler returns false to end.
 void SocketProcessor(std::shared_ptr<WebSocket> ws,
-                     Poco::Net::HTTPResponse& response,
                      std::function<bool(const std::vector<char>&)> handler,
                      std::function<bool()> stopPredicate)
 {
@@ -168,22 +166,6 @@ void SocketProcessor(std::shared_ptr<WebSocket> ws,
                       " bytes) will not be processed: [" + msg + "].");
         }
     }
-    catch (const WebSocketException& exc)
-    {
-        Log::error("SocketProcessor: WebSocketException: " + exc.message());
-        switch (exc.code())
-        {
-        case WebSocket::WS_ERR_HANDSHAKE_UNSUPPORTED_VERSION:
-            response.set("Sec-WebSocket-Version", WebSocket::WEBSOCKET_VERSION);
-            // fallthrough
-        case WebSocket::WS_ERR_NO_HANDSHAKE:
-        case WebSocket::WS_ERR_HANDSHAKE_NO_VERSION:
-        case WebSocket::WS_ERR_HANDSHAKE_NO_KEY:
-            response.setStatusAndReason(Poco::Net::HTTPResponse::HTTP_BAD_REQUEST);
-            response.setContentLength(0);
-            break;
-        }
-    }
     catch (const Poco::Exception& exc)
     {
         Log::error("SocketProcessor: Exception: " + exc.message());
diff --git a/loolwsd/IoUtil.hpp b/loolwsd/IoUtil.hpp
index 10078bb59..a9ed2ef9f 100644
--- a/loolwsd/IoUtil.hpp
+++ b/loolwsd/IoUtil.hpp
@@ -24,7 +24,6 @@ namespace IoUtil
     /// Synchronously process WebSocket requests and dispatch to handler.
     //. Handler returns false to end.
     void SocketProcessor(std::shared_ptr<Poco::Net::WebSocket> ws,
-                         Poco::Net::HTTPResponse& response,
                          std::function<bool(const std::vector<char>&)> handler,
                          std::function<bool()> stopPredicate);
 
diff --git a/loolwsd/LOOLKit.cpp b/loolwsd/LOOLKit.cpp
index ce32008f7..7f63ace06 100644
--- a/loolwsd/LOOLKit.cpp
+++ b/loolwsd/LOOLKit.cpp
@@ -266,18 +266,6 @@ public:
         }
     }
 
-    void handle(std::shared_ptr<TileQueue> queue, const std::string& firstLine, char* buffer, int n)
-    {
-        if (firstLine.find("paste") != 0)
-        {
-            // Everything else is expected to be a single line.
-            assert(firstLine.size() == static_cast<std::string::size_type>(n));
-            queue->put(firstLine);
-        }
-        else
-            queue->put(std::string(buffer, n));
-    }
-
     void run() override
     {
         Util::setThreadName("kit_ws_" + _session->getId());
@@ -292,38 +280,13 @@ public:
             Thread queueHandlerThread;
             queueHandlerThread.start(handler);
 
-            int flags;
-            int n;
-            do
-            {
-                char buffer[1024];
-                n = _ws->receiveFrame(buffer, sizeof(buffer), flags);
-                if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE)
+            IoUtil::SocketProcessor(_ws,
+                    [&queue](const std::vector<char>& payload)
                 {
-                    std::string firstLine = getFirstLine(buffer, n);
-                    StringTokenizer tokens(firstLine, " ", StringTokenizer::TOK_IGNORE_EMPTY | StringTokenizer::TOK_TRIM);
-
-                    // Check if it is a "nextmessage:" and in that case read the large
-                    // follow-up message separately, and handle that only.
-                    int size;
-                    if (tokens.count() == 2 && tokens[0] == "nextmessage:" && getTokenInteger(tokens[1], "size", size) && size > 0)
-                    {
-                        char largeBuffer[size];
-                        n = _ws->receiveFrame(largeBuffer, size, flags);
-                        if (n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE)
-                        {
-                            firstLine = getFirstLine(largeBuffer, n);
-                            handle(queue, firstLine, largeBuffer, n);
-                        }
-                    }
-                    else
-                        handle(queue, firstLine, buffer, n);
-                }
-            }
-            while (!_stop && n > 0 && (flags & WebSocket::FRAME_OP_BITMASK) != WebSocket::FRAME_OP_CLOSE);
-            Log::debug() << "Finishing. stop " << _stop
-                         << ", payload size: " << n
-                         << ", flags: " << std::hex << flags << Log::end;
+                    queue->put(payload);
+                    return true;
+                },
+                []() { return TerminationFlag; });
 
             queue->clear();
             queue->put("eof");
@@ -1006,8 +969,8 @@ void lokit_main(const std::string& childRoot,
         ws->setReceiveTimeout(0);
 
         const std::string socketName = "ChildControllerWS";
-        IoUtil::SocketProcessor(ws, response,
-                                [&socketName, &ws, &document, &loKit](const std::vector<char>& data)
+        IoUtil::SocketProcessor(ws,
+                [&socketName, &ws, &document, &loKit](const std::vector<char>& data)
                 {
                     std::string message(data.data(), data.size());
 
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index cbf3cce62..9d14ca921 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -590,8 +590,8 @@ private:
         Thread queueHandlerThread;
         queueHandlerThread.start(handler);
 
-        IoUtil::SocketProcessor(ws, response,
-                [&session, &queue](const std::vector<char>& payload)
+        IoUtil::SocketProcessor(ws,
+            [&queue](const std::vector<char>& payload)
             {
                 queue->put(payload);
                 return true;
@@ -896,7 +896,7 @@ public:
             // Now the bridge beetween the prison and the client is connected
             // Let messages flow
 
-            IoUtil::SocketProcessor(ws, response,
+            IoUtil::SocketProcessor(ws,
                     [&session](const std::vector<char>& payload)
                 {
                     return session->handleInput(payload.data(), payload.size());
commit df47ff1b2f475ea430cd214ecf23372f3d750102
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu Apr 14 23:11:39 2016 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Fri Apr 15 11:53:57 2016 +0000

    loolwsd: .gitignore updated
    
    Change-Id: Ica74b3f6f2fd9e3f9d75f41f2f780010b9b9bc55
    Reviewed-on: https://gerrit.libreoffice.org/24109
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/.gitignore b/loolwsd/.gitignore
index ca7b0e883..9190e91a6 100644
--- a/loolwsd/.gitignore
+++ b/loolwsd/.gitignore
@@ -45,4 +45,4 @@ loolwsd
 loolforkit
 loolmount
 loolmap
-loolmount
+looltool
commit cf85f51850fbb87c4bb7f7a7493cd4021986b9e5
Author:     Ashod Nakashian <ashod.nakashian at collabora.co.uk>
AuthorDate: Thu Apr 14 23:09:46 2016 -0400
Commit:     Ashod Nakashian <ashnakash at gmail.com>
CommitDate: Fri Apr 15 11:53:42 2016 +0000

    loolwsd: tabs -> spaces
    
    Change-Id: I581346970321446378ff135e0227e06a2092b39f
    Reviewed-on: https://gerrit.libreoffice.org/24108
    Reviewed-by: Ashod Nakashian <ashnakash at gmail.com>
    Tested-by: Ashod Nakashian <ashnakash at gmail.com>

diff --git a/loolwsd/Makefile.am b/loolwsd/Makefile.am
index b11426b08..a81842be0 100644
--- a/loolwsd/Makefile.am
+++ b/loolwsd/Makefile.am
@@ -28,7 +28,7 @@ AM_CTAGSFLAGS = $(AM_ETAGSFLAGS)
 
 shared_sources = ChildProcessSession.cpp \
                  IoUtil.cpp \
-				 Log.cpp \
+                 Log.cpp \
                  LOOLProtocol.cpp \
                  LOOLSession.cpp \
                  MessageQueue.cpp \
@@ -84,7 +84,7 @@ noinst_HEADERS = Admin.hpp \
                  FileServer.hpp \
                  IoUtil.hpp \
                  LoadTest.hpp \
-				 Log.hpp \
+                 Log.hpp \
                  LOKitHelper.hpp \
                  LOOLKit.hpp \
                  LOOLProtocol.hpp \
commit 5782e0b04c628f2a04d54004bd90bf25a6ae2420
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Fri Apr 15 14:06:00 2016 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Fri Apr 15 14:12:35 2016 +0300

    TileCache::lookupTile() already returns non-null only if the stream is open
    
    No need to test at call sites. We can assert() as a sanity check
    though.

diff --git a/loolwsd/MasterProcessSession.cpp b/loolwsd/MasterProcessSession.cpp
index 280e19c8c..63b32eb64 100644
--- a/loolwsd/MasterProcessSession.cpp
+++ b/loolwsd/MasterProcessSession.cpp
@@ -593,8 +593,9 @@ void MasterProcessSession::sendTile(const char *buffer, int length, StringTokeni
     std::memcpy(output.data(), response.data(), response.size());
 
     std::unique_ptr<std::fstream> cachedTile = _docBroker->tileCache().lookupTile(part, width, height, tilePosX, tilePosY, tileWidth, tileHeight);
-    if (cachedTile && cachedTile->is_open())
+    if (cachedTile)
     {
+        assert(cachedTile->is_open());
         cachedTile->seekg(0, std::ios_base::end);
         size_t pos = output.size();
         std::streamsize size = cachedTile->tellg();
@@ -674,8 +675,9 @@ void MasterProcessSession::sendCombinedTiles(const char* /*buffer*/, int /*lengt
 
         std::unique_ptr<std::fstream> cachedTile = _docBroker->tileCache().lookupTile(part, pixelWidth, pixelHeight, x, y, tileWidth, tileHeight);
 
-        if (cachedTile && cachedTile->is_open())
+        if (cachedTile)
         {
+            assert(cachedTile->is_open());
             std::ostringstream oss;
             oss << "tile: part=" << part
                 << " width=" << pixelWidth
commit ecaaab6e9085737d06842e1ddfaf0de3a884b066
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Fri Apr 15 13:17:16 2016 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Fri Apr 15 13:17:20 2016 +0300

    Default values for bool parameters make the code harder to read
    
    In this case we always passed the parameter anyway.

diff --git a/loolwsd/TileCache.hpp b/loolwsd/TileCache.hpp
index 70beabc5a..d656da356 100644
--- a/loolwsd/TileCache.hpp
+++ b/loolwsd/TileCache.hpp
@@ -47,7 +47,7 @@ public:
     void documentSaved();
 
     /// Notify whether we need to use the Editing cache.
-    void setEditing(bool editing = true);
+    void setEditing(bool editing);
 
     // The parameter is a message
     void saveTextFile(const std::string& text, std::string fileName);
commit cca858732a733cd7f43850b971e02ff7d462ae42
Author:     Pranav Kant <pranavk at collabora.com>
AuthorDate: Fri Apr 15 15:24:02 2016 +0530
Commit:     Pranav Kant <pranavk at collabora.com>
CommitDate: Fri Apr 15 15:25:01 2016 +0530

    loolwsd: Allow admin console to kill documents (again)
    
    Change-Id: I30405854e9ebdc56ab3477758e9008963d4b8efa

diff --git a/loolwsd/Admin.cpp b/loolwsd/Admin.cpp
index 3feec3382..d5d4557e9 100644
--- a/loolwsd/Admin.cpp
+++ b/loolwsd/Admin.cpp
@@ -186,14 +186,15 @@ void AdminRequestHandler::handleWSRequests(HTTPServerRequest& request, HTTPServe
                     {
                         try
                         {
-                            if (std::stoi(tokens[1]))
+                            const auto pid = std::stoi(tokens[1]);
+                            if (kill(pid, SIGINT) != 0 && kill(pid, 0) !=0)
                             {
-                                LOOLWSD::killKit(std::stoi(tokens[1]));
+                                Log::syserror("Cannot terminate PID: " + tokens[0]);
                             }
                         }
-                        catch(std::exception& e)
+                        catch(std::invalid_argument& exc)
                         {
-                            Log::warn() << "Could not kill given PID" << Log::end;
+                            Log::warn() << "Invalid PID to kill: " << tokens[0] << Log::end;
                         }
                     }
                     else if (tokens[0] == "mem_stats")
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 5d2ca8c80..cbf3cce62 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -1301,12 +1301,6 @@ Process::PID LOOLWSD::createForKit()
     return child.id();
 }
 
-void LOOLWSD::killKit(const Process::PID /*pid*/)
-{
-    std::unique_lock<std::mutex> docBrokersLock(docBrokersMutex);
-    // TODO
-}
-
 int LOOLWSD::main(const std::vector<std::string>& /*args*/)
 {
     Log::initialize("wsd");
diff --git a/loolwsd/LOOLWSD.hpp b/loolwsd/LOOLWSD.hpp
index 33c8c9783..ae290e490 100644
--- a/loolwsd/LOOLWSD.hpp
+++ b/loolwsd/LOOLWSD.hpp
@@ -55,9 +55,6 @@ public:
         return Util::encodeId(++NextSessionId, 4);
     }
 
-    static
-    void killKit(const Poco::Process::PID pid);
-
 protected:
     void initialize(Poco::Util::Application& self) override;
     void uninitialize() override;
commit 6ca6bf0da68957b143d32c6d02a020830e7b5d76
Author:     Tor Lillqvist <tml at collabora.com>
AuthorDate: Fri Apr 15 12:26:56 2016 +0300
Commit:     Tor Lillqvist <tml at collabora.com>
CommitDate: Fri Apr 15 12:26:56 2016 +0300

    Rant about over-use of variables where literals would work

diff --git a/loolwsd/PROBLEMS b/loolwsd/PROBLEMS
index 6f72e284c..687fae981 100644
--- a/loolwsd/PROBLEMS
+++ b/loolwsd/PROBLEMS
@@ -23,4 +23,11 @@
   to kill it with SIGKILL. Which of course leaves all the chroot jails
   around.
 
+- There are lots of places where a std::string variable is defined,
+  initialised with a value, that is never changed. (In many cases it
+  is const, so could of course not be changed.) Then the variable is
+  used just once or twice, passed as a parameter to a function, or
+  used in a comparisin expression. This is fairly pointless and just
+  makes the code harder to read. Use string literals instead.
+
 - ASCII art? Seriously?
commit 382da839e0fd41549ed06347c0e19faddb9b5400
Author:     Pranav Kant <pranavk at collabora.com>
AuthorDate: Fri Apr 15 14:48:58 2016 +0530
Commit:     Pranav Kant <pranavk at collabora.com>
CommitDate: Fri Apr 15 14:48:58 2016 +0530

    Add documentation about takeedit
    
    Change-Id: I600046111d2478f1c02552d3caa60d2a50fa7c98

diff --git a/loolwsd/protocol.txt b/loolwsd/protocol.txt
index a7e36c6c4..f6e1f523c 100644
--- a/loolwsd/protocol.txt
+++ b/loolwsd/protocol.txt
@@ -135,6 +135,13 @@ clientvisiblearea x=<x> y=<y> width=<width> height=<height>
 
     Invokes lok::Document::setClientVisibleArea().
 
+takeedit
+
+    Request for an edit lock. If successful, client will receive an 'editlock: 1'
+    message meaning editlock is granted.
+
+    See 'editlock:' message in server -> client.
+
 server -> client
 ================
 
commit 91c6154fc0900331dbe075207896ae9914ad4fb0
Author:     Pranav Kant <pranavk at collabora.com>
AuthorDate: Fri Apr 15 14:30:22 2016 +0530
Commit:     Pranav Kant <pranavk at collabora.com>
CommitDate: Fri Apr 15 14:42:14 2016 +0530

    loolwsd: Use docKey as key for Admin instead of PID
    
    Also change some variable names to be consistent with rest of the
    coding style.
    
    Change-Id: Icca9a9aec9bfb34c1edd5b6533d7646b05fe814f

diff --git a/loolwsd/Admin.cpp b/loolwsd/Admin.cpp
index 1202e95d7..3feec3382 100644
--- a/loolwsd/Admin.cpp
+++ b/loolwsd/Admin.cpp
@@ -188,7 +188,7 @@ void AdminRequestHandler::handleWSRequests(HTTPServerRequest& request, HTTPServe
                         {
                             if (std::stoi(tokens[1]))
                             {
-                                IoUtil::writeFIFO(LOOLWSD::ForKitWritePipe, firstLine + "\n");
+                                LOOLWSD::killKit(std::stoi(tokens[1]));
                             }
                         }
                         catch(std::exception& e)
@@ -384,16 +384,16 @@ Admin::~Admin()
     _cpuStatsTask->cancel();
 }
 
-void Admin::addDoc(Poco::Process::PID pid, const std::string& filename, const int sessionId)
+void Admin::addDoc(const std::string& docKey, Poco::Process::PID pid, const std::string& filename, const int sessionId)
 {
     std::unique_lock<std::mutex> modelLock(_modelMutex);
-    _model.addDocument(pid, filename, sessionId);
+    _model.addDocument(docKey, pid, filename, sessionId);
 }
 
-void Admin::rmDoc(Poco::Process::PID pid, const int sessionId)
+void Admin::rmDoc(const std::string& docKey, const int sessionId)
 {
     std::unique_lock<std::mutex> modelLock(_modelMutex);
-    _model.removeDocument(pid, sessionId);
+    _model.removeDocument(docKey, sessionId);
 }
 
 void MemoryStats::run()
diff --git a/loolwsd/Admin.hpp b/loolwsd/Admin.hpp
index 9f4d838d8..a281ba5a7 100644
--- a/loolwsd/Admin.hpp
+++ b/loolwsd/Admin.hpp
@@ -54,12 +54,11 @@ public:
     void update(const std::string& message);
 
     /// Calls with same pid will increment view count, if pid already exists
-    void addDoc(Poco::Process::PID pid, const std::string& filename, const int sessionId);
+    void addDoc(const std::string& docKey, Poco::Process::PID pid, const std::string& filename, const int sessionId);
 
     /// Decrement view count till becomes zero after which doc is removed
-    void rmDoc(Poco::Process::PID pid, const int nSessionId);
+    void rmDoc(const std::string& docKey, const int nSessionId);
 
-    /// Set the forkit process id.
     void setForKitPid(const int forKitPid) { _forKitPid = forKitPid; }
 
     /// Callers must ensure that modelMutex is acquired
diff --git a/loolwsd/AdminModel.cpp b/loolwsd/AdminModel.cpp
index 3ff947753..fec35d95e 100644
--- a/loolwsd/AdminModel.cpp
+++ b/loolwsd/AdminModel.cpp
@@ -33,7 +33,7 @@ void Document::addView(int sessionId)
     }
     else
     {
-        _nActiveViews++;
+        _activeViews++;
     }
 }
 
@@ -45,11 +45,11 @@ int Document::expireView(int sessionId)
         it->second.expire();
 
         // If last view, expire the Document also
-        if (--_nActiveViews == 0)
+        if (--_activeViews == 0)
             _end = std::time(nullptr);
     }
 
-    return _nActiveViews;
+    return _activeViews;
 }
 
 ///////////////////
@@ -243,9 +243,9 @@ void AdminModel::notify(const std::string& message)
     }
 }
 
-void AdminModel::addDocument(Poco::Process::PID pid, const std::string& filename, const int sessionId)
+void AdminModel::addDocument(const std::string& docKey, Poco::Process::PID pid, const std::string& filename, const int sessionId)
 {
-    const auto ret = _documents.emplace(pid, Document(pid, filename));
+    const auto ret = _documents.emplace(docKey, Document(docKey, pid, filename));
     ret.first->second.addView(sessionId);
 
     // Notify the subscribers
@@ -260,15 +260,15 @@ void AdminModel::addDocument(Poco::Process::PID pid, const std::string& filename
     notify(oss.str());
 }
 
-void AdminModel::removeDocument(Poco::Process::PID pid, const int sessionId)
+void AdminModel::removeDocument(const std::string& docKey, const int sessionId)
 {
-    auto docIt = _documents.find(pid);
+    auto docIt = _documents.find(docKey);
     if (docIt != _documents.end() && !docIt->second.isExpired())
     {
         // Notify the subscribers
         std::ostringstream oss;
         oss << "rmdoc" << " "
-            << pid << " "
+            << docIt->second.getPid() << " "
             << sessionId;
         Log::info("Message to admin console: " + oss.str());
         notify(oss.str());
diff --git a/loolwsd/AdminModel.hpp b/loolwsd/AdminModel.hpp
index 843320df8..806fb5cbe 100644
--- a/loolwsd/AdminModel.hpp
+++ b/loolwsd/AdminModel.hpp
@@ -23,7 +23,7 @@ class View
 {
 public:
     View(int sessionId)
-        : _nSessionId(sessionId),
+        : _sessionId(sessionId),
           _start(std::time(nullptr))
     {    }
 
@@ -32,7 +32,7 @@ public:
     bool isExpired() { return _end != 0 && std::time(nullptr) >= _end; }
 
 private:
-    int _nSessionId;
+    int _sessionId;
 
     std::time_t _start;
     std::time_t _end = 0;
@@ -41,22 +41,23 @@ private:
 class Document
 {
 public:
-    Document(Poco::Process::PID pid, std::string filename)
-        : _nPid(pid),
-          _sFilename(filename),
+    Document(std::string docKey, Poco::Process::PID pid, std::string filename)
+        : _docKey(docKey),
+          _pid(pid),
+          _filename(filename),
           _start(std::time(nullptr))
     {
-        Log::info("Document " + std::to_string(_nPid) + " ctor.");
+        Log::info("Document " + _docKey + " ctor.");
     }
 
     ~Document()
     {
-        Log::info("Document " + std::to_string(_nPid) + " dtor.");
+        Log::info("Document " + _docKey + " dtor.");
     }
 
-    Poco::Process::PID getPid() const { return _nPid; }
+    Poco::Process::PID getPid() const { return _pid; }
 
-    std::string getFilename() const { return _sFilename; }
+    std::string getFilename() const { return _filename; }
 
     bool isExpired() const { return _end != 0 && std::time(nullptr) >= _end; }
 
@@ -66,16 +67,17 @@ public:
 
     int expireView(int sessionId);
 
-    unsigned getActiveViews() const { return _nActiveViews; }
+    unsigned getActiveViews() const { return _activeViews; }
 
 private:
-    Poco::Process::PID _nPid;
+    const std::string _docKey;
+    const Poco::Process::PID _pid;
     /// SessionId mapping to View object
     std::map<int, View> _views;
     /// Total number of active views
-    unsigned _nActiveViews = 0;
+    unsigned _activeViews = 0;
     /// Hosted filename
-    std::string _sFilename;
+    std::string _filename;
 
     std::time_t _start;
     std::time_t _end = 0;
@@ -85,7 +87,7 @@ class Subscriber
 {
 public:
     Subscriber(int sessionId, std::shared_ptr<Poco::Net::WebSocket>& ws)
-        : _nSessionId(sessionId),
+        : _sessionId(sessionId),
           _ws(ws),
           _start(std::time(nullptr))
     {
@@ -109,7 +111,7 @@ public:
 
 private:
     /// Admin session Id
-    int _nSessionId;
+    int _sessionId;
     /// WebSocket to use to send messages to session
     std::weak_ptr<Poco::Net::WebSocket> _ws;
 
@@ -156,9 +158,9 @@ public:
 
     void notify(const std::string& message);
 
-    void addDocument(Poco::Process::PID pid, const std::string& filename, const int sessionId);
+    void addDocument(const std::string& docKey, Poco::Process::PID pid, const std::string& filename, const int sessionId);
 
-    void removeDocument(Poco::Process::PID pid, const int sessionId);
+    void removeDocument(const std::string& docKey, const int sessionId);
 
 private:
 
@@ -172,7 +174,7 @@ private:
 
 private:
     std::map<int, Subscriber> _subscribers;
-    std::map<Poco::Process::PID, Document> _documents;
+    std::map<std::string, Document> _documents;
 
     std::list<unsigned> _memStats;
     unsigned _memStatsSize = 100;
diff --git a/loolwsd/DocumentBroker.hpp b/loolwsd/DocumentBroker.hpp
index 998ea91c8..599fb3f1a 100644
--- a/loolwsd/DocumentBroker.hpp
+++ b/loolwsd/DocumentBroker.hpp
@@ -172,6 +172,8 @@ public:
 
     unsigned getWSSessionsCount() { return _wsSessions.size(); }
 
+    void kill() { _childProcess->close(true); };
+
 private:
     const Poco::URI _uriPublic;
     const std::string _docKey;
diff --git a/loolwsd/LOOLWSD.cpp b/loolwsd/LOOLWSD.cpp
index 0cf254d0f..5d2ca8c80 100644
--- a/loolwsd/LOOLWSD.cpp
+++ b/loolwsd/LOOLWSD.cpp
@@ -805,10 +805,10 @@ public:
 
         std::string sessionId;
         std::string jailId;
+        std::string docKey;
         try
         {
             const auto params = Poco::URI(request.getURI()).getQueryParameters();
-            std::string docKey;
             for (const auto& param : params)
             {
                 if (param.first == "sessionId")
@@ -875,16 +875,17 @@ public:
             const auto uri = request.getURI();
 
             // Jail id should be the PID, beacuse Admin need it to calculate the memory
+            Poco::Process::PID pid;
             try
             {
-                Log::info("Adding doc " + jailId + " to Admin");
-                Admin::instance().addDoc(std::stoi(jailId), docBroker->getFilename(), std::stoi(sessionId));
+                pid = std::stoi(jailId);
             }
             catch (std::invalid_argument& exc)
             {
                 assert(false);
             }
-
+            Log::info("Adding doc " + docKey + " to Admin");
+            Admin::instance().addDoc(docKey, pid, docBroker->getFilename(), Util::decodeId(sessionId));
 
             if (waitBridgeCompleted(session))
             {
@@ -919,15 +920,8 @@ public:
 
         if (!jailId.empty())
         {
-            try
-            {
-                Log::info("Removing doc " + jailId + " from Admin");
-                Admin::instance().rmDoc(std::stoi(jailId), std::stoi(sessionId));
-            }
-            catch (std::invalid_argument& exc)
-            {
-                assert(false);
-            }
+            Log::info("Removing doc " + docKey + " from Admin");
+            Admin::instance().rmDoc(docKey, Util::decodeId(sessionId));
         }
 
         Log::debug("Thread finished.");
@@ -1307,6 +1301,12 @@ Process::PID LOOLWSD::createForKit()
     return child.id();
 }
 
+void LOOLWSD::killKit(const Process::PID /*pid*/)
+{
+    std::unique_lock<std::mutex> docBrokersLock(docBrokersMutex);
+    // TODO
+}
+
 int LOOLWSD::main(const std::vector<std::string>& /*args*/)
 {
     Log::initialize("wsd");
diff --git a/loolwsd/LOOLWSD.hpp b/loolwsd/LOOLWSD.hpp
index ae290e490..33c8c9783 100644
--- a/loolwsd/LOOLWSD.hpp
+++ b/loolwsd/LOOLWSD.hpp
@@ -55,6 +55,9 @@ public:
         return Util::encodeId(++NextSessionId, 4);
     }
 
+    static
+    void killKit(const Poco::Process::PID pid);
+
 protected:
     void initialize(Poco::Util::Application& self) override;
     void uninitialize() override;
commit 61914208bce83fcb5f7c306a9959e4cab93344b8
Author:     Pranav Kant <pranavk at collabora.com>
AuthorDate: Fri Apr 15 02:20:05 2016 +0530
Commit:     Pranav Kant <pranavk at collabora.com>
CommitDate: Fri Apr 15 13:28:42 2016 +0530

    loleaflet: Adapt to new changes in admin console
    
    Change-Id: I0761bd6c5b3650795a318a077eb50d0a8bd161da

diff --git a/loleaflet/src/admin/AdminSocketOverview.js b/loleaflet/src/admin/AdminSocketOverview.js
index 5bcb54eaf..a93041580 100644
--- a/loleaflet/src/admin/AdminSocketOverview.js
+++ b/loleaflet/src/admin/AdminSocketOverview.js
@@ -20,7 +20,7 @@ var AdminSocketOverview = AdminSocketBase.extend({
 
 	onSocketOpen: function() {
 		this.socket.send('documents');
-		this.socket.send('subscribe document addview rmview rmdoc');
+		this.socket.send('subscribe adddoc rmdoc');
 
 		this._getBasicStats();
 		var socketOverview = this;
@@ -78,9 +78,9 @@ var AdminSocketOverview = AdminSocketBase.extend({
 
 		var tableContainer = document.getElementById('doclist');
 		var rowContainer;
-		var pidEle, urlEle, viewsEle, memEle, sDocTimeEle, docEle;
+		var pidEle, nameEle, viewsEle, memEle, sDocTimeEle, docEle, aEle;
 		var nViews, nTotalViews;
-		var docProps, sPid, sUrl, sViews, sMem, sDocTime;
+		var docProps, sPid, sName, sViews, sMem, sDocTime;
 		if (textMsg.startsWith('documents')) {
 			var documents = textMsg.substring('documents'.length);
 			documents = documents.trim().split('\n');
@@ -90,11 +90,11 @@ var AdminSocketOverview = AdminSocketBase.extend({
 				}
 				docProps = documents[i].trim().split(' ');
 				sPid = docProps[0];
-				sUrl = docProps[1];
+				sName = docProps[1];
 				sViews = docProps[2];
 				sMem = docProps[3];
 				sDocTime = docProps[4];
-				if (sUrl === '0') {
+				if (sName === '0') {
 					continue;
 				}
 				rowContainer = document.createElement('tr');
@@ -105,9 +105,9 @@ var AdminSocketOverview = AdminSocketBase.extend({
 				pidEle.innerHTML = sPid;
 				rowContainer.appendChild(pidEle);
 
-				urlEle = document.createElement('td');
-				urlEle.innerHTML = sUrl;
-				rowContainer.appendChild(urlEle);
+				nameEle = document.createElement('td');

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list