[Libreoffice-commits] online.git: net/Socket.cpp net/Socket.hpp wsd/LOOLWSD.cpp

Michael Meeks michael.meeks at collabora.com
Tue May 1 15:30:58 UTC 2018


 net/Socket.cpp  |   66 +++++++++++++++++++++++++++++++++++++
 net/Socket.hpp  |   19 +++++++++-
 wsd/LOOLWSD.cpp |   98 +++++++-------------------------------------------------
 3 files changed, 96 insertions(+), 87 deletions(-)

New commits:
commit b5a1af763cf0e2295286f3e27c767ec51551cf2f
Author: Michael Meeks <michael.meeks at collabora.com>
Date:   Tue May 1 14:57:17 2018 +0100

    Share HTTP header parsing inside the StreamSocket.
    
    Change-Id: Id98e895a939d931ac10b7cd7403da4cbe822ee82

diff --git a/net/Socket.cpp b/net/Socket.cpp
index 1bf847cba..9a07986c9 100644
--- a/net/Socket.cpp
+++ b/net/Socket.cpp
@@ -17,6 +17,8 @@
 #include <Poco/DateTime.h>
 #include <Poco/DateTimeFormat.h>
 #include <Poco/DateTimeFormatter.h>
+#include <Poco/MemoryStream.h>
+#include <Poco/Net/HTTPRequest.h>
 #include <Poco/Net/HTTPResponse.h>
 
 #include <SigUtil.hpp>
@@ -241,6 +243,70 @@ bool ServerSocket::bind(Type type, int port)
     return rc == 0;
 }
 
+bool StreamSocket::parseHeader(const char *clientName,
+                               Poco::MemoryInputStream &message,
+                               Poco::Net::HTTPRequest &request,
+                               size_t *requestSize)
+{
+    LOG_TRC("#" << getFD() << " handling incoming " << _inBuffer.size() << " bytes.");
+
+    assert(!requestSize || *requestSize == 0);
+
+    // Find the end of the header, if any.
+    static const std::string marker("\r\n\r\n");
+    auto itBody = std::search(_inBuffer.begin(), _inBuffer.end(),
+                              marker.begin(), marker.end());
+    if (itBody == _inBuffer.end())
+    {
+        LOG_TRC("#" << getFD() << " doesn't have enough data yet.");
+        return false;
+    }
+
+    // Skip the marker.
+    itBody += marker.size();
+    if (requestSize)
+        *requestSize = static_cast<size_t>(itBody - _inBuffer.begin());
+
+    try
+    {
+        request.read(message);
+
+        Log::StreamLogger logger = Log::info();
+        if (logger.enabled())
+        {
+            logger << "#" << getFD() << ": " << clientName << " HTTP Request: "
+                   << request.getMethod() << ' '
+                   << request.getURI() << ' '
+                   << request.getVersion();
+
+            for (const auto& it : request)
+            {
+                logger << " / " << it.first << ": " << it.second;
+            }
+
+            LOG_END(logger);
+        }
+
+        const std::streamsize contentLength = request.getContentLength();
+        const auto offset = itBody - _inBuffer.begin();
+        const std::streamsize available = _inBuffer.size() - offset;
+
+        if (contentLength != Poco::Net::HTTPMessage::UNKNOWN_CONTENT_LENGTH && available < contentLength)
+        {
+            LOG_DBG("Not enough content yet: ContentLength: " << contentLength << ", available: " << available);
+            return false;
+        }
+    }
+    catch (const std::exception& exc)
+    {
+        // Probably don't have enough data just yet.
+        // TODO: timeout if we never get enough.
+        return false;
+    }
+
+    return true;
+}
+
 
 namespace HttpHelper
 {
diff --git a/net/Socket.hpp b/net/Socket.hpp
index d3d48128f..84632a4f2 100644
--- a/net/Socket.hpp
+++ b/net/Socket.hpp
@@ -40,8 +40,10 @@
 
 namespace Poco
 {
+    class MemoryInputStream;
     namespace Net
     {
+        class HTTPRequest;
         class HTTPResponse;
     }
 }
@@ -833,6 +835,20 @@ public:
         return socket;
     }
 
+    /// Remove the first @count bytes from input buffer
+    void eraseFirstInputBytes(size_t count)
+    {
+        _inBuffer.erase(_inBuffer.begin(), _inBuffer.begin() + count);
+    }
+
+    /// Detects if we have an HTTP header in the provided message and
+    /// populates a request for that.
+    bool parseHeader(const char *clientLoggingName,
+                     Poco::MemoryInputStream &message,
+                     Poco::Net::HTTPRequest &request,
+                     size_t *requestSize = nullptr);
+
+    /// Get input/output statistics on this stream
     void getIOStats(uint64_t &sent, uint64_t &recv)
     {
         sent = _bytesSent;
@@ -1021,8 +1037,7 @@ namespace HttpHelper
     void sendFile(const std::shared_ptr<StreamSocket>& socket, const std::string& path, const std::string& mediaType,
                   Poco::Net::HTTPResponse& response, bool noCache = false, bool deflate = false,
                   const bool headerOnly = false);
-};
-
+}
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/wsd/LOOLWSD.cpp b/wsd/LOOLWSD.cpp
index 9d39ba2ce..668916500 100644
--- a/wsd/LOOLWSD.cpp
+++ b/wsd/LOOLWSD.cpp
@@ -1608,42 +1608,16 @@ private:
         }
 
         std::shared_ptr<StreamSocket> socket = _socket.lock();
