AU: When server dies, don't retry forever

BUG=4871
TEST=attached unittests

Review URL: http://codereview.chromium.org/3010009
diff --git a/libcurl_http_fetcher.cc b/libcurl_http_fetcher.cc
index 7a032fe..e2f18af 100644
--- a/libcurl_http_fetcher.cc
+++ b/libcurl_http_fetcher.cc
@@ -14,6 +14,10 @@
 
 namespace chromeos_update_engine {
 
+namespace {
+const int kMaxRetriesCount = 20;
+}
+
 LibcurlHttpFetcher::~LibcurlHttpFetcher() {
   CleanUp();
 }
@@ -66,9 +70,9 @@
   transfer_size_ = -1;
   bytes_downloaded_ = 0;
   resume_offset_ = 0;
-  do {
-    ResumeTransfer(url);
-  } while (CurlPerformOnce());
+  retry_count_ = 0;
+  ResumeTransfer(url);
+  CurlPerformOnce();
 }
 
 void LibcurlHttpFetcher::TerminateTransfer() {
@@ -86,15 +90,37 @@
     retcode = curl_multi_perform(curl_multi_handle_, &running_handles);
   }
   if (0 == running_handles) {
+    long http_response_code = 0;
+    if (curl_easy_getinfo(curl_handle_,
+                          CURLINFO_RESPONSE_CODE,
+                          &http_response_code) == CURLE_OK) {
+      LOG(INFO) << "HTTP response code: " << http_response_code;
+    } else {
+      LOG(ERROR) << "Unable to get http response code.";
+    }
+    
     // we're done!
     CleanUp();
 
     if ((transfer_size_ >= 0) && (bytes_downloaded_ < transfer_size_)) {
       // Need to restart transfer
-      return true;
+      retry_count_++;
+      LOG(INFO) << "Restarting transfer b/c we finished, had downloaded "
+                << bytes_downloaded_ << " bytes, but transfer_size_ is "
+                << transfer_size_ << ". retry_count: " << retry_count_;
+      if (retry_count_ > kMaxRetriesCount) {
+        if (delegate_)
+          delegate_->TransferComplete(this, false);  // success
+      } else {
+        g_timeout_add(5 * 1000,
+                      &LibcurlHttpFetcher::StaticRetryTimeoutCallback,
+                      this);
+      }
+      return false;
     } else {
       if (delegate_) {
-        delegate_->TransferComplete(this, true);  // success
+        // success is when http_response_code is 200
+        delegate_->TransferComplete(this, http_response_code == 200);
       }
     }
   } else {
@@ -217,9 +243,7 @@
 
 bool LibcurlHttpFetcher::FDCallback(GIOChannel *source,
                                     GIOCondition condition) {
-  while (CurlPerformOnce()) {
-    ResumeTransfer(url_);
-  }
+  CurlPerformOnce();
   // We handle removing of this source elsewhere, so we always return true.
   // The docs say, "the function should return FALSE if the event source
   // should be removed."
@@ -227,6 +251,12 @@
   return true;
 }
 
+gboolean LibcurlHttpFetcher::RetryTimeoutCallback() {
+  ResumeTransfer(url_);
+  CurlPerformOnce();
+  return FALSE;  // Don't have glib auto call this callback again
+}
+
 gboolean LibcurlHttpFetcher::TimeoutCallback() {
   if (!transfer_in_progress_)
     return TRUE;
@@ -236,9 +266,7 @@
   // timeout callback then.
   // TODO(adlr): optimize by checking if we can keep this timeout callback.
   //timeout_source_ = NULL;
-  while (CurlPerformOnce()) {
-    ResumeTransfer(url_);
-  }
+  CurlPerformOnce();
   return TRUE;
 }