[go: nahoru, domu]

blob: caafba71e86642e24ade1d3954dd587138f768ba [file] [log] [blame]
Avi Drissman64595482022-09-14 20:52:291// Copyright 2012 The Chromium Authors
rvargas@google.com8bf26f49a2009-06-12 17:35:502// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/http/partial_data.h"
6
avid0181f32015-12-10 19:41:477#include <limits>
Bence Béky74838e52018-08-03 19:25:238#include <utility>
avid0181f32015-12-10 19:41:479
evan@chromium.org34b2b002009-11-20 06:53:2810#include "base/format_macros.h"
Avi Drissman41c4a412023-01-11 22:45:3711#include "base/functional/bind.h"
12#include "base/functional/callback_helpers.h"
rvargas@google.com8bf26f49a2009-06-12 17:35:5013#include "base/logging.h"
avi@chromium.org125ef482013-06-11 18:32:4714#include "base/strings/string_number_conversions.h"
15#include "base/strings/string_util.h"
16#include "base/strings/stringprintf.h"
rvargas@google.com8bf26f49a2009-06-12 17:35:5017#include "net/base/net_errors.h"
18#include "net/disk_cache/disk_cache.h"
rvargas@google.com95792eb12009-06-22 21:30:4019#include "net/http/http_response_headers.h"
Feifei Wanged3689f2022-05-29 23:35:3820#include "net/http/http_status_code.h"
rvargas@google.com8bf26f49a2009-06-12 17:35:5021#include "net/http/http_util.h"
22
willchan@chromium.org8c76ae22010-04-20 22:15:4323namespace net {
24
rvargas@google.com95792eb12009-06-22 21:30:4025namespace {
26
27// The headers that we have to process.
28const char kLengthHeader[] = "Content-Length";
29const char kRangeHeader[] = "Content-Range";
rvargas@google.come5dad132009-08-18 00:53:4130const int kDataStream = 1;
rvargas@google.com95792eb12009-06-22 21:30:4031
willchan@chromium.org8c76ae22010-04-20 22:15:4332} // namespace
rvargas@google.com8bf26f49a2009-06-12 17:35:5033
Tsuyoshi Horo11e321eb2022-06-07 07:56:4034PartialData::PartialData() = default;
erg@google.comb104b502010-10-18 20:21:3135
Chris Watkins7a41d3552017-12-01 02:13:2736PartialData::~PartialData() = default;
rvargas@google.com034740a2010-06-11 17:16:4837
willchan@chromium.org8c76ae22010-04-20 22:15:4338bool PartialData::Init(const HttpRequestHeaders& headers) {
39 std::string range_header;
Maks Orlovich70039f12018-11-07 18:52:5740 if (!headers.GetHeader(HttpRequestHeaders::kRange, &range_header)) {
41 range_requested_ = false;
willchan@chromium.org8c76ae22010-04-20 22:15:4342 return false;
Maks Orlovich70039f12018-11-07 18:52:5743 }
44 range_requested_ = true;
willchan@chromium.org8c76ae22010-04-20 22:15:4345
rvargas@google.com8bf26f49a2009-06-12 17:35:5046 std::vector<HttpByteRange> ranges;
willchan@chromium.org8c76ae22010-04-20 22:15:4347 if (!HttpUtil::ParseRangeHeader(range_header, &ranges) || ranges.size() != 1)
rvargas@google.com8bf26f49a2009-06-12 17:35:5048 return false;
49
50 // We can handle this range request.
51 byte_range_ = ranges[0];
Maks Orlovich8e48d242023-04-25 18:44:2652 user_byte_range_ = byte_range_;
rvargas@google.com8bf26f49a2009-06-12 17:35:5053 if (!byte_range_.IsValid())
54 return false;
55
rvargas@google.com8bf26f49a2009-06-12 17:35:5056 current_range_start_ = byte_range_.first_byte_position();
rvargas@google.coma5c9d982010-10-12 20:48:0257
58 DVLOG(1) << "Range start: " << current_range_start_ << " end: " <<
59 byte_range_.last_byte_position();
rvargas@google.com8bf26f49a2009-06-12 17:35:5060 return true;
61}
62
willchan@chromium.org8c76ae22010-04-20 22:15:4363void PartialData::SetHeaders(const HttpRequestHeaders& headers) {
64 DCHECK(extra_headers_.IsEmpty());
Adam Rice6104cc5b2023-10-05 08:34:1665 extra_headers_ = headers;
rvargas@google.come75e8af2009-11-03 00:04:2066}
67
willchan@chromium.org8c76ae22010-04-20 22:15:4368void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const {
rvargas@google.com67fe45c2009-06-24 17:44:5769 DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange());
avid0181f32015-12-10 19:41:4770 int64_t end = byte_range_.IsSuffixByteRange()
71 ? byte_range_.suffix_length()
72 : byte_range_.last_byte_position();
rvargas@google.com8bf26f49a2009-06-12 17:35:5073
Adam Rice6104cc5b2023-10-05 08:34:1674 *headers = extra_headers_;
tommycli@chromium.orgb7572ea2013-11-26 20:16:3875 if (truncated_ || !byte_range_.IsValid())
76 return;
77
78 if (current_range_start_ < 0) {
79 headers->SetHeader(HttpRequestHeaders::kRange,
80 HttpByteRange::Suffix(end).GetHeaderValue());
81 } else {
82 headers->SetHeader(HttpRequestHeaders::kRange,
83 HttpByteRange::Bounded(
84 current_range_start_, end).GetHeaderValue());
85 }
rvargas@google.com8bf26f49a2009-06-12 17:35:5086}
87
rvargas@google.com034740a2010-06-11 17:16:4888int PartialData::ShouldValidateCache(disk_cache::Entry* entry,
Bence Békya4a50932018-08-10 13:39:4189 CompletionOnceCallback callback) {
rvargas@google.com034740a2010-06-11 17:16:4890 DCHECK_GE(current_range_start_, 0);
rvargas@google.com8bf26f49a2009-06-12 17:35:5091
92 // Scan the disk cache for the first cached portion within this range.
rvargas@google.com034740a2010-06-11 17:16:4893 int len = GetNextRangeLen();
rvargas@google.com8bf26f49a2009-06-12 17:35:5094 if (!len)
95 return 0;
rvargas@google.com8bf26f49a2009-06-12 17:35:5096
rvargas@google.coma5c9d982010-10-12 20:48:0297 DVLOG(3) << "ShouldValidateCache len: " << len;
98
rvargas@google.come5dad132009-08-18 00:53:4199 if (sparse_entry_) {
jhawkins@chromium.org49639fa2011-12-20 23:22:41100 DCHECK(callback_.is_null());
Maks Orlovich04cd1ad2021-07-02 17:32:24101 disk_cache::RangeResultCallback cb = base::BindOnce(
102 &PartialData::GetAvailableRangeCompleted, weak_factory_.GetWeakPtr());
103 disk_cache::RangeResult range =
104 entry->GetAvailableRange(current_range_start_, len, std::move(cb));
rvargas@google.com034740a2010-06-11 17:16:48105
Maks Orlovich04cd1ad2021-07-02 17:32:24106 cached_min_len_ =
107 range.net_error == OK ? range.available_len : range.net_error;
rvargas@google.com034740a2010-06-11 17:16:48108 if (cached_min_len_ == ERR_IO_PENDING) {
Bence Békya4a50932018-08-10 13:39:41109 callback_ = std::move(callback);
rvargas@google.com034740a2010-06-11 17:16:48110 return ERR_IO_PENDING;
hubbe6cad67c2015-07-09 19:01:02111 } else {
Maks Orlovich04cd1ad2021-07-02 17:32:24112 cached_start_ = range.start;
rvargas@google.com034740a2010-06-11 17:16:48113 }
rvargas@google.com634739b2011-03-02 18:08:25114 } else if (!truncated_) {
rvargas@google.coma5c9d982010-10-12 20:48:02115 if (byte_range_.HasFirstBytePosition() &&
116 byte_range_.first_byte_position() >= resource_size_) {
117 // The caller should take care of this condition because we should have
118 // failed IsRequestedRangeOK(), but it's better to be consistent here.
119 len = 0;
120 }
rvargas@google.come5dad132009-08-18 00:53:41121 cached_min_len_ = len;
122 cached_start_ = current_range_start_;
123 }
124
rvargas@google.com034740a2010-06-11 17:16:48125 if (cached_min_len_ < 0)
rvargas@google.com8bf26f49a2009-06-12 17:35:50126 return cached_min_len_;
rvargas@google.com034740a2010-06-11 17:16:48127
128 // Return a positive number to indicate success (versus error or finished).
129 return 1;
130}
131
132void PartialData::PrepareCacheValidation(disk_cache::Entry* entry,
133 HttpRequestHeaders* headers) {
134 DCHECK_GE(current_range_start_, 0);
135 DCHECK_GE(cached_min_len_, 0);
136
137 int len = GetNextRangeLen();
Maks Orlovich8e48d242023-04-25 18:44:26138 if (!len) {
139 // Stored body is empty, so just use the original range header.
140 headers->SetHeader(HttpRequestHeaders::kRange,
141 user_byte_range_.GetHeaderValue());
142 return;
143 }
rvargas@google.com034740a2010-06-11 17:16:48144 range_present_ = false;
rvargas@google.com8bf26f49a2009-06-12 17:35:50145
Adam Rice6104cc5b2023-10-05 08:34:16146 *headers = extra_headers_;
rvargas@google.com8bf26f49a2009-06-12 17:35:50147
148 if (!cached_min_len_) {
149 // We don't have anything else stored.
150 final_range_ = true;
rvargas@google.com28accfe2009-09-04 23:36:33151 cached_start_ =
152 byte_range_.HasLastBytePosition() ? current_range_start_ + len : 0;
rvargas@google.com8bf26f49a2009-06-12 17:35:50153 }
154
155 if (current_range_start_ == cached_start_) {
156 // The data lives in the cache.
157 range_present_ = true;
rvargas3b57e37a2015-01-06 00:56:34158 current_range_end_ = cached_start_ + cached_min_len_ - 1;
rvargas@google.com8bf26f49a2009-06-12 17:35:50159 if (len == cached_min_len_)
160 final_range_ = true;
rvargas@google.com8bf26f49a2009-06-12 17:35:50161 } else {
162 // This range is not in the cache.
rvargas3b57e37a2015-01-06 00:56:34163 current_range_end_ = cached_start_ - 1;
rvargas@google.com8bf26f49a2009-06-12 17:35:50164 }
hubbe70fbde6a2015-07-08 19:24:14165 headers->SetHeader(
166 HttpRequestHeaders::kRange,
167 HttpByteRange::Bounded(current_range_start_, current_range_end_)
168 .GetHeaderValue());
rvargas@google.com8bf26f49a2009-06-12 17:35:50169}
170
171bool PartialData::IsCurrentRangeCached() const {
172 return range_present_;
173}
174
175bool PartialData::IsLastRange() const {
176 return final_range_;
177}
178
rvargas@google.com44f873a62009-08-12 00:14:48179bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers,
rvargas@google.com28accfe2009-09-04 23:36:33180 disk_cache::Entry* entry,
Maks Orlovichd19c8272018-03-23 15:27:05181 bool truncated,
182 bool writing_in_progress) {
rvargas@google.com67fe45c2009-06-24 17:44:57183 resource_size_ = 0;
rvargas@google.com28accfe2009-09-04 23:36:33184 if (truncated) {
185 DCHECK_EQ(headers->response_code(), 200);
rvargas@google.com28accfe2009-09-04 23:36:33186 // We don't have the real length and the user may be trying to create a
187 // sparse entry so let's not write to this entry.
188 if (byte_range_.IsValid())
189 return false;
190
rvargas@google.com9f03cb7a2012-07-30 23:15:20191 if (!headers->HasStrongValidators())
192 return false;
193
rvargas@google.comdbd39fb2010-01-08 01:13:36194 // Now we avoid resume if there is no content length, but that was not
195 // always the case so double check here.
avid0181f32015-12-10 19:41:47196 int64_t total_length = headers->GetContentLength();
rvargas@google.combd069d72011-05-19 01:11:11197 if (total_length <= 0)
rvargas@google.comdbd39fb2010-01-08 01:13:36198 return false;
199
Maks Orlovich332bb11a2018-03-17 01:43:32200 // In case we see a truncated entry, we first send a network request for
201 // 1 byte range with If-Range: to probe server support for resumption.
202 // The setting of |current_range_start_| and |cached_start_| below (with any
203 // positive value of |cached_min_len_|) results in that.
204 //
205 // Setting |initial_validation_| to true is how this communicates to
206 // HttpCache::Transaction that we're doing that (and that it's not the user
207 // asking for one byte), so if it sees a 206 with that flag set it will call
208 // SetRangeToStartDownload(), and then restart the process looking for the
209 // entire file (which is what the user wanted), with the cache handling
210 // the previous portion, and then a second network request for the entire
211 // rest of the range. A 200 in response to the probe request can be simply
212 // returned directly to the user.
hclam@chromium.orgecd8becb2009-10-02 17:57:45213 truncated_ = true;
rvargas@google.com634739b2011-03-02 18:08:25214 initial_validation_ = true;
hclam@chromium.orgecd8becb2009-10-02 17:57:45215 sparse_entry_ = false;
rvargas@google.com634739b2011-03-02 18:08:25216 int current_len = entry->GetDataSize(kDataStream);
217 byte_range_.set_first_byte_position(current_len);
rvargas@google.comdbd39fb2010-01-08 01:13:36218 resource_size_ = total_length;
rvargas@google.com634739b2011-03-02 18:08:25219 current_range_start_ = current_len;
220 cached_min_len_ = current_len;
221 cached_start_ = current_len + 1;
rvargas@google.com28accfe2009-09-04 23:36:33222 return true;
223 }
224
Feifei Wanged3689f2022-05-29 23:35:38225 sparse_entry_ = (headers->response_code() == net::HTTP_PARTIAL_CONTENT);
Maks Orlovichd19c8272018-03-23 15:27:05226
227 if (writing_in_progress || sparse_entry_) {
228 // |writing_in_progress| means another Transaction is still fetching the
229 // body, so the only way we can see the length is if the server sent it
230 // in Content-Length -- GetDataSize would just return what got written
231 // thus far.
232 //
233 // |sparse_entry_| means a 206, and for those FixContentLength arranges it
234 // so that Content-Length written to the cache has the full length (on wire
235 // it's for a particular range only); while GetDataSize would be unusable
236 // since the data is stored using WriteSparseData, and not in the usual data
237 // stream.
238 resource_size_ = headers->GetContentLength();
239 if (resource_size_ <= 0)
240 return false;
241 } else {
242 // If we can safely use GetDataSize, it's preferrable since it's usable for
243 // things w/o Content-Length, such as chunked content.
rvargas@google.come5dad132009-08-18 00:53:41244 resource_size_ = entry->GetDataSize(kDataStream);
rvargas@google.come5dad132009-08-18 00:53:41245 }
246
Maks Orlovichd19c8272018-03-23 15:27:05247 DVLOG(2) << "UpdateFromStoredHeaders size: " << resource_size_;
rvargas43dc8fd2015-01-07 23:03:25248
Maks Orlovichd19c8272018-03-23 15:27:05249 if (sparse_entry_) {
250 // If our previous is a 206, we need strong validators as we may be
251 // stiching the cached data and network data together.
252 if (!headers->HasStrongValidators())
253 return false;
254 // Make sure that this is really a sparse entry.
255 return entry->CouldBeSparse();
256 }
257 return true;
rvargas@google.come5dad132009-08-18 00:53:41258}
259
rvargas@google.com634739b2011-03-02 18:08:25260void PartialData::SetRangeToStartDownload() {
261 DCHECK(truncated_);
262 DCHECK(!sparse_entry_);
263 current_range_start_ = 0;
264 cached_start_ = 0;
265 initial_validation_ = false;
266}
267
rvargas@google.come5dad132009-08-18 00:53:41268bool PartialData::IsRequestedRangeOK() {
rvargas@google.com44f873a62009-08-12 00:14:48269 if (byte_range_.IsValid()) {
270 if (!byte_range_.ComputeBounds(resource_size_))
271 return false;
rvargas@google.com634739b2011-03-02 18:08:25272 if (truncated_)
273 return true;
rvargas@google.com67fe45c2009-06-24 17:44:57274
rvargas@google.com44f873a62009-08-12 00:14:48275 if (current_range_start_ < 0)
276 current_range_start_ = byte_range_.first_byte_position();
277 } else {
278 // This is not a range request but we have partial data stored.
279 current_range_start_ = 0;
280 byte_range_.set_last_byte_position(resource_size_ - 1);
281 }
282
rvargas@google.come5dad132009-08-18 00:53:41283 bool rv = current_range_start_ >= 0;
284 if (!rv)
285 current_range_start_ = 0;
rvargas@google.com67fe45c2009-06-24 17:44:57286
rvargas@google.come5dad132009-08-18 00:53:41287 return rv;
rvargas@google.com95792eb12009-06-22 21:30:40288}
289
290bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) {
Feifei Wanged3689f2022-05-29 23:35:38291 if (headers->response_code() == net::HTTP_NOT_MODIFIED) {
hclam@chromium.orgd9adff2c2009-09-05 01:15:45292 if (!byte_range_.IsValid() || truncated_)
rvargas@google.com28accfe2009-09-04 23:36:33293 return true;
294
rvargas@google.come5dad132009-08-18 00:53:41295 // We must have a complete range here.
296 return byte_range_.HasFirstBytePosition() &&
cbentzel@chromium.org2227c692010-05-04 15:36:11297 byte_range_.HasLastBytePosition();
rvargas@google.come5dad132009-08-18 00:53:41298 }
299
avid0181f32015-12-10 19:41:47300 int64_t start, end, total_length;
sclittled43b2fb2016-12-17 03:20:47301 if (!headers->GetContentRangeFor206(&start, &end, &total_length))
rvargas@google.com95792eb12009-06-22 21:30:40302 return false;
303 if (total_length <= 0)
304 return false;
305
rvargas@chromium.org9f10ec32013-11-01 00:51:53306 DCHECK_EQ(headers->response_code(), 206);
307
308 // A server should return a valid content length with a 206 (per the standard)
309 // but relax the requirement because some servers don't do that.
avid0181f32015-12-10 19:41:47310 int64_t content_length = headers->GetContentLength();
rvargas@chromium.org9f10ec32013-11-01 00:51:53311 if (content_length > 0 && content_length != end - start + 1)
rvargas@google.com7eab0d2262009-10-14 22:05:54312 return false;
313
rvargas@google.com95792eb12009-06-22 21:30:40314 if (!resource_size_) {
315 // First response. Update our values with the ones provided by the server.
316 resource_size_ = total_length;
rvargas@google.com67fe45c2009-06-24 17:44:57317 if (!byte_range_.HasFirstBytePosition()) {
rvargas@google.com95792eb12009-06-22 21:30:40318 byte_range_.set_first_byte_position(start);
rvargas@google.com67fe45c2009-06-24 17:44:57319 current_range_start_ = start;
320 }
rvargas@google.com95792eb12009-06-22 21:30:40321 if (!byte_range_.HasLastBytePosition())
322 byte_range_.set_last_byte_position(end);
323 } else if (resource_size_ != total_length) {
324 return false;
325 }
326
rvargas@google.comdbd39fb2010-01-08 01:13:36327 if (truncated_) {
328 if (!byte_range_.HasLastBytePosition())
329 byte_range_.set_last_byte_position(end);
330 }
331
rvargas@google.com95792eb12009-06-22 21:30:40332 if (start != current_range_start_)
333 return false;
334
rvargas3b57e37a2015-01-06 00:56:34335 if (!current_range_end_) {
336 // There is nothing in the cache.
337 DCHECK(byte_range_.HasLastBytePosition());
338 current_range_end_ = byte_range_.last_byte_position();
339 if (current_range_end_ >= resource_size_) {
340 // We didn't know the real file size, and the server is saying that the
341 // requested range goes beyond the size. Fix it.
342 current_range_end_ = end;
343 byte_range_.set_last_byte_position(end);
344 }
345 }
346
347 // If we received a range, but it's not exactly the range we asked for, avoid
348 // trouble and signal an error.
349 if (end != current_range_end_)
rvargas@google.com95792eb12009-06-22 21:30:40350 return false;
351
352 return true;
353}
354
355// We are making multiple requests to complete the range requested by the user.
356// Just assume that everything is fine and say that we are returning what was
357// requested.
rvargas@google.coma5c9d982010-10-12 20:48:02358void PartialData::FixResponseHeaders(HttpResponseHeaders* headers,
359 bool success) {
rvargas@google.com28accfe2009-09-04 23:36:33360 if (truncated_)
361 return;
362
Maks Orlovich4b3edfc2023-04-25 17:21:08363 if (!success) {
kinuko@chromium.org3d47dac9622014-03-10 07:28:58364 headers->ReplaceStatusLine("HTTP/1.1 416 Requested Range Not Satisfiable");
Matt Menke73ed38f2020-04-10 21:29:11365 headers->SetHeader(
366 kRangeHeader, base::StringPrintf("bytes 0-0/%" PRId64, resource_size_));
367 headers->SetHeader(kLengthHeader, "0");
Maks Orlovich4b3edfc2023-04-25 17:21:08368 return;
369 }
370
371 if (byte_range_.IsValid() && resource_size_) {
372 headers->UpdateWithNewRange(byte_range_, resource_size_, !sparse_entry_);
rvargas@google.com44f873a62009-08-12 00:14:48373 } else {
Maks Orlovich4b3edfc2023-04-25 17:21:08374 if (headers->response_code() == net::HTTP_PARTIAL_CONTENT) {
375 // TODO(rvargas): Is it safe to change the protocol version?
376 headers->ReplaceStatusLine("HTTP/1.1 200 OK");
377 }
Matt Menke73ed38f2020-04-10 21:29:11378 headers->RemoveHeader(kRangeHeader);
379 headers->SetHeader(kLengthHeader,
380 base::StringPrintf("%" PRId64, resource_size_));
rvargas@google.com44f873a62009-08-12 00:14:48381 }
rvargas@google.com95792eb12009-06-22 21:30:40382}
383
384void PartialData::FixContentLength(HttpResponseHeaders* headers) {
Matt Menke73ed38f2020-04-10 21:29:11385 headers->SetHeader(kLengthHeader,
386 base::StringPrintf("%" PRId64, resource_size_));
rvargas@google.com95792eb12009-06-22 21:30:40387}
388
ttuttle859dc7a2015-04-23 19:42:29389int PartialData::CacheRead(disk_cache::Entry* entry,
390 IOBuffer* data,
391 int data_len,
Bence Békya4a50932018-08-10 13:39:41392 CompletionOnceCallback callback) {
rvargas@google.com8bf26f49a2009-06-12 17:35:50393 int read_len = std::min(data_len, cached_min_len_);
hclam@chromium.org8f28d632009-10-01 22:09:21394 if (!read_len)
395 return 0;
396
rvargas@google.come5dad132009-08-18 00:53:41397 int rv = 0;
398 if (sparse_entry_) {
399 rv = entry->ReadSparseData(current_range_start_, data, read_len,
Bence Békya4a50932018-08-10 13:39:41400 std::move(callback));
rvargas@google.come5dad132009-08-18 00:53:41401 } else {
avid0181f32015-12-10 19:41:47402 if (current_range_start_ > std::numeric_limits<int32_t>::max())
rvargas@google.come5dad132009-08-18 00:53:41403 return ERR_INVALID_ARGUMENT;
404
405 rv = entry->ReadData(kDataStream, static_cast<int>(current_range_start_),
Bence Békya4a50932018-08-10 13:39:41406 data, read_len, std::move(callback));
rvargas@google.come5dad132009-08-18 00:53:41407 }
rvargas@google.com8bf26f49a2009-06-12 17:35:50408 return rv;
409}
410
ttuttle859dc7a2015-04-23 19:42:29411int PartialData::CacheWrite(disk_cache::Entry* entry,
412 IOBuffer* data,
413 int data_len,
Bence Békya4a50932018-08-10 13:39:41414 CompletionOnceCallback callback) {
rvargas@google.coma5c9d982010-10-12 20:48:02415 DVLOG(3) << "To write: " << data_len;
rvargas@google.come5dad132009-08-18 00:53:41416 if (sparse_entry_) {
Bence Békya4a50932018-08-10 13:39:41417 return entry->WriteSparseData(current_range_start_, data, data_len,
418 std::move(callback));
rvargas@google.come5dad132009-08-18 00:53:41419 } else {
avid0181f32015-12-10 19:41:47420 if (current_range_start_ > std::numeric_limits<int32_t>::max())
rvargas@google.come5dad132009-08-18 00:53:41421 return ERR_INVALID_ARGUMENT;
422
423 return entry->WriteData(kDataStream, static_cast<int>(current_range_start_),
Bence Békya4a50932018-08-10 13:39:41424 data, data_len, std::move(callback), true);
rvargas@google.come5dad132009-08-18 00:53:41425 }
rvargas@google.com8bf26f49a2009-06-12 17:35:50426}
427
428void PartialData::OnCacheReadCompleted(int result) {
rvargas@google.coma5c9d982010-10-12 20:48:02429 DVLOG(3) << "Read: " << result;
rvargas@google.com8bf26f49a2009-06-12 17:35:50430 if (result > 0) {
431 current_range_start_ += result;
432 cached_min_len_ -= result;
rvargas@google.com034740a2010-06-11 17:16:48433 DCHECK_GE(cached_min_len_, 0);
rvargas@google.com8bf26f49a2009-06-12 17:35:50434 }
435}
436
437void PartialData::OnNetworkReadCompleted(int result) {
438 if (result > 0)
439 current_range_start_ += result;
440}
441
rvargas@google.com034740a2010-06-11 17:16:48442int PartialData::GetNextRangeLen() {
Maks Orlovich4b3edfc2023-04-25 17:21:08443 if (!resource_size_) {
444 return 0;
445 }
avid0181f32015-12-10 19:41:47446 int64_t range_len =
447 byte_range_.HasLastBytePosition()
448 ? byte_range_.last_byte_position() - current_range_start_ + 1
449 : std::numeric_limits<int32_t>::max();
450 if (range_len > std::numeric_limits<int32_t>::max())
451 range_len = std::numeric_limits<int32_t>::max();
452 return static_cast<int32_t>(range_len);
rvargas@google.com034740a2010-06-11 17:16:48453}
454
Maks Orlovich04cd1ad2021-07-02 17:32:24455void PartialData::GetAvailableRangeCompleted(
456 const disk_cache::RangeResult& result) {
jhawkins@chromium.org49639fa2011-12-20 23:22:41457 DCHECK(!callback_.is_null());
Maks Orlovich04cd1ad2021-07-02 17:32:24458 DCHECK_NE(ERR_IO_PENDING, result.net_error);
rvargas@google.com034740a2010-06-11 17:16:48459
Maks Orlovich04cd1ad2021-07-02 17:32:24460 int len_or_error =
461 result.net_error == OK ? result.available_len : result.net_error;
462 cached_start_ = result.start;
463 cached_min_len_ = len_or_error;
rvargas@google.com034740a2010-06-11 17:16:48464
Maks Orlovich04cd1ad2021-07-02 17:32:24465 // ShouldValidateCache has an unusual convention where 0 denotes EOF,
466 // so convert end of range to success (since there may be things that need
467 // fetching from network or other ranges).
468 std::move(callback_).Run(len_or_error >= 0 ? 1 : len_or_error);
rvargas@google.com034740a2010-06-11 17:16:48469}
470
rvargas@google.com8bf26f49a2009-06-12 17:35:50471} // namespace net