-        std::vector<char>& in = socket->_inBuffer;
 
-        // Find the end of the header, if any.
-        static const std::string marker("\r\n\r\n");
-        auto itBody = std::search(in.begin(), in.end(),
-                                  marker.begin(), marker.end());
-        if (itBody == in.end())
-        {
-            LOG_TRC("#" << socket->getFD() << " doesn't have enough data yet.");
-            return;
-        }
-
-        // Skip the marker.
-        itBody += marker.size();
-
-        Poco::MemoryInputStream message(&in[0], in.size());
+        Poco::MemoryInputStream message(&socket->_inBuffer[0],
+                                        socket->_inBuffer.size());;
         Poco::Net::HTTPRequest request;
+        size_t requestSize = 0;
+
         try
         {
-            request.read(message);
-
-            Log::StreamLogger logger = Log::info();
-            if (logger.enabled())
-            {
-                logger << "#" << socket->getFD() << ": Prisoner HTTP Request: "
-                       << request.getMethod() << ' '
-                       << request.getURI() << ' '
-                       << request.getVersion();
-
-                for (const auto& it : request)
-                {
-                    logger << " / " << it.first << ": " << it.second;
-                }
-
-                LOG_END(logger);
-            }
+            if (!socket->parseHeader("Prisoner", message, request, &requestSize))
+                return;
 
             LOG_TRC("Child connection with URI [" << request.getURI() << "].");
             if (request.getURI().find(NEW_CHILD_URI) != 0)
@@ -1684,7 +1658,7 @@ private:
                 return;
             }
 
-            in.clear();
+            socket->_inBuffer.clear();
 
             LOG_INF("New child [" << pid << "], jailId: " << jailId << ".");
 
@@ -1768,60 +1742,14 @@ private:
     void handleIncomingMessage(SocketDisposition &disposition) override
     {
         std::shared_ptr<StreamSocket> socket = _socket.lock();
-        std::vector<char>& in = socket->_inBuffer;
-        LOG_TRC("#" << socket->getFD() << " handling incoming " << in.size() << " bytes.");
-
-        // Find the end of the header, if any.
-        static const std::string marker("\r\n\r\n");
-        auto itBody = std::search(in.begin(), in.end(),
-                                  marker.begin(), marker.end());
-        if (itBody == in.end())
-        {
-            LOG_DBG("#" << socket->getFD() << " doesn't have enough data yet.");
-            return;
-        }
 
-        // Skip the marker.
-        itBody += marker.size();
-
-        Poco::MemoryInputStream message(&in[0], in.size());
+        Poco::MemoryInputStream message(&socket->_inBuffer[0],
+                                        socket->_inBuffer.size());;
         Poco::Net::HTTPRequest request;
-        try
-        {
-            request.read(message);
-
-            Log::StreamLogger logger = Log::info();
-            if (logger.enabled())
-            {
-                logger << "#" << socket->getFD() << ": Client HTTP Request: "
-                       << request.getMethod() << ' '
-                       << request.getURI() << ' '
-                       << request.getVersion();
-
-                for (const auto& it : request)
-                {
-                    logger << " / " << it.first << ": " << it.second;
-                }
-
-                LOG_END(logger);
-            }
-
-            const std::streamsize contentLength = request.getContentLength();
-            const auto offset = itBody - in.begin();
-            const std::streamsize available = in.size() - offset;
+        size_t requestSize = 0;
 
-            if (contentLength != Poco::Net::HTTPMessage::UNKNOWN_CONTENT_LENGTH && available < contentLength)
-            {
-                LOG_DBG("Not enough content yet: ContentLength: " << contentLength << ", available: " << available);
-                return;
-            }
-        }
-        catch (const std::exception& exc)
-        {
-            // Probably don't have enough data just yet.
-            // TODO: timeout if we never get enough.
+        if (!socket->parseHeader("Client", message, request, &requestSize))
             return;
-        }
 
         try
         {
@@ -1949,12 +1877,12 @@ private:
 
             // NOTE: Check _wsState to choose between HTTP response or WebSocket (app-level) error.
             LOG_INF("#" << socket->getFD() << " Exception while processing incoming request: [" <<
-                    LOOLProtocol::getAbbreviatedMessage(in) << "]: " << exc.what());
+                    LOOLProtocol::getAbbreviatedMessage(socket->_inBuffer) << "]: " << exc.what());
         }
 
         // if we succeeded - remove the request from our input buffer
         // we expect one request per socket
-        in.erase(in.begin(), itBody);
+        socket->eraseFirstInputBytes(requestSize);
     }
 
     int getPollEvents(std::chrono::steady_clock::time_point /* now */,


More information about the Libreoffice-commits mailing list