multi_range_http_fetcher.cc revision ffcb6d16938fb1c91be4f55abc3ad3da109c1044
1819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// Use of this source code is governed by a BSD-style license that can be 3819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// found in the LICENSE file. 4819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 5819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes#include "update_engine/multi_range_http_fetcher.h" 6819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 7819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes#include "update_engine/utils.h" 8819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 9819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesnamespace chromeos_update_engine { 10819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 11819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// Begins the transfer to the specified URL. 12819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Stopped -> Downloading 13819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// (corner case: Stopped -> Stopped for an empty request) 14819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesvoid MultiRangeHTTPFetcher::BeginTransfer(const std::string& url) { 15819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!base_fetcher_active_) << "BeginTransfer but already active."; 16819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!pending_transfer_ended_) << "BeginTransfer but pending."; 17819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!terminating_) << "BeginTransfer but terminating."; 18819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 19819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (ranges_.empty()) { 20819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 21819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 22819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferComplete(this, true); 23819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 24819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 25819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes url_ = url; 26819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_ = 0; 27819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 28819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "starting first transfer"; 29819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->set_delegate(this); 30819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes StartTransfer(); 31819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 32819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 33819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading -> Pending transfer ended 34819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesvoid MultiRangeHTTPFetcher::TerminateTransfer() { 35819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (!base_fetcher_active_) { 36819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Called TerminateTransfer but not active."; 37819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 38819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 39819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferTerminated(this); 40819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 41819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 42819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes terminating_ = true; 43819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 44819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (!pending_transfer_ended_) { 45819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->TerminateTransfer(); 46819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 47819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 48819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 49819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Stopped or Downloading -> Downloading 50819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesvoid MultiRangeHTTPFetcher::StartTransfer() { 51819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (current_index_ >= ranges_.size()) { 52819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 53819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 54819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Starting a transfer @" << ranges_[current_index_].first << "(" 55819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes << ranges_[current_index_].second << ")"; 56819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 57819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->SetOffset(ranges_[current_index_].first); 58819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 59819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->SeekToOffset(ranges_[current_index_].first); 60819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_active_ = true; 61819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->BeginTransfer(url_); 62819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 63819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 64819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading -> Downloading or Pending transfer ended 65819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesvoid MultiRangeHTTPFetcher::ReceivedBytes(HttpFetcher* fetcher, 66819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes const char* bytes, 67819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes int length) { 68819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_LT(current_index_, ranges_.size()); 69819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_EQ(fetcher, base_fetcher_.get()); 70819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!pending_transfer_ended_); 71819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes off_t next_size = length; 72819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (ranges_[current_index_].second >= 0) { 73819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes next_size = std::min(next_size, 74819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes ranges_[current_index_].second - 75819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_); 76819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 77819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG_IF(WARNING, next_size <= 0) << "Asked to write length <= 0"; 78819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) { 79819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->ReceivedBytes(this, bytes, next_size); 80819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 81819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ += length; 82819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (ranges_[current_index_].second >= 0 && 83819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ >= ranges_[current_index_].second) { 84819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Terminates the current fetcher. Waits for its TransferTerminated 85819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // callback before starting the next range so that we don't end up 86819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // signalling the delegate that the whole multi-transfer is complete 87819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // before all fetchers are really done and cleaned up. 88819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes pending_transfer_ended_ = true; 89819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "terminating transfer"; 90819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes fetcher->TerminateTransfer(); 91819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 92819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 93819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 94819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading or Pending transfer ended -> Stopped 95819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesvoid MultiRangeHTTPFetcher::TransferEnded(HttpFetcher* fetcher, 96819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bool successful) { 97819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(base_fetcher_active_) << "Transfer ended unexpectedly."; 98819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_EQ(fetcher, base_fetcher_.get()); 99819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes pending_transfer_ended_ = false; 100819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes http_response_code_ = fetcher->http_response_code(); 101819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "TransferEnded w/ code " << http_response_code_; 102819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (terminating_) { 103819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Terminating."; 104819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 105819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 106819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 107819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferTerminated(this); 108819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 109819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 110819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 111819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // If we didn't get enough bytes, it's failure 112819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (ranges_[current_index_].second >= 0) { 113819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (bytes_received_this_range_ < ranges_[current_index_].second) { 114819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Failure 115819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Didn't get enough bytes. Ending w/ failure."; 116819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 117819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 118819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 119819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferComplete(this, false); 120819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 121819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 122819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // We got enough bytes and there were bytes specified, so this is success. 123819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes successful = true; 124819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 125819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 126ffcb6d16938fb1c91be4f55abc3ad3da109c1044Andrew de los Reyes // If we have another transfer, do that. 127819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (current_index_ + 1 < ranges_.size()) { 128819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_++; 129819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Starting next transfer (" << current_index_ << ")."; 130819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes StartTransfer(); 131819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 132819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 133819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 134819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Done w/ all transfers"; 135819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 136819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 137819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 138819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferComplete(this, successful); 139819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 140819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 141819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesvoid MultiRangeHTTPFetcher::TransferComplete(HttpFetcher* fetcher, 142819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bool successful) { 143819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Received transfer complete."; 144819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes TransferEnded(fetcher, successful); 145819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 146819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 147819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesvoid MultiRangeHTTPFetcher::TransferTerminated(HttpFetcher* fetcher) { 148819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Received transfer terminated."; 149819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes TransferEnded(fetcher, false); 150819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 151819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 152819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesvoid MultiRangeHTTPFetcher::Reset() { 153819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_active_ = pending_transfer_ended_ = terminating_ = false; 154819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_ = 0; 155819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 156819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 157819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 158819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} // namespace chromeos_update_engine 159