AU multi-range fetcher requests properly closed ranges when their length
is known.

* HttpFetcher allows to set the length of data to be fetched.
  LibcurlHttpFetcher uses this value in applying the appropriate libcurl
  option (CURLOPT_RANGE).  MultiHttpFetcher sets the desired payload
  length in the underlying fetcher accordingly.

* Improved functionality of test_http_server: (a) correctly parses
  closed range intervals; (b) generalized response header generation;
  (c) unified and generalized get handling for both stable and flaky
  cases.

* Small scale refactoring, improved logging and readability.

BUG=chromium-os:24666
TEST=unit tests

Change-Id: I1727710ca747088c67a68305f355da683b07b6a3
Reviewed-on: https://gerrit.chromium.org/gerrit/13594
Reviewed-by: Gilad Arnold <garnold@chromium.org>
Tested-by: Gilad Arnold <garnold@chromium.org>
Commit-Ready: Gilad Arnold <garnold@chromium.org>
diff --git a/libcurl_http_fetcher.cc b/libcurl_http_fetcher.cc
index 05d03fa..df376d5 100644
--- a/libcurl_http_fetcher.cc
+++ b/libcurl_http_fetcher.cc
@@ -8,6 +8,7 @@
 #include <string>
 
 #include <base/logging.h>
+#include <base/stringprintf.h>
 
 #include "update_engine/certificate_checker.h"
 #include "update_engine/chrome_proxy_resolver.h"
@@ -92,12 +93,26 @@
              CURLE_OK);
   }
 
-  if (bytes_downloaded_ > 0) {
-    // Resume from where we left off
+  if (bytes_downloaded_ > 0 || download_length_) {
+    // Resume from where we left off.
     resume_offset_ = bytes_downloaded_;
-    CHECK_EQ(curl_easy_setopt(curl_handle_,
-                              CURLOPT_RESUME_FROM_LARGE,
-                              bytes_downloaded_), CURLE_OK);
+    CHECK_GE(resume_offset_, 0);
+
+    // Compute end offset, if one is specified. As per HTTP specification, this
+    // is an inclusive boundary. Make sure it doesn't overflow.
+    size_t end_offset = 0;
+    if (download_length_) {
+      end_offset = static_cast<size_t>(resume_offset_) + download_length_ - 1;
+      CHECK_LE((size_t) resume_offset_, end_offset);
+    }
+
+    // Create a string representation of the desired range.
+    std::string range_str = (end_offset ?
+                             StringPrintf("%jd-%zu", resume_offset_,
+                                          end_offset) :
+                             StringPrintf("%jd-", resume_offset_));
+    CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_RANGE, range_str.c_str()),
+             CURLE_OK);
   }
 
   CHECK_EQ(curl_easy_setopt(curl_handle_, CURLOPT_WRITEDATA, this), CURLE_OK);