blob: 849ed32bc11d1ba8570a410edfcb45781448cdaa [file] [log] [blame]
Alex Deymoaea4c1c2015-08-19 20:24:43 -07001//
2// Copyright (C) 2010 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
Andrew de los Reyes819fef22010-12-17 11:33:58 -080016
Alex Deymo39910dc2015-11-09 17:04:30 -080017#ifndef UPDATE_ENGINE_COMMON_MULTI_RANGE_HTTP_FETCHER_H_
18#define UPDATE_ENGINE_COMMON_MULTI_RANGE_HTTP_FETCHER_H_
Andrew de los Reyes819fef22010-12-17 11:33:58 -080019
20#include <deque>
Ben Chan02f7c1d2014-10-18 15:18:02 -070021#include <memory>
Alex Vakulenkod2779df2014-06-16 13:19:00 -070022#include <string>
Andrew de los Reyes819fef22010-12-17 11:33:58 -080023#include <utility>
24#include <vector>
25
Alex Deymo39910dc2015-11-09 17:04:30 -080026#include "update_engine/common/http_fetcher.h"
Andrew de los Reyes819fef22010-12-17 11:33:58 -080027
28// This class is a simple wrapper around an HttpFetcher. The client
Gilad Arnold9bedeb52011-11-17 16:19:57 -080029// specifies a vector of byte ranges. MultiRangeHttpFetcher will fetch bytes
Andrew de los Reyes819fef22010-12-17 11:33:58 -080030// from those offsets, using the same bash fetcher for all ranges. Thus, the
Alex Vakulenko072359c2014-07-18 11:41:07 -070031// fetcher must support beginning a transfer after one has stopped. Pass -1
Andrew de los Reyes819fef22010-12-17 11:33:58 -080032// as a length to specify unlimited length. It really only would make sense
33// for the last range specified to have unlimited length, tho it is legal for
34// other entries to have unlimited length.
35
Gilad Arnold9bedeb52011-11-17 16:19:57 -080036// There are three states a MultiRangeHttpFetcher object will be in:
Andrew de los Reyes819fef22010-12-17 11:33:58 -080037// - Stopped (start state)
38// - Downloading
39// - Pending transfer ended
40// Various functions below that might change state indicate possible
41// state changes.
42
43namespace chromeos_update_engine {
44
Gilad Arnold9bedeb52011-11-17 16:19:57 -080045class MultiRangeHttpFetcher : public HttpFetcher, public HttpFetcherDelegate {
Andrew de los Reyes819fef22010-12-17 11:33:58 -080046 public:
47 // Takes ownership of the passed in fetcher.
Gilad Arnold9bedeb52011-11-17 16:19:57 -080048 explicit MultiRangeHttpFetcher(HttpFetcher* base_fetcher)
Kelvin Zhangc7a1d1f2022-07-29 13:36:29 -070049 : HttpFetcher(),
Andrew de los Reyes819fef22010-12-17 11:33:58 -080050 base_fetcher_(base_fetcher),
51 base_fetcher_active_(false),
52 pending_transfer_ended_(false),
53 terminating_(false),
54 current_index_(0),
55 bytes_received_this_range_(0) {}
Alex Deymo610277e2014-11-11 21:18:11 -080056 ~MultiRangeHttpFetcher() override {}
Andrew de los Reyes819fef22010-12-17 11:33:58 -080057
58 void ClearRanges() { ranges_.clear(); }
59
Gilad Arnolde4ad2502011-12-29 17:08:54 -080060 void AddRange(off_t offset, size_t size) {
Mike Frysinger0f9547d2012-02-16 12:11:37 -050061 CHECK_GT(size, static_cast<size_t>(0));
Gilad Arnolde4ad2502011-12-29 17:08:54 -080062 ranges_.push_back(Range(offset, size));
63 }
64
Amin Hassanib2689592019-01-13 17:04:28 -080065 void AddRange(off_t offset) { ranges_.push_back(Range(offset)); }
Andrew de los Reyes819fef22010-12-17 11:33:58 -080066
Alex Deymo610277e2014-11-11 21:18:11 -080067 // HttpFetcher overrides.
Sen Jiangba2213a2018-02-27 16:28:20 -080068 void SetOffset(off_t offset) override;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080069
Alex Deymo610277e2014-11-11 21:18:11 -080070 void SetLength(size_t length) override {} // unsupported
71 void UnsetLength() override {}
Gilad Arnolde4ad2502011-12-29 17:08:54 -080072
Andrew de los Reyes819fef22010-12-17 11:33:58 -080073 // Begins the transfer to the specified URL.
74 // State change: Stopped -> Downloading
75 // (corner case: Stopped -> Stopped for an empty request)
Alex Deymo610277e2014-11-11 21:18:11 -080076 void BeginTransfer(const std::string& url) override;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080077
78 // State change: Downloading -> Pending transfer ended
Alex Deymo610277e2014-11-11 21:18:11 -080079 void TerminateTransfer() override;
Andrew de los Reyes819fef22010-12-17 11:33:58 -080080
Alex Deymo6f10c5f2016-03-03 22:35:43 -080081 void SetHeader(const std::string& header_name,
82 const std::string& header_value) override {
83 base_fetcher_->SetHeader(header_name, header_value);
84 }
85
Jae Hoon Kim0ae8fe12019-06-26 14:32:50 -070086 bool GetHeader(const std::string& header_name,
87 std::string* header_value) const override {
88 return base_fetcher_->GetHeader(header_name, header_value);
89 }
90
Alex Deymo610277e2014-11-11 21:18:11 -080091 void Pause() override { base_fetcher_->Pause(); }
Andrew de los Reyes819fef22010-12-17 11:33:58 -080092
Alex Deymo610277e2014-11-11 21:18:11 -080093 void Unpause() override { base_fetcher_->Unpause(); }
Andrew de los Reyes819fef22010-12-17 11:33:58 -080094
95 // These functions are overloaded in LibcurlHttp fetcher for testing purposes.
Alex Deymo610277e2014-11-11 21:18:11 -080096 void set_idle_seconds(int seconds) override {
Andrew de los Reyes819fef22010-12-17 11:33:58 -080097 base_fetcher_->set_idle_seconds(seconds);
98 }
Alex Deymo610277e2014-11-11 21:18:11 -080099 void set_retry_seconds(int seconds) override {
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800100 base_fetcher_->set_retry_seconds(seconds);
101 }
Alex Deymo610277e2014-11-11 21:18:11 -0800102 // TODO(deymo): Determine if this method should be virtual in HttpFetcher so
103 // this call is sent to the base_fetcher_.
Kelvin Zhangc7a1d1f2022-07-29 13:36:29 -0700104 void SetProxies(const std::deque<std::string>& proxies) override {
105 HttpFetcher::SetProxies(proxies);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800106 base_fetcher_->SetProxies(proxies);
107 }
108
Alex Deymo610277e2014-11-11 21:18:11 -0800109 inline size_t GetBytesDownloaded() override {
Gilad Arnold48085ba2011-11-16 09:36:08 -0800110 return base_fetcher_->GetBytesDownloaded();
111 }
112
Alex Deymo610277e2014-11-11 21:18:11 -0800113 void set_low_speed_limit(int low_speed_bps, int low_speed_sec) override {
David Zeuthen34135a92013-08-06 11:16:16 -0700114 base_fetcher_->set_low_speed_limit(low_speed_bps, low_speed_sec);
115 }
116
Alex Deymo610277e2014-11-11 21:18:11 -0800117 void set_connect_timeout(int connect_timeout_seconds) override {
David Zeuthen34135a92013-08-06 11:16:16 -0700118 base_fetcher_->set_connect_timeout(connect_timeout_seconds);
119 }
120
Alex Deymo610277e2014-11-11 21:18:11 -0800121 void set_max_retry_count(int max_retry_count) override {
David Zeuthen34135a92013-08-06 11:16:16 -0700122 base_fetcher_->set_max_retry_count(max_retry_count);
123 }
124
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800125 private:
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800126 // A range object defining the offset and length of a download chunk. Zero
127 // length indicates an unspecified end offset (note that it is impossible to
128 // request a zero-length range in HTTP).
129 class Range {
130 public:
131 Range(off_t offset, size_t length) : offset_(offset), length_(length) {}
Alex Vakulenkod2779df2014-06-16 13:19:00 -0700132 explicit Range(off_t offset) : offset_(offset), length_(0) {}
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800133
134 inline off_t offset() const { return offset_; }
135 inline size_t length() const { return length_; }
136
137 inline bool HasLength() const { return (length_ > 0); }
138
139 std::string ToString() const;
140
141 private:
142 off_t offset_;
143 size_t length_;
144 };
145
146 typedef std::vector<Range> RangesVect;
Jay Srinivasan43488792012-06-19 00:25:31 -0700147
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800148 // State change: Stopped or Downloading -> Downloading
149 void StartTransfer();
150
Alex Deymo610277e2014-11-11 21:18:11 -0800151 // HttpFetcherDelegate overrides.
Jay Srinivasan43488792012-06-19 00:25:31 -0700152 // State change: Downloading -> Downloading or Pending transfer ended
Amin Hassani0cd9d772018-07-31 23:55:43 -0700153 bool ReceivedBytes(HttpFetcher* fetcher,
Alex Vakulenkof68bbbc2015-02-09 12:53:18 -0800154 const void* bytes,
155 size_t length) override;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800156
157 // State change: Pending transfer ended -> Stopped
158 void TransferEnded(HttpFetcher* fetcher, bool successful);
159 // These two call TransferEnded():
Alex Deymo610277e2014-11-11 21:18:11 -0800160 void TransferComplete(HttpFetcher* fetcher, bool successful) override;
161 void TransferTerminated(HttpFetcher* fetcher) override;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800162
163 void Reset();
164
Ben Chan02f7c1d2014-10-18 15:18:02 -0700165 std::unique_ptr<HttpFetcher> base_fetcher_;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800166
167 // If true, do not send any more data or TransferComplete to the delegate.
168 bool base_fetcher_active_;
169
170 // If true, the next fetcher needs to be started when TransferTerminated is
171 // received from the current fetcher.
172 bool pending_transfer_ended_;
Jay Srinivasan43488792012-06-19 00:25:31 -0700173
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800174 // True if we are waiting for base fetcher to terminate b/c we are
175 // ourselves terminating.
176 bool terminating_;
177
178 RangesVect ranges_;
179
180 RangesVect::size_type current_index_; // index into ranges_
Gilad Arnolde4ad2502011-12-29 17:08:54 -0800181 size_t bytes_received_this_range_;
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800182
Gilad Arnold9bedeb52011-11-17 16:19:57 -0800183 DISALLOW_COPY_AND_ASSIGN(MultiRangeHttpFetcher);
Andrew de los Reyes819fef22010-12-17 11:33:58 -0800184};
185
186} // namespace chromeos_update_engine
187
Alex Deymo39910dc2015-11-09 17:04:30 -0800188#endif // UPDATE_ENGINE_COMMON_MULTI_RANGE_HTTP_FETCHER_H_