[go: nahoru, domu]

blob: 7fc934f3c00cc967c359166883cae5b42111e195 [file] [log] [blame]
tbreisacher@chromium.org9987dd72012-01-25 23:40:041// Copyright (c) 2012 The Chromium Authors. All rights reserved.
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
jhawkins@chromium.org2a65aceb82011-12-19 20:59:277#include "base/bind.h"
8#include "base/bind_helpers.h"
evan@chromium.org34b2b002009-11-20 06:53:289#include "base/format_macros.h"
rvargas@google.com8bf26f49a2009-06-12 17:35:5010#include "base/logging.h"
avi@chromium.org125ef482013-06-11 18:32:4711#include "base/strings/string_number_conversions.h"
12#include "base/strings/string_util.h"
13#include "base/strings/stringprintf.h"
rvargas@google.com8bf26f49a2009-06-12 17:35:5014#include "net/base/net_errors.h"
15#include "net/disk_cache/disk_cache.h"
rvargas@google.com95792eb12009-06-22 21:30:4016#include "net/http/http_response_headers.h"
rvargas@google.com8bf26f49a2009-06-12 17:35:5017#include "net/http/http_util.h"
rvargas@google.com95792eb12009-06-22 21:30:4018
willchan@chromium.org8c76ae22010-04-20 22:15:4319namespace net {
20
rvargas@google.com95792eb12009-06-22 21:30:4021namespace {
22
23// The headers that we have to process.
24const char kLengthHeader[] = "Content-Length";
25const char kRangeHeader[] = "Content-Range";
rvargas@google.come5dad132009-08-18 00:53:4126const int kDataStream = 1;
rvargas@google.com95792eb12009-06-22 21:30:4027
willchan@chromium.org8c76ae22010-04-20 22:15:4328} // namespace
rvargas@google.com8bf26f49a2009-06-12 17:35:5029
rvargas@google.com034740a2010-06-11 17:16:4830// A core object that can be detached from the Partialdata object at destruction
31// so that asynchronous operations cleanup can be performed.
32class PartialData::Core {
33 public:
34 // Build a new core object. Lifetime management is automatic.
35 static Core* CreateCore(PartialData* owner) {
36 return new Core(owner);
37 }
38
39 // Wrapper for Entry::GetAvailableRange. If this method returns ERR_IO_PENDING
40 // PartialData::GetAvailableRangeCompleted() will be invoked on the owner
41 // object when finished (unless Cancel() is called first).
42 int GetAvailableRange(disk_cache::Entry* entry, int64 offset, int len,
43 int64* start);
44
45 // Cancels a pending operation. It is a mistake to call this method if there
46 // is no operation in progress; in fact, there will be no object to do so.
47 void Cancel();
48
49 private:
50 explicit Core(PartialData* owner);
51 ~Core();
52
53 // Pending io completion routine.
54 void OnIOComplete(int result);
55
56 PartialData* owner_;
57 int64 start_;
jhawkins@chromium.org2a65aceb82011-12-19 20:59:2758
rvargas@google.com034740a2010-06-11 17:16:4859 DISALLOW_COPY_AND_ASSIGN(Core);
60};
61
62PartialData::Core::Core(PartialData* owner)
tbreisacher@chromium.org9987dd72012-01-25 23:40:0463 : owner_(owner), start_(0) {
rvargas@google.com034740a2010-06-11 17:16:4864 DCHECK(!owner_->core_);
65 owner_->core_ = this;
66}
67
68PartialData::Core::~Core() {
69 if (owner_)
70 owner_->core_ = NULL;
71}
72
73void PartialData::Core::Cancel() {
74 DCHECK(owner_);
75 owner_ = NULL;
76}
77
78int PartialData::Core::GetAvailableRange(disk_cache::Entry* entry, int64 offset,
79 int len, int64* start) {
jhawkins@chromium.org2a65aceb82011-12-19 20:59:2780 int rv = entry->GetAvailableRange(
81 offset, len, &start_, base::Bind(&PartialData::Core::OnIOComplete,
82 base::Unretained(this)));
ttuttle859dc7a2015-04-23 19:42:2983 if (rv != ERR_IO_PENDING) {
rvargas@google.com034740a2010-06-11 17:16:4884 // The callback will not be invoked. Lets cleanup.
85 *start = start_;
86 delete this;
87 }
88 return rv;
89}
90
91void PartialData::Core::OnIOComplete(int result) {
92 if (owner_)
93 owner_->GetAvailableRangeCompleted(result, start_);
94 delete this;
95}
96
97// -----------------------------------------------------------------------------
98
erg@google.comb104b502010-10-18 20:21:3199PartialData::PartialData()
rvargas3b57e37a2015-01-06 00:56:34100 : current_range_start_(0),
101 current_range_end_(0),
102 cached_start_(0),
103 resource_size_(0),
104 cached_min_len_(0),
105 range_present_(false),
erg@google.comb104b502010-10-18 20:21:31106 final_range_(false),
107 sparse_entry_(true),
108 truncated_(false),
rvargas@google.com634739b2011-03-02 18:08:25109 initial_validation_(false),
jhawkins@chromium.org49639fa2011-12-20 23:22:41110 core_(NULL) {
erg@google.comb104b502010-10-18 20:21:31111}
112
rvargas@google.com034740a2010-06-11 17:16:48113PartialData::~PartialData() {
114 if (core_)
115 core_->Cancel();
116}
117
willchan@chromium.org8c76ae22010-04-20 22:15:43118bool PartialData::Init(const HttpRequestHeaders& headers) {
119 std::string range_header;
120 if (!headers.GetHeader(HttpRequestHeaders::kRange, &range_header))
121 return false;
122
rvargas@google.com8bf26f49a2009-06-12 17:35:50123 std::vector<HttpByteRange> ranges;
willchan@chromium.org8c76ae22010-04-20 22:15:43124 if (!HttpUtil::ParseRangeHeader(range_header, &ranges) || ranges.size() != 1)
rvargas@google.com8bf26f49a2009-06-12 17:35:50125 return false;
126
127 // We can handle this range request.
128 byte_range_ = ranges[0];
129 if (!byte_range_.IsValid())
130 return false;
131
rvargas@google.com8bf26f49a2009-06-12 17:35:50132 current_range_start_ = byte_range_.first_byte_position();
rvargas@google.coma5c9d982010-10-12 20:48:02133
134 DVLOG(1) << "Range start: " << current_range_start_ << " end: " <<
135 byte_range_.last_byte_position();
rvargas@google.com8bf26f49a2009-06-12 17:35:50136 return true;
137}
138
willchan@chromium.org8c76ae22010-04-20 22:15:43139void PartialData::SetHeaders(const HttpRequestHeaders& headers) {
140 DCHECK(extra_headers_.IsEmpty());
141 extra_headers_.CopyFrom(headers);
rvargas@google.come75e8af2009-11-03 00:04:20142}
143
willchan@chromium.org8c76ae22010-04-20 22:15:43144void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const {
rvargas@google.com67fe45c2009-06-24 17:44:57145 DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange());
146 int64 end = byte_range_.IsSuffixByteRange() ?
147 byte_range_.suffix_length() : byte_range_.last_byte_position();
rvargas@google.com8bf26f49a2009-06-12 17:35:50148
willchan@chromium.org8c76ae22010-04-20 22:15:43149 headers->CopyFrom(extra_headers_);
tommycli@chromium.orgb7572ea2013-11-26 20:16:38150 if (truncated_ || !byte_range_.IsValid())
151 return;
152
153 if (current_range_start_ < 0) {
154 headers->SetHeader(HttpRequestHeaders::kRange,
155 HttpByteRange::Suffix(end).GetHeaderValue());
156 } else {
157 headers->SetHeader(HttpRequestHeaders::kRange,
158 HttpByteRange::Bounded(
159 current_range_start_, end).GetHeaderValue());
160 }
rvargas@google.com8bf26f49a2009-06-12 17:35:50161}
162
rvargas@google.com034740a2010-06-11 17:16:48163int PartialData::ShouldValidateCache(disk_cache::Entry* entry,
jhawkins@chromium.org49639fa2011-12-20 23:22:41164 const CompletionCallback& callback) {
rvargas@google.com034740a2010-06-11 17:16:48165 DCHECK_GE(current_range_start_, 0);
rvargas@google.com8bf26f49a2009-06-12 17:35:50166
167 // Scan the disk cache for the first cached portion within this range.
rvargas@google.com034740a2010-06-11 17:16:48168 int len = GetNextRangeLen();
rvargas@google.com8bf26f49a2009-06-12 17:35:50169 if (!len)
170 return 0;
rvargas@google.com8bf26f49a2009-06-12 17:35:50171
rvargas@google.coma5c9d982010-10-12 20:48:02172 DVLOG(3) << "ShouldValidateCache len: " << len;
173
rvargas@google.come5dad132009-08-18 00:53:41174 if (sparse_entry_) {
jhawkins@chromium.org49639fa2011-12-20 23:22:41175 DCHECK(callback_.is_null());
rvargas@google.com034740a2010-06-11 17:16:48176 Core* core = Core::CreateCore(this);
177 cached_min_len_ = core->GetAvailableRange(entry, current_range_start_, len,
178 &cached_start_);
179
180 if (cached_min_len_ == ERR_IO_PENDING) {
181 callback_ = callback;
182 return ERR_IO_PENDING;
183 }
rvargas@google.com634739b2011-03-02 18:08:25184 } else if (!truncated_) {
rvargas@google.coma5c9d982010-10-12 20:48:02185 if (byte_range_.HasFirstBytePosition() &&
186 byte_range_.first_byte_position() >= resource_size_) {
187 // The caller should take care of this condition because we should have
188 // failed IsRequestedRangeOK(), but it's better to be consistent here.
189 len = 0;
190 }
rvargas@google.come5dad132009-08-18 00:53:41191 cached_min_len_ = len;
192 cached_start_ = current_range_start_;
193 }
194
rvargas@google.com034740a2010-06-11 17:16:48195 if (cached_min_len_ < 0)
rvargas@google.com8bf26f49a2009-06-12 17:35:50196 return cached_min_len_;
rvargas@google.com034740a2010-06-11 17:16:48197
198 // Return a positive number to indicate success (versus error or finished).
199 return 1;
200}
201
202void PartialData::PrepareCacheValidation(disk_cache::Entry* entry,
203 HttpRequestHeaders* headers) {
204 DCHECK_GE(current_range_start_, 0);
205 DCHECK_GE(cached_min_len_, 0);
206
207 int len = GetNextRangeLen();
208 DCHECK_NE(0, len);
209 range_present_ = false;
rvargas@google.com8bf26f49a2009-06-12 17:35:50210
willchan@chromium.org8c76ae22010-04-20 22:15:43211 headers->CopyFrom(extra_headers_);
rvargas@google.com8bf26f49a2009-06-12 17:35:50212
213 if (!cached_min_len_) {
214 // We don't have anything else stored.
215 final_range_ = true;
rvargas@google.com28accfe2009-09-04 23:36:33216 cached_start_ =
217 byte_range_.HasLastBytePosition() ? current_range_start_ + len : 0;
rvargas@google.com8bf26f49a2009-06-12 17:35:50218 }
219
220 if (current_range_start_ == cached_start_) {
221 // The data lives in the cache.
222 range_present_ = true;
rvargas3b57e37a2015-01-06 00:56:34223 current_range_end_ = cached_start_ + cached_min_len_ - 1;
rvargas@google.com8bf26f49a2009-06-12 17:35:50224 if (len == cached_min_len_)
225 final_range_ = true;
rvargas@google.com8bf26f49a2009-06-12 17:35:50226 } else {
227 // This range is not in the cache.
rvargas3b57e37a2015-01-06 00:56:34228 current_range_end_ = cached_start_ - 1;
rvargas@google.com8bf26f49a2009-06-12 17:35:50229 }
hubbe70fbde6a2015-07-08 19:24:14230 headers->SetHeader(
231 HttpRequestHeaders::kRange,
232 HttpByteRange::Bounded(current_range_start_, current_range_end_)
233 .GetHeaderValue());
rvargas@google.com8bf26f49a2009-06-12 17:35:50234}
235
236bool PartialData::IsCurrentRangeCached() const {
237 return range_present_;
238}
239
240bool PartialData::IsLastRange() const {
241 return final_range_;
242}
243
rvargas@google.com44f873a62009-08-12 00:14:48244bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers,
rvargas@google.com28accfe2009-09-04 23:36:33245 disk_cache::Entry* entry,
246 bool truncated) {
rvargas@google.com67fe45c2009-06-24 17:44:57247 resource_size_ = 0;
rvargas@google.com28accfe2009-09-04 23:36:33248 if (truncated) {
249 DCHECK_EQ(headers->response_code(), 200);
rvargas@google.com28accfe2009-09-04 23:36:33250 // We don't have the real length and the user may be trying to create a
251 // sparse entry so let's not write to this entry.
252 if (byte_range_.IsValid())
rvargas@google.com9f03cb7a2012-07-30 23:15:20253 return false;
254
255 if (!headers->HasStrongValidators())
rvargas@google.com28accfe2009-09-04 23:36:33256 return false;
257
rvargas@google.comdbd39fb2010-01-08 01:13:36258 // Now we avoid resume if there is no content length, but that was not
259 // always the case so double check here.
260 int64 total_length = headers->GetContentLength();
rvargas@google.combd069d72011-05-19 01:11:11261 if (total_length <= 0)
rvargas@google.comdbd39fb2010-01-08 01:13:36262 return false;
263
hclam@chromium.orgecd8becb2009-10-02 17:57:45264 truncated_ = true;
rvargas@google.com634739b2011-03-02 18:08:25265 initial_validation_ = true;
hclam@chromium.orgecd8becb2009-10-02 17:57:45266 sparse_entry_ = false;
rvargas@google.com634739b2011-03-02 18:08:25267 int current_len = entry->GetDataSize(kDataStream);
268 byte_range_.set_first_byte_position(current_len);
rvargas@google.comdbd39fb2010-01-08 01:13:36269 resource_size_ = total_length;
rvargas@google.com634739b2011-03-02 18:08:25270 current_range_start_ = current_len;
271 cached_min_len_ = current_len;
272 cached_start_ = current_len + 1;
rvargas@google.com28accfe2009-09-04 23:36:33273 return true;
274 }
275
rvargas@google.com9f03cb7a2012-07-30 23:15:20276 if (headers->response_code() != 206) {
rvargas@google.come5dad132009-08-18 00:53:41277 DCHECK(byte_range_.IsValid());
278 sparse_entry_ = false;
279 resource_size_ = entry->GetDataSize(kDataStream);
rvargas@google.coma5c9d982010-10-12 20:48:02280 DVLOG(2) << "UpdateFromStoredHeaders size: " << resource_size_;
rvargas@google.come5dad132009-08-18 00:53:41281 return true;
282 }
283
rvargas43dc8fd2015-01-07 23:03:25284 if (!headers->HasStrongValidators())
285 return false;
286
rvargas@google.comdbd39fb2010-01-08 01:13:36287 int64 length_value = headers->GetContentLength();
288 if (length_value <= 0)
rvargas@google.com67fe45c2009-06-24 17:44:57289 return false; // We must have stored the resource length.
290
rvargas@google.comdbd39fb2010-01-08 01:13:36291 resource_size_ = length_value;
rvargas@google.com67fe45c2009-06-24 17:44:57292
rvargas@google.come5dad132009-08-18 00:53:41293 // Make sure that this is really a sparse entry.
rvargas@google.com034740a2010-06-11 17:16:48294 return entry->CouldBeSparse();
rvargas@google.come5dad132009-08-18 00:53:41295}
296
rvargas@google.com634739b2011-03-02 18:08:25297void PartialData::SetRangeToStartDownload() {
298 DCHECK(truncated_);
299 DCHECK(!sparse_entry_);
300 current_range_start_ = 0;
301 cached_start_ = 0;
302 initial_validation_ = false;
303}
304
rvargas@google.come5dad132009-08-18 00:53:41305bool PartialData::IsRequestedRangeOK() {
rvargas@google.com44f873a62009-08-12 00:14:48306 if (byte_range_.IsValid()) {
307 if (!byte_range_.ComputeBounds(resource_size_))
308 return false;
rvargas@google.com634739b2011-03-02 18:08:25309 if (truncated_)
310 return true;
rvargas@google.com67fe45c2009-06-24 17:44:57311
rvargas@google.com44f873a62009-08-12 00:14:48312 if (current_range_start_ < 0)
313 current_range_start_ = byte_range_.first_byte_position();
314 } else {
315 // This is not a range request but we have partial data stored.
316 current_range_start_ = 0;
317 byte_range_.set_last_byte_position(resource_size_ - 1);
318 }
319
rvargas@google.come5dad132009-08-18 00:53:41320 bool rv = current_range_start_ >= 0;
321 if (!rv)
322 current_range_start_ = 0;
rvargas@google.com67fe45c2009-06-24 17:44:57323
rvargas@google.come5dad132009-08-18 00:53:41324 return rv;
rvargas@google.com95792eb12009-06-22 21:30:40325}
326
327bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) {
rvargas@google.come5dad132009-08-18 00:53:41328 if (headers->response_code() == 304) {
hclam@chromium.orgd9adff2c2009-09-05 01:15:45329 if (!byte_range_.IsValid() || truncated_)
rvargas@google.com28accfe2009-09-04 23:36:33330 return true;
331
rvargas@google.come5dad132009-08-18 00:53:41332 // We must have a complete range here.
333 return byte_range_.HasFirstBytePosition() &&
cbentzel@chromium.org2227c692010-05-04 15:36:11334 byte_range_.HasLastBytePosition();
rvargas@google.come5dad132009-08-18 00:53:41335 }
336
rvargas@google.com95792eb12009-06-22 21:30:40337 int64 start, end, total_length;
338 if (!headers->GetContentRange(&start, &end, &total_length))
339 return false;
340 if (total_length <= 0)
341 return false;
342
rvargas@chromium.org9f10ec32013-11-01 00:51:53343 DCHECK_EQ(headers->response_code(), 206);
344
345 // A server should return a valid content length with a 206 (per the standard)
346 // but relax the requirement because some servers don't do that.
rvargas@google.com7eab0d2262009-10-14 22:05:54347 int64 content_length = headers->GetContentLength();
rvargas@chromium.org9f10ec32013-11-01 00:51:53348 if (content_length > 0 && content_length != end - start + 1)
rvargas@google.com7eab0d2262009-10-14 22:05:54349 return false;
350
rvargas@google.com95792eb12009-06-22 21:30:40351 if (!resource_size_) {
352 // First response. Update our values with the ones provided by the server.
353 resource_size_ = total_length;
rvargas@google.com67fe45c2009-06-24 17:44:57354 if (!byte_range_.HasFirstBytePosition()) {
rvargas@google.com95792eb12009-06-22 21:30:40355 byte_range_.set_first_byte_position(start);
rvargas@google.com67fe45c2009-06-24 17:44:57356 current_range_start_ = start;
357 }
rvargas@google.com95792eb12009-06-22 21:30:40358 if (!byte_range_.HasLastBytePosition())
359 byte_range_.set_last_byte_position(end);
360 } else if (resource_size_ != total_length) {
361 return false;
362 }
363
rvargas@google.comdbd39fb2010-01-08 01:13:36364 if (truncated_) {
365 if (!byte_range_.HasLastBytePosition())
366 byte_range_.set_last_byte_position(end);
367 }
368
rvargas@google.com95792eb12009-06-22 21:30:40369 if (start != current_range_start_)
370 return false;
371
rvargas3b57e37a2015-01-06 00:56:34372 if (!current_range_end_) {
373 // There is nothing in the cache.
374 DCHECK(byte_range_.HasLastBytePosition());
375 current_range_end_ = byte_range_.last_byte_position();
376 if (current_range_end_ >= resource_size_) {
377 // We didn't know the real file size, and the server is saying that the
378 // requested range goes beyond the size. Fix it.
379 current_range_end_ = end;
380 byte_range_.set_last_byte_position(end);
381 }
382 }
383
384 // If we received a range, but it's not exactly the range we asked for, avoid
385 // trouble and signal an error.
386 if (end != current_range_end_)
rvargas@google.com95792eb12009-06-22 21:30:40387 return false;
388
389 return true;
390}
391
392// We are making multiple requests to complete the range requested by the user.
393// Just assume that everything is fine and say that we are returning what was
394// requested.
rvargas@google.coma5c9d982010-10-12 20:48:02395void PartialData::FixResponseHeaders(HttpResponseHeaders* headers,
396 bool success) {
rvargas@google.com28accfe2009-09-04 23:36:33397 if (truncated_)
398 return;
399
kinuko@chromium.org3d47dac9622014-03-10 07:28:58400 if (byte_range_.IsValid() && success) {
401 headers->UpdateWithNewRange(byte_range_, resource_size_, !sparse_entry_);
402 return;
403 }
404
rvargas@google.com95792eb12009-06-22 21:30:40405 headers->RemoveHeader(kLengthHeader);
406 headers->RemoveHeader(kRangeHeader);
407
rvargas@google.com44f873a62009-08-12 00:14:48408 if (byte_range_.IsValid()) {
kinuko@chromium.org3d47dac9622014-03-10 07:28:58409 headers->ReplaceStatusLine("HTTP/1.1 416 Requested Range Not Satisfiable");
410 headers->AddHeader(base::StringPrintf("%s: bytes 0-0/%" PRId64,
411 kRangeHeader, resource_size_));
412 headers->AddHeader(base::StringPrintf("%s: 0", kLengthHeader));
rvargas@google.com44f873a62009-08-12 00:14:48413 } else {
414 // TODO(rvargas): Is it safe to change the protocol version?
415 headers->ReplaceStatusLine("HTTP/1.1 200 OK");
416 DCHECK_NE(resource_size_, 0);
kinuko@chromium.org3d47dac9622014-03-10 07:28:58417 headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader,
418 resource_size_));
rvargas@google.com44f873a62009-08-12 00:14:48419 }
rvargas@google.com95792eb12009-06-22 21:30:40420}
421
422void PartialData::FixContentLength(HttpResponseHeaders* headers) {
423 headers->RemoveHeader(kLengthHeader);
tfarina@chromium.orgd8eb84242010-09-25 02:25:06424 headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader,
425 resource_size_));
rvargas@google.com95792eb12009-06-22 21:30:40426}
427
ttuttle859dc7a2015-04-23 19:42:29428int PartialData::CacheRead(disk_cache::Entry* entry,
429 IOBuffer* data,
430 int data_len,
431 const CompletionCallback& callback) {
rvargas@google.com8bf26f49a2009-06-12 17:35:50432 int read_len = std::min(data_len, cached_min_len_);
hclam@chromium.org8f28d632009-10-01 22:09:21433 if (!read_len)
434 return 0;
435
rvargas@google.come5dad132009-08-18 00:53:41436 int rv = 0;
437 if (sparse_entry_) {
438 rv = entry->ReadSparseData(current_range_start_, data, read_len,
439 callback);
440 } else {
441 if (current_range_start_ > kint32max)
442 return ERR_INVALID_ARGUMENT;
443
444 rv = entry->ReadData(kDataStream, static_cast<int>(current_range_start_),
445 data, read_len, callback);
446 }
rvargas@google.com8bf26f49a2009-06-12 17:35:50447 return rv;
448}
449
ttuttle859dc7a2015-04-23 19:42:29450int PartialData::CacheWrite(disk_cache::Entry* entry,
451 IOBuffer* data,
452 int data_len,
453 const CompletionCallback& callback) {
rvargas@google.coma5c9d982010-10-12 20:48:02454 DVLOG(3) << "To write: " << data_len;
rvargas@google.come5dad132009-08-18 00:53:41455 if (sparse_entry_) {
jhawkins@chromium.org2a65aceb82011-12-19 20:59:27456 return entry->WriteSparseData(
457 current_range_start_, data, data_len, callback);
rvargas@google.come5dad132009-08-18 00:53:41458 } else {
459 if (current_range_start_ > kint32max)
460 return ERR_INVALID_ARGUMENT;
461
462 return entry->WriteData(kDataStream, static_cast<int>(current_range_start_),
rvargas@google.com28accfe2009-09-04 23:36:33463 data, data_len, callback, true);
rvargas@google.come5dad132009-08-18 00:53:41464 }
rvargas@google.com8bf26f49a2009-06-12 17:35:50465}
466
467void PartialData::OnCacheReadCompleted(int result) {
rvargas@google.coma5c9d982010-10-12 20:48:02468 DVLOG(3) << "Read: " << result;
rvargas@google.com8bf26f49a2009-06-12 17:35:50469 if (result > 0) {
470 current_range_start_ += result;
471 cached_min_len_ -= result;
rvargas@google.com034740a2010-06-11 17:16:48472 DCHECK_GE(cached_min_len_, 0);
rvargas@google.com8bf26f49a2009-06-12 17:35:50473 }
474}
475
476void PartialData::OnNetworkReadCompleted(int result) {
477 if (result > 0)
478 current_range_start_ += result;
rvargas@google.com8bf26f49a2009-06-12 17:35:50479}
rvargas@google.com8bf26f49a2009-06-12 17:35:50480
rvargas@google.com034740a2010-06-11 17:16:48481int PartialData::GetNextRangeLen() {
482 int64 range_len =
483 byte_range_.HasLastBytePosition() ?
484 byte_range_.last_byte_position() - current_range_start_ + 1 :
485 kint32max;
486 if (range_len > kint32max)
487 range_len = kint32max;
488 return static_cast<int32>(range_len);
489}
490
491void PartialData::GetAvailableRangeCompleted(int result, int64 start) {
jhawkins@chromium.org49639fa2011-12-20 23:22:41492 DCHECK(!callback_.is_null());
rvargas@google.com034740a2010-06-11 17:16:48493 DCHECK_NE(ERR_IO_PENDING, result);
494
495 cached_start_ = start;
496 cached_min_len_ = result;
497 if (result >= 0)
498 result = 1; // Return success, go ahead and validate the entry.
499
jhawkins@chromium.org49639fa2011-12-20 23:22:41500 CompletionCallback cb = callback_;
501 callback_.Reset();
502 cb.Run(result);
rvargas@google.com034740a2010-06-11 17:16:48503}
504
rvargas@google.com8bf26f49a2009-06-12 17:35:50505} // namespace net