AU: MultiHttpFetcher, an HttpFetcher for specific byte ranges

MultiHttpFetcher takes an HttpFetcher class via template parameter,
and a collection of byte ranges. It hits up the URL multiple times,
once per range specified. For each time, it uses a new HttpFetcher of
the type specified and fast-forwards to the offset requested, and
aborting after enough bytes have been downloaded. Any range many
specify a length of -1, which means until the end of the file (as
dictated by the server). Thus, a single range of [0, -1] makes
MultiHttpFetcher a pass-through.

HttpFetcher change: ability to supply an offset.

LibcurlHttpFetcher changes: offset support (from HttpFetcher API),
ability to be terminted in a write-callback.

test_http_fetcher: support for failures in write() on the socket (at
least in the /big url case).

BUG=7391
TEST=unittests

Review URL: http://codereview.chromium.org/3591018
diff --git a/libcurl_http_fetcher.h b/libcurl_http_fetcher.h
index 8908638..69e794f 100644
--- a/libcurl_http_fetcher.h
+++ b/libcurl_http_fetcher.h
@@ -27,13 +27,20 @@
         curl_handle_(NULL),
         timeout_source_(NULL),
         transfer_in_progress_(false),
+        transfer_size_(0),
+        bytes_downloaded_(0),
+        resume_offset_(0),
         retry_count_(0),
         retry_seconds_(60),
-        idle_seconds_(1) {}
+        idle_seconds_(1),
+        in_write_callback_(false),
+        terminate_requested_(false) {}
 
   // Cleans up all internal state. Does not notify delegate
   ~LibcurlHttpFetcher();
 
+  void SetOffset(off_t offset) { bytes_downloaded_ = offset; }
+
   // Begins the transfer if it hasn't already begun.
   virtual void BeginTransfer(const std::string& url);
 
@@ -62,6 +69,9 @@
   void set_retry_seconds(int seconds) { retry_seconds_ = seconds; }
 
  private:
+  // Asks libcurl for the http response code and stores it in the object.
+  void GetHttpResponseCode();
+
   // Resumes a transfer where it left off. This will use the
   // HTTP Range: header to make a new connection from where the last
   // left off.
@@ -135,6 +145,8 @@
 
   // If we resumed an earlier transfer, data offset that we used for the
   // new connection.  0 otherwise.
+  // In this class, resume refers to resuming a dropped HTTP connection,
+  // not to resuming an interrupted download.
   off_t resume_offset_;
 
   // Number of resumes performed.
@@ -146,6 +158,13 @@
   // Seconds to wait before asking libcurl to "perform".
   int idle_seconds_;
 
+  // If true, we are currently performing a write callback on the delegate.
+  bool in_write_callback_;
+  
+  // We can't clean everything up while we're in a write callback, so
+  // if we get a terminate request, queue it until we can handle it.
+  bool terminate_requested_;
+
   DISALLOW_COPY_AND_ASSIGN(LibcurlHttpFetcher);
 };