1aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 2aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Copyright (C) 2010 The Android Open Source Project 3aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 4aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Licensed under the Apache License, Version 2.0 (the "License"); 5aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// you may not use this file except in compliance with the License. 6aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// You may obtain a copy of the License at 7aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 8aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// http://www.apache.org/licenses/LICENSE-2.0 9aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 10aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// Unless required by applicable law or agreed to in writing, software 11aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// distributed under the License is distributed on an "AS IS" BASIS, 12aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// See the License for the specific language governing permissions and 14aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// limitations under the License. 15aea4c1cea20dda7ae7e85fc8924a2d784f70d806Alex Deymo// 16819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 1739910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/multi_range_http_fetcher.h" 18aab50e31f0b80ed53a9b8d5dbabcf943974bd32cAlex Deymo 1975039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko#include <base/strings/stringprintf.h> 20819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 21d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko#include <algorithm> 22d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko#include <string> 23d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko 2439910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h" 25819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 26819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyesnamespace chromeos_update_engine { 27819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 28819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// Begins the transfer to the specified URL. 29819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Stopped -> Downloading 30819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// (corner case: Stopped -> Stopped for an empty request) 319bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::BeginTransfer(const std::string& url) { 32819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!base_fetcher_active_) << "BeginTransfer but already active."; 33819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!pending_transfer_ended_) << "BeginTransfer but pending."; 34819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!terminating_) << "BeginTransfer but terminating."; 35819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 36819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (ranges_.empty()) { 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_->TransferComplete(this, true); 40819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 41819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 42819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes url_ = url; 43819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_ = 0; 44819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 45819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "starting first transfer"; 46819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->set_delegate(this); 47819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes StartTransfer(); 48819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 49819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 50819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading -> Pending transfer ended 519bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::TerminateTransfer() { 52819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (!base_fetcher_active_) { 53819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Called TerminateTransfer but not active."; 54819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 55819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 56819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferTerminated(this); 57819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 58819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 59819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes terminating_ = true; 60d2779df63aaad8b65fc5d4badee7dbc9bed7f2b6Alex Vakulenko 61819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (!pending_transfer_ended_) { 62819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->TerminateTransfer(); 63819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 64819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 65819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 66819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Stopped or Downloading -> Downloading 679bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::StartTransfer() { 68819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (current_index_ >= ranges_.size()) { 69819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 70819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 71e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold 72e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold Range range = ranges_[current_index_]; 73e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold LOG(INFO) << "starting transfer of range " << range.ToString(); 74e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold 75819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 76e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold base_fetcher_->SetOffset(range.offset()); 77e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (range.HasLength()) 78e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold base_fetcher_->SetLength(range.length()); 79e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold else 80e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold base_fetcher_->UnsetLength(); 81819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 82e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold delegate_->SeekToOffset(range.offset()); 83819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_active_ = true; 84819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_->BeginTransfer(url_); 85819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 86819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 87819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading -> Downloading or Pending transfer ended 889bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::ReceivedBytes(HttpFetcher* fetcher, 89f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko const void* bytes, 90f68bbbc952aa9a71898e4939b5f36187fa564a50Alex Vakulenko size_t length) { 91819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_LT(current_index_, ranges_.size()); 92819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_EQ(fetcher, base_fetcher_.get()); 93819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(!pending_transfer_ended_); 94e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold size_t next_size = length; 95e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold Range range = ranges_[current_index_]; 96e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (range.HasLength()) { 97819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes next_size = std::min(next_size, 98e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold range.length() - bytes_received_this_range_); 99819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 100819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG_IF(WARNING, next_size <= 0) << "Asked to write length <= 0"; 101819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) { 102819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->ReceivedBytes(this, bytes, next_size); 103819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 104819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ += length; 105e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (range.HasLength() && bytes_received_this_range_ >= range.length()) { 106819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Terminates the current fetcher. Waits for its TransferTerminated 107819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // callback before starting the next range so that we don't end up 108819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // signalling the delegate that the whole multi-transfer is complete 109819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // before all fetchers are really done and cleaned up. 110819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes pending_transfer_ended_ = true; 111819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "terminating transfer"; 112819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes fetcher->TerminateTransfer(); 113819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 114819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 115819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 116819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes// State change: Downloading or Pending transfer ended -> Stopped 1179bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::TransferEnded(HttpFetcher* fetcher, 118819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bool successful) { 119819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK(base_fetcher_active_) << "Transfer ended unexpectedly."; 120819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes CHECK_EQ(fetcher, base_fetcher_.get()); 121819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes pending_transfer_ended_ = false; 122819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes http_response_code_ = fetcher->http_response_code(); 123819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "TransferEnded w/ code " << http_response_code_; 124819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (terminating_) { 125819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Terminating."; 126819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 127819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 128819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 129819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferTerminated(this); 130819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 131819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 132819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 133819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // If we didn't get enough bytes, it's failure 134e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold Range range = ranges_[current_index_]; 135e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (range.HasLength()) { 136e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (bytes_received_this_range_ < range.length()) { 137819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Failure 138819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Didn't get enough bytes. Ending w/ failure."; 139819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 140819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 141819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 142819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferComplete(this, false); 143819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 144819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 145819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // We got enough bytes and there were bytes specified, so this is success. 146819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes successful = true; 147819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 148819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 149ffcb6d16938fb1c91be4f55abc3ad3da109c1044Andrew de los Reyes // If we have another transfer, do that. 150819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (current_index_ + 1 < ranges_.size()) { 151819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_++; 152819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Starting next transfer (" << current_index_ << ")."; 153819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes StartTransfer(); 154819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes return; 155819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes } 156819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 157819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Done w/ all transfers"; 158819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes Reset(); 159819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes // Note that after the callback returns this object may be destroyed. 160819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes if (delegate_) 161819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes delegate_->TransferComplete(this, successful); 162819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 163819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 1649bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::TransferComplete(HttpFetcher* fetcher, 165819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bool successful) { 166819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Received transfer complete."; 167819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes TransferEnded(fetcher, successful); 168819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 169819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 1709bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::TransferTerminated(HttpFetcher* fetcher) { 171819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes LOG(INFO) << "Received transfer terminated."; 172819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes TransferEnded(fetcher, false); 173819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 174819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 1759bedeb51f80c9547269eef6c2ec09596033bb818Gilad Arnoldvoid MultiRangeHttpFetcher::Reset() { 176819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes base_fetcher_active_ = pending_transfer_ended_ = terminating_ = false; 177819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes current_index_ = 0; 178819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes bytes_received_this_range_ = 0; 179819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} 180819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes 181e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnoldstd::string MultiRangeHttpFetcher::Range::ToString() const { 18275039d7397f03dff77bdf4e26398049ff88edc4cAlex Vakulenko std::string range_str = base::StringPrintf("%jd+", offset()); 183e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold if (HasLength()) 184c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo range_str += std::to_string(length()); 185e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold else 186c00c98a1dad941e5cc04ce0b0e766d40b3b384e1Alex Deymo range_str += "?"; 187e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold return range_str; 188e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold} 189e4ad2508de4d69d7a90d3ce441efe2c82c55bd1dGilad Arnold 190819fef2e0fa08984cf31e848e704442c500ea4f9Andrew de los Reyes} // namespace chromeos_update_engine 191