Protect against slow read attack

Right now as long as an attacker continutes to
do a slow read, the connection will stay open forever.
Set a timeout so this can't happen.

Tested: Used slowhttptest to verify this wouldn't
happen

Change-Id: I4dbe2a18f9ccce0ba36875572ec3df6bf3be6a1e
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/http/http_connection.h b/http/http_connection.h
index 4cd1e89..9f6c7b6 100644
--- a/http/http_connection.h
+++ b/http/http_connection.h
@@ -831,34 +831,39 @@
         }
     }
 
-    void startDeadline()
+    void startDeadline(size_t timerIterations = 0)
     {
+        // drop all connections after 1 minute, this time limit was chosen
+        // arbitrarily and can be adjusted later if needed
+        constexpr const size_t maxReadAttempts =
+            (60 / detail::timerQueueTimeoutSeconds);
+
         cancelDeadlineTimer();
 
-        timerCancelKey =
-            timerQueue.add([this, self(shared_from_this()),
-                            readCount{parser->get().body().size()}] {
-                // Mark timer as not active to avoid canceling it during
-                // Connection destructor which leads to double free issue
-                timerCancelKey.reset();
-                if (!isAlive())
-                {
-                    return;
-                }
+        timerCancelKey = timerQueue.add([this, self(shared_from_this()),
+                                         readCount{parser->get().body().size()},
+                                         timerIterations{timerIterations + 1}] {
+            // Mark timer as not active to avoid canceling it during
+            // Connection destructor which leads to double free issue
+            timerCancelKey.reset();
+            if (!isAlive())
+            {
+                return;
+            }
 
-                // Restart timer if read is in progress.
-                // With threshold can be used to drop slow connections
-                // to protect against slow-rate DoS attack
-                if (parser->get().body().size() > readCount)
-                {
-                    BMCWEB_LOG_DEBUG << this
-                                     << " restart timer - read in progress";
-                    startDeadline();
-                    return;
-                }
+            // Restart timer if read is in progress.
+            // With threshold can be used to drop slow connections
+            // to protect against slow-rate DoS attack
+            if ((parser->get().body().size() > readCount) &&
+                (timerIterations < maxReadAttempts))
+            {
+                BMCWEB_LOG_DEBUG << this << " restart timer - read in progress";
+                startDeadline(timerIterations);
+                return;
+            }
 
-                close();
-            });
+            close();
+        });
         BMCWEB_LOG_DEBUG << this << " timer added: " << &timerQueue << ' '
                          << *timerCancelKey;
     }