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