Fix timeout issue during image upload

This commit fixes timeout issues when transfering bigger payloads
like update image.

Tested by uploading image:

  curl -k -H "X-Auth-Token: $token" -H "Content-Type: application/octet-stream" \
    -X POST -T test.tar https://$bmc/upload/image

  # slow connection upload (~10kB/s)
  curl -k -H "X-Auth-Token: $token" -H "Content-Type: application/octet-stream" \
    -X POST -T test.tar https://$bmc/upload/image --limit-rate 10k

Signed-off-by: Jan Sowinski <jan.sowinski@intel.com>
Change-Id: I913136013afb58c97071819288460f4cb64d0d83
diff --git a/http/http_connection.h b/http/http_connection.h
index 4ef3bc6..5155779 100644
--- a/http/http_connection.h
+++ b/http/http_connection.h
@@ -833,16 +833,30 @@
     {
         cancelDeadlineTimer();
 
-        timerCancelKey = timerQueue.add([this, self(shared_from_this())] {
-            // Mark timer as not active to avoid canceling it during
-            // Connection destructor which leads to double free issue
-            timerCancelKey.reset();
-            if (!isAlive())
-            {
-                return;
-            }
-            close();
-        });
+        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;
+                }
+
+                // 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;
+                }
+
+                close();
+            });
         BMCWEB_LOG_DEBUG << this << " timer added: " << &timerQueue << ' '
                          << *timerCancelKey;
     }
diff --git a/http/timer_queue.h b/http/timer_queue.h
index 26eea13..7339d66 100644
--- a/http/timer_queue.h
+++ b/http/timer_queue.h
@@ -45,12 +45,15 @@
         while (!dq.empty())
         {
             auto& x = dq.front();
-            if (now - x.first < std::chrono::seconds(5))
-            {
-                break;
-            }
+            // Check expiration time only for active handlers,
+            // remove canceled ones immediately
             if (x.second)
             {
+                if (now - x.first < std::chrono::seconds(5))
+                {
+                    break;
+                }
+
                 BMCWEB_LOG_DEBUG << "timer call: " << this << ' ' << step;
                 // we know that timer handlers are very simple currenty; call
                 // here