[go: nahoru, domu]

blob: d199c28290b3e5d982ca6c4ee9963f7ec260f4ae [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:4328void AddRangeHeader(int64 start, int64 end, HttpRequestHeaders* headers) {
29 DCHECK(start >= 0 || end >= 0);
30 std::string my_start, my_end;
31 if (start >= 0)
brettw@chromium.org528c56d2010-07-30 19:28:4432 my_start = base::Int64ToString(start);
willchan@chromium.org8c76ae22010-04-20 22:15:4333 if (end >= 0)
brettw@chromium.org528c56d2010-07-30 19:28:4434 my_end = base::Int64ToString(end);
willchan@chromium.org8c76ae22010-04-20 22:15:4335
36 headers->SetHeader(
37 HttpRequestHeaders::kRange,
tfarina@chromium.orgd8eb84242010-09-25 02:25:0638 base::StringPrintf("bytes=%s-%s", my_start.c_str(), my_end.c_str()));
rvargas@google.com95792eb12009-06-22 21:30:4039}
rvargas@google.com8bf26f49a2009-06-12 17:35:5040
willchan@chromium.org8c76ae22010-04-20 22:15:4341} // namespace
rvargas@google.com8bf26f49a2009-06-12 17:35:5042
rvargas@google.com034740a2010-06-11 17:16:4843// A core object that can be detached from the Partialdata object at destruction
44// so that asynchronous operations cleanup can be performed.
45class PartialData::Core {
46 public:
47 // Build a new core object. Lifetime management is automatic.
48 static Core* CreateCore(PartialData* owner) {
49 return new Core(owner);
50 }
51
52 // Wrapper for Entry::GetAvailableRange. If this method returns ERR_IO_PENDING
53 // PartialData::GetAvailableRangeCompleted() will be invoked on the owner
54 // object when finished (unless Cancel() is called first).
55 int GetAvailableRange(disk_cache::Entry* entry, int64 offset, int len,
56 int64* start);
57
58 // Cancels a pending operation. It is a mistake to call this method if there
59 // is no operation in progress; in fact, there will be no object to do so.
60 void Cancel();
61
62 private:
63 explicit Core(PartialData* owner);
64 ~Core();
65
66 // Pending io completion routine.
67 void OnIOComplete(int result);
68
69 PartialData* owner_;
70 int64 start_;
jhawkins@chromium.org2a65aceb82011-12-19 20:59:2771
rvargas@google.com034740a2010-06-11 17:16:4872 DISALLOW_COPY_AND_ASSIGN(Core);
73};
74
75PartialData::Core::Core(PartialData* owner)
tbreisacher@chromium.org9987dd72012-01-25 23:40:0476 : owner_(owner), start_(0) {
rvargas@google.com034740a2010-06-11 17:16:4877 DCHECK(!owner_->core_);
78 owner_->core_ = this;
79}
80
81PartialData::Core::~Core() {
82 if (owner_)
83 owner_->core_ = NULL;
84}
85
86void PartialData::Core::Cancel() {
87 DCHECK(owner_);
88 owner_ = NULL;
89}
90
91int PartialData::Core::GetAvailableRange(disk_cache::Entry* entry, int64 offset,
92 int len, int64* start) {
jhawkins@chromium.org2a65aceb82011-12-19 20:59:2793 int rv = entry->GetAvailableRange(
94 offset, len, &start_, base::Bind(&PartialData::Core::OnIOComplete,
95 base::Unretained(this)));
rvargas@google.com034740a2010-06-11 17:16:4896 if (rv != net::ERR_IO_PENDING) {
97 // The callback will not be invoked. Lets cleanup.
98 *start = start_;
99 delete this;
100 }
101 return rv;
102}
103
104void PartialData::Core::OnIOComplete(int result) {
105 if (owner_)
106 owner_->GetAvailableRangeCompleted(result, start_);
107 delete this;
108}
109
110// -----------------------------------------------------------------------------
111
erg@google.comb104b502010-10-18 20:21:31112PartialData::PartialData()
113 : range_present_(false),
114 final_range_(false),
115 sparse_entry_(true),
116 truncated_(false),
rvargas@google.com634739b2011-03-02 18:08:25117 initial_validation_(false),
jhawkins@chromium.org49639fa2011-12-20 23:22:41118 core_(NULL) {
erg@google.comb104b502010-10-18 20:21:31119}
120
rvargas@google.com034740a2010-06-11 17:16:48121PartialData::~PartialData() {
122 if (core_)
123 core_->Cancel();
124}
125
willchan@chromium.org8c76ae22010-04-20 22:15:43126bool PartialData::Init(const HttpRequestHeaders& headers) {
127 std::string range_header;
128 if (!headers.GetHeader(HttpRequestHeaders::kRange, &range_header))
129 return false;
130
rvargas@google.com8bf26f49a2009-06-12 17:35:50131 std::vector<HttpByteRange> ranges;
willchan@chromium.org8c76ae22010-04-20 22:15:43132 if (!HttpUtil::ParseRangeHeader(range_header, &ranges) || ranges.size() != 1)
rvargas@google.com8bf26f49a2009-06-12 17:35:50133 return false;
134
135 // We can handle this range request.
136 byte_range_ = ranges[0];
137 if (!byte_range_.IsValid())
138 return false;
139
rvargas@google.com95792eb12009-06-22 21:30:40140 resource_size_ = 0;
rvargas@google.com8bf26f49a2009-06-12 17:35:50141 current_range_start_ = byte_range_.first_byte_position();
rvargas@google.coma5c9d982010-10-12 20:48:02142
143 DVLOG(1) << "Range start: " << current_range_start_ << " end: " <<
144 byte_range_.last_byte_position();
rvargas@google.com8bf26f49a2009-06-12 17:35:50145 return true;
146}
147
willchan@chromium.org8c76ae22010-04-20 22:15:43148void PartialData::SetHeaders(const HttpRequestHeaders& headers) {
149 DCHECK(extra_headers_.IsEmpty());
150 extra_headers_.CopyFrom(headers);
rvargas@google.come75e8af2009-11-03 00:04:20151}
152
willchan@chromium.org8c76ae22010-04-20 22:15:43153void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const {
rvargas@google.com67fe45c2009-06-24 17:44:57154 DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange());
155 int64 end = byte_range_.IsSuffixByteRange() ?
156 byte_range_.suffix_length() : byte_range_.last_byte_position();
rvargas@google.com8bf26f49a2009-06-12 17:35:50157
willchan@chromium.org8c76ae22010-04-20 22:15:43158 headers->CopyFrom(extra_headers_);
rvargas@google.com634739b2011-03-02 18:08:25159 if (!truncated_ && byte_range_.IsValid())
rvargas@google.coma189bce2009-12-01 01:59:12160 AddRangeHeader(current_range_start_, end, headers);
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;
223 if (len == cached_min_len_)
224 final_range_ = true;
225 AddRangeHeader(current_range_start_, cached_start_ + cached_min_len_ - 1,
226 headers);
227 } else {
228 // This range is not in the cache.
229 AddRangeHeader(current_range_start_, cached_start_ - 1, headers);
230 }
rvargas@google.com8bf26f49a2009-06-12 17:35:50231}
232
233bool PartialData::IsCurrentRangeCached() const {
234 return range_present_;
235}
236
237bool PartialData::IsLastRange() const {
238 return final_range_;
239}
240
rvargas@google.com44f873a62009-08-12 00:14:48241bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers,
rvargas@google.com28accfe2009-09-04 23:36:33242 disk_cache::Entry* entry,
243 bool truncated) {
rvargas@google.com67fe45c2009-06-24 17:44:57244 resource_size_ = 0;
rvargas@google.com28accfe2009-09-04 23:36:33245 if (truncated) {
246 DCHECK_EQ(headers->response_code(), 200);
rvargas@google.com28accfe2009-09-04 23:36:33247 // We don't have the real length and the user may be trying to create a
248 // sparse entry so let's not write to this entry.
249 if (byte_range_.IsValid())
rvargas@google.com9f03cb7a2012-07-30 23:15:20250 return false;
251
252 if (!headers->HasStrongValidators())
rvargas@google.com28accfe2009-09-04 23:36:33253 return false;
254
rvargas@google.comdbd39fb2010-01-08 01:13:36255 // Now we avoid resume if there is no content length, but that was not
256 // always the case so double check here.
257 int64 total_length = headers->GetContentLength();
rvargas@google.combd069d72011-05-19 01:11:11258 if (total_length <= 0)
rvargas@google.comdbd39fb2010-01-08 01:13:36259 return false;
260
hclam@chromium.orgecd8becb2009-10-02 17:57:45261 truncated_ = true;
rvargas@google.com634739b2011-03-02 18:08:25262 initial_validation_ = true;
hclam@chromium.orgecd8becb2009-10-02 17:57:45263 sparse_entry_ = false;
rvargas@google.com634739b2011-03-02 18:08:25264 int current_len = entry->GetDataSize(kDataStream);
265 byte_range_.set_first_byte_position(current_len);
rvargas@google.comdbd39fb2010-01-08 01:13:36266 resource_size_ = total_length;
rvargas@google.com634739b2011-03-02 18:08:25267 current_range_start_ = current_len;
268 cached_min_len_ = current_len;
269 cached_start_ = current_len + 1;
rvargas@google.com28accfe2009-09-04 23:36:33270 return true;
271 }
272
rvargas@google.com9f03cb7a2012-07-30 23:15:20273 if (headers->response_code() != 206) {
rvargas@google.come5dad132009-08-18 00:53:41274 DCHECK(byte_range_.IsValid());
275 sparse_entry_ = false;
276 resource_size_ = entry->GetDataSize(kDataStream);
rvargas@google.coma5c9d982010-10-12 20:48:02277 DVLOG(2) << "UpdateFromStoredHeaders size: " << resource_size_;
rvargas@google.come5dad132009-08-18 00:53:41278 return true;
279 }
280
rvargas@google.com8a301142011-04-13 18:33:40281 if (!headers->HasStrongValidators())
282 return false;
283
rvargas@google.comdbd39fb2010-01-08 01:13:36284 int64 length_value = headers->GetContentLength();
285 if (length_value <= 0)
rvargas@google.com67fe45c2009-06-24 17:44:57286 return false; // We must have stored the resource length.
287
rvargas@google.comdbd39fb2010-01-08 01:13:36288 resource_size_ = length_value;
rvargas@google.com67fe45c2009-06-24 17:44:57289
rvargas@google.come5dad132009-08-18 00:53:41290 // Make sure that this is really a sparse entry.
rvargas@google.com034740a2010-06-11 17:16:48291 return entry->CouldBeSparse();
rvargas@google.come5dad132009-08-18 00:53:41292}
293
rvargas@google.com634739b2011-03-02 18:08:25294void PartialData::SetRangeToStartDownload() {
295 DCHECK(truncated_);
296 DCHECK(!sparse_entry_);
297 current_range_start_ = 0;
298 cached_start_ = 0;
299 initial_validation_ = false;
300}
301
rvargas@google.come5dad132009-08-18 00:53:41302bool PartialData::IsRequestedRangeOK() {
rvargas@google.com44f873a62009-08-12 00:14:48303 if (byte_range_.IsValid()) {
304 if (!byte_range_.ComputeBounds(resource_size_))
305 return false;
rvargas@google.com634739b2011-03-02 18:08:25306 if (truncated_)
307 return true;
rvargas@google.com67fe45c2009-06-24 17:44:57308
rvargas@google.com44f873a62009-08-12 00:14:48309 if (current_range_start_ < 0)
310 current_range_start_ = byte_range_.first_byte_position();
311 } else {
312 // This is not a range request but we have partial data stored.
313 current_range_start_ = 0;
314 byte_range_.set_last_byte_position(resource_size_ - 1);
315 }
316
rvargas@google.come5dad132009-08-18 00:53:41317 bool rv = current_range_start_ >= 0;
318 if (!rv)
319 current_range_start_ = 0;
rvargas@google.com67fe45c2009-06-24 17:44:57320
rvargas@google.come5dad132009-08-18 00:53:41321 return rv;
rvargas@google.com95792eb12009-06-22 21:30:40322}
323
324bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) {
rvargas@google.come5dad132009-08-18 00:53:41325 if (headers->response_code() == 304) {
hclam@chromium.orgd9adff2c2009-09-05 01:15:45326 if (!byte_range_.IsValid() || truncated_)
rvargas@google.com28accfe2009-09-04 23:36:33327 return true;
328
rvargas@google.come5dad132009-08-18 00:53:41329 // We must have a complete range here.
330 return byte_range_.HasFirstBytePosition() &&
cbentzel@chromium.org2227c692010-05-04 15:36:11331 byte_range_.HasLastBytePosition();
rvargas@google.come5dad132009-08-18 00:53:41332 }
333
rvargas@google.com95792eb12009-06-22 21:30:40334 int64 start, end, total_length;
335 if (!headers->GetContentRange(&start, &end, &total_length))
336 return false;
337 if (total_length <= 0)
338 return false;
339
rvargas@chromium.org9f10ec32013-11-01 00:51:53340 DCHECK_EQ(headers->response_code(), 206);
341
342 // A server should return a valid content length with a 206 (per the standard)
343 // but relax the requirement because some servers don't do that.
rvargas@google.com7eab0d2262009-10-14 22:05:54344 int64 content_length = headers->GetContentLength();
rvargas@chromium.org9f10ec32013-11-01 00:51:53345 if (content_length > 0 && content_length != end - start + 1)
rvargas@google.com7eab0d2262009-10-14 22:05:54346 return false;
347
rvargas@google.com95792eb12009-06-22 21:30:40348 if (!resource_size_) {
349 // First response. Update our values with the ones provided by the server.
350 resource_size_ = total_length;
rvargas@google.com67fe45c2009-06-24 17:44:57351 if (!byte_range_.HasFirstBytePosition()) {
rvargas@google.com95792eb12009-06-22 21:30:40352 byte_range_.set_first_byte_position(start);
rvargas@google.com67fe45c2009-06-24 17:44:57353 current_range_start_ = start;
354 }
rvargas@google.com95792eb12009-06-22 21:30:40355 if (!byte_range_.HasLastBytePosition())
356 byte_range_.set_last_byte_position(end);
357 } else if (resource_size_ != total_length) {
358 return false;
359 }
360
rvargas@google.comdbd39fb2010-01-08 01:13:36361 if (truncated_) {
362 if (!byte_range_.HasLastBytePosition())
363 byte_range_.set_last_byte_position(end);
364 }
365
rvargas@google.com95792eb12009-06-22 21:30:40366 if (start != current_range_start_)
367 return false;
368
rvargas@google.com44f873a62009-08-12 00:14:48369 if (byte_range_.IsValid() && end > byte_range_.last_byte_position())
rvargas@google.com95792eb12009-06-22 21:30:40370 return false;
371
372 return true;
373}
374
375// We are making multiple requests to complete the range requested by the user.
376// Just assume that everything is fine and say that we are returning what was
377// requested.
rvargas@google.coma5c9d982010-10-12 20:48:02378void PartialData::FixResponseHeaders(HttpResponseHeaders* headers,
379 bool success) {
rvargas@google.com28accfe2009-09-04 23:36:33380 if (truncated_)
381 return;
382
rvargas@google.com95792eb12009-06-22 21:30:40383 headers->RemoveHeader(kLengthHeader);
384 headers->RemoveHeader(kRangeHeader);
385
rvargas@google.coma5c9d982010-10-12 20:48:02386 int64 range_len, start, end;
rvargas@google.com44f873a62009-08-12 00:14:48387 if (byte_range_.IsValid()) {
rvargas@google.coma5c9d982010-10-12 20:48:02388 if (success) {
389 if (!sparse_entry_)
390 headers->ReplaceStatusLine("HTTP/1.1 206 Partial Content");
rvargas@google.come5dad132009-08-18 00:53:41391
rvargas@google.coma5c9d982010-10-12 20:48:02392 DCHECK(byte_range_.HasFirstBytePosition());
393 DCHECK(byte_range_.HasLastBytePosition());
394 start = byte_range_.first_byte_position();
395 end = byte_range_.last_byte_position();
396 range_len = end - start + 1;
397 } else {
398 headers->ReplaceStatusLine(
399 "HTTP/1.1 416 Requested Range Not Satisfiable");
400 start = 0;
401 end = 0;
402 range_len = 0;
403 }
404
evan@chromium.org34b2b002009-11-20 06:53:28405 headers->AddHeader(
tfarina@chromium.orgd8eb84242010-09-25 02:25:06406 base::StringPrintf("%s: bytes %" PRId64 "-%" PRId64 "/%" PRId64,
rvargas@google.coma5c9d982010-10-12 20:48:02407 kRangeHeader, start, end, resource_size_));
rvargas@google.com44f873a62009-08-12 00:14:48408 } else {
409 // TODO(rvargas): Is it safe to change the protocol version?
410 headers->ReplaceStatusLine("HTTP/1.1 200 OK");
411 DCHECK_NE(resource_size_, 0);
412 range_len = resource_size_;
413 }
rvargas@google.com95792eb12009-06-22 21:30:40414
tfarina@chromium.orgd8eb84242010-09-25 02:25:06415 headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader,
416 range_len));
rvargas@google.com95792eb12009-06-22 21:30:40417}
418
419void PartialData::FixContentLength(HttpResponseHeaders* headers) {
420 headers->RemoveHeader(kLengthHeader);
tfarina@chromium.orgd8eb84242010-09-25 02:25:06421 headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader,
422 resource_size_));
rvargas@google.com95792eb12009-06-22 21:30:40423}
424
jhawkins@chromium.org2a65aceb82011-12-19 20:59:27425int PartialData::CacheRead(
426 disk_cache::Entry* entry, IOBuffer* data, int data_len,
427 const net::CompletionCallback& callback) {
rvargas@google.com8bf26f49a2009-06-12 17:35:50428 int read_len = std::min(data_len, cached_min_len_);
hclam@chromium.org8f28d632009-10-01 22:09:21429 if (!read_len)
430 return 0;
431
rvargas@google.come5dad132009-08-18 00:53:41432 int rv = 0;
433 if (sparse_entry_) {
434 rv = entry->ReadSparseData(current_range_start_, data, read_len,
435 callback);
436 } else {
437 if (current_range_start_ > kint32max)
438 return ERR_INVALID_ARGUMENT;
439
440 rv = entry->ReadData(kDataStream, static_cast<int>(current_range_start_),
441 data, read_len, callback);
442 }
rvargas@google.com8bf26f49a2009-06-12 17:35:50443 return rv;
444}
445
jhawkins@chromium.org2a65aceb82011-12-19 20:59:27446int PartialData::CacheWrite(
447 disk_cache::Entry* entry, IOBuffer* data, int data_len,
448 const net::CompletionCallback& callback) {
rvargas@google.coma5c9d982010-10-12 20:48:02449 DVLOG(3) << "To write: " << data_len;
rvargas@google.come5dad132009-08-18 00:53:41450 if (sparse_entry_) {
jhawkins@chromium.org2a65aceb82011-12-19 20:59:27451 return entry->WriteSparseData(
452 current_range_start_, data, data_len, callback);
rvargas@google.come5dad132009-08-18 00:53:41453 } else {
454 if (current_range_start_ > kint32max)
455 return ERR_INVALID_ARGUMENT;
456
457 return entry->WriteData(kDataStream, static_cast<int>(current_range_start_),
rvargas@google.com28accfe2009-09-04 23:36:33458 data, data_len, callback, true);
rvargas@google.come5dad132009-08-18 00:53:41459 }
rvargas@google.com8bf26f49a2009-06-12 17:35:50460}
461
462void PartialData::OnCacheReadCompleted(int result) {
rvargas@google.coma5c9d982010-10-12 20:48:02463 DVLOG(3) << "Read: " << result;
rvargas@google.com8bf26f49a2009-06-12 17:35:50464 if (result > 0) {
465 current_range_start_ += result;
466 cached_min_len_ -= result;
rvargas@google.com034740a2010-06-11 17:16:48467 DCHECK_GE(cached_min_len_, 0);
rvargas@google.com8bf26f49a2009-06-12 17:35:50468 }
469}
470
471void PartialData::OnNetworkReadCompleted(int result) {
472 if (result > 0)
473 current_range_start_ += result;
rvargas@google.com8bf26f49a2009-06-12 17:35:50474}
rvargas@google.com8bf26f49a2009-06-12 17:35:50475
rvargas@google.com034740a2010-06-11 17:16:48476int PartialData::GetNextRangeLen() {
477 int64 range_len =
478 byte_range_.HasLastBytePosition() ?
479 byte_range_.last_byte_position() - current_range_start_ + 1 :
480 kint32max;
481 if (range_len > kint32max)
482 range_len = kint32max;
483 return static_cast<int32>(range_len);
484}
485
486void PartialData::GetAvailableRangeCompleted(int result, int64 start) {
jhawkins@chromium.org49639fa2011-12-20 23:22:41487 DCHECK(!callback_.is_null());
rvargas@google.com034740a2010-06-11 17:16:48488 DCHECK_NE(ERR_IO_PENDING, result);
489
490 cached_start_ = start;
491 cached_min_len_ = result;
492 if (result >= 0)
493 result = 1; // Return success, go ahead and validate the entry.
494
jhawkins@chromium.org49639fa2011-12-20 23:22:41495 CompletionCallback cb = callback_;
496 callback_.Reset();
497 cb.Run(result);
rvargas@google.com034740a2010-06-11 17:16:48498}
499
rvargas@google.com8bf26f49a2009-06-12 17:35:50500} // namespace net