multi_range_http_fetcher.cc revision f68bbbc952aa9a71898e4939b5f36187fa564a50
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 5aab50e31f0b80ed53a9b8d5dbabcf943974bd32cAlex Deymo#include "update_engine/multi_range_http_fetcher.h" 6aab50e31f0b80ed53a9b8d5dbabcf943974bd32cAlex Deymo 775039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/stringprintf.h> 8819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 9d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko#include <algorithm> 10d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko#include <string> 11d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko 12819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes#include "update_engine/utils.h" 13819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 14819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesnamespace chromeos_update_engine { 15819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 16819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// Begins the transfer to the specified URL. 17819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Stopped -> Downloading 18819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// (corner case: Stopped -> Stopped for an empty request) 199bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::BeginTransfer(const std::string& url) { 20819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!base_fetcher_active_) << "BeginTransfer but already active."; 21819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!pending_transfer_ended_) << "BeginTransfer but pending."; 22819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!terminating_) << "BeginTransfer but terminating."; 23819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 24819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (ranges_.empty()) { 25819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 26819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 27819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferComplete(this, true); 28819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 29819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 30819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes url_ = url; 31819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_ = 0; 32819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 33819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "starting first transfer"; 34819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->set_delegate(this); 35819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes StartTransfer(); 36819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 37819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 38819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading -> Pending transfer ended 399bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::TerminateTransfer() { 40819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (!base_fetcher_active_) { 41819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Called TerminateTransfer but not active."; 42819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 43819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 44819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferTerminated(this); 45819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 46819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 47819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes terminating_ = true; 48d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko 49819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (!pending_transfer_ended_) { 50819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->TerminateTransfer(); 51819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 52819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 53819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 54819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Stopped or Downloading -> Downloading 559bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::StartTransfer() { 56819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (current_index_ >= ranges_.size()) { 57819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 58819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 59e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold 60e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold Range range = ranges_[current_index_]; 61e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold LOG(INFO) << "starting transfer of range " << range.ToString(); 62e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold 63819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 64e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold base_fetcher_->SetOffset(range.offset()); 65e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (range.HasLength()) 66e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold base_fetcher_->SetLength(range.length()); 67e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold else 68e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold base_fetcher_->UnsetLength(); 69819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 70e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold delegate_->SeekToOffset(range.offset()); 71819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_active_ = true; 72819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->BeginTransfer(url_); 73819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 74819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 75819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading -> Downloading or Pending transfer ended 769bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::ReceivedBytes(HttpFetcher* fetcher, 77f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko const void* bytes, 78f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko size_t length) { 79819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_LT(current_index_, ranges_.size()); 80819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_EQ(fetcher, base_fetcher_.get()); 81819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!pending_transfer_ended_); 82e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold size_t next_size = length; 83e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold Range range = ranges_[current_index_]; 84e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (range.HasLength()) { 85819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes next_size = std::min(next_size, 86e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold range.length() - bytes_received_this_range_); 87819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 88819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG_IF(WARNING, next_size <= 0) << "Asked to write length <= 0"; 89819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) { 90819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->ReceivedBytes(this, bytes, next_size); 91819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 92819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ += length; 93e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (range.HasLength() && bytes_received_this_range_ >= range.length()) { 94819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Terminates the current fetcher. Waits for its TransferTerminated 95819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // callback before starting the next range so that we don't end up 96819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // signalling the delegate that the whole multi-transfer is complete 97819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // before all fetchers are really done and cleaned up. 98819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes pending_transfer_ended_ = true; 99819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "terminating transfer"; 100819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes fetcher->TerminateTransfer(); 101819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 102819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 103819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 104819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading or Pending transfer ended -> Stopped 1059bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::TransferEnded(HttpFetcher* fetcher, 106819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bool successful) { 107819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(base_fetcher_active_) << "Transfer ended unexpectedly."; 108819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_EQ(fetcher, base_fetcher_.get()); 109819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes pending_transfer_ended_ = false; 110819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes http_response_code_ = fetcher->http_response_code(); 111819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "TransferEnded w/ code " << http_response_code_; 112819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (terminating_) { 113819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Terminating."; 114819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 115819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 116819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 117819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferTerminated(this); 118819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 119819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 120819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 121819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // If we didn't get enough bytes, it's failure 122e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold Range range = ranges_[current_index_]; 123e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (range.HasLength()) { 124e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (bytes_received_this_range_ < range.length()) { 125819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Failure 126819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Didn't get enough bytes. Ending w/ failure."; 127819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 128819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 129819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 130819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferComplete(this, false); 131819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 132819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 133819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // We got enough bytes and there were bytes specified, so this is success. 134819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes successful = true; 135819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 136819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 137ffcb6d16938fb1c91be4f55abc3ad3da109c1044Andrew de los Reyes // If we have another transfer, do that. 138819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (current_index_ + 1 < ranges_.size()) { 139819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_++; 140819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Starting next transfer (" << current_index_ << ")."; 141819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes StartTransfer(); 142819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 143819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 144819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 145819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Done w/ all transfers"; 146819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 147819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 148819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 149819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferComplete(this, successful); 150819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 151819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 1529bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::TransferComplete(HttpFetcher* fetcher, 153819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bool successful) { 154819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Received transfer complete."; 155819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes TransferEnded(fetcher, successful); 156819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 157819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 1589bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::TransferTerminated(HttpFetcher* fetcher) { 159819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Received transfer terminated."; 160819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes TransferEnded(fetcher, false); 161819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 162819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 1639bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::Reset() { 164819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_active_ = pending_transfer_ended_ = terminating_ = false; 165819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_ = 0; 166819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 167819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 168819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 169e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnoldstd::string MultiRangeHttpFetcher::Range::ToString() const { 17075039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko std::string range_str = base::StringPrintf("%jd+", offset()); 171e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (HasLength()) 172e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold base::StringAppendF(&range_str, "%zu", length()); 173e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold else 174e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold base::StringAppendF(&range_str, "?"); 175e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold return range_str; 176e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold} 177e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold 178819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} // namespace chromeos_update_engine 179