OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "net/http/partial_data.h" | 5 #include "net/http/partial_data.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/bind_helpers.h" | 8 #include "base/bind_helpers.h" |
9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 14 matching lines...) Expand all Loading... |
25 const char kRangeHeader[] = "Content-Range"; | 25 const char kRangeHeader[] = "Content-Range"; |
26 const int kDataStream = 1; | 26 const int kDataStream = 1; |
27 | 27 |
28 } // namespace | 28 } // namespace |
29 | 29 |
30 // A core object that can be detached from the Partialdata object at destruction | 30 // A core object that can be detached from the Partialdata object at destruction |
31 // so that asynchronous operations cleanup can be performed. | 31 // so that asynchronous operations cleanup can be performed. |
32 class PartialData::Core { | 32 class PartialData::Core { |
33 public: | 33 public: |
34 // Build a new core object. Lifetime management is automatic. | 34 // Build a new core object. Lifetime management is automatic. |
35 static Core* CreateCore(PartialData* owner) { | 35 static Core* CreateCore(PartialData* owner) { return new Core(owner); } |
36 return new Core(owner); | |
37 } | |
38 | 36 |
39 // Wrapper for Entry::GetAvailableRange. If this method returns ERR_IO_PENDING | 37 // Wrapper for Entry::GetAvailableRange. If this method returns ERR_IO_PENDING |
40 // PartialData::GetAvailableRangeCompleted() will be invoked on the owner | 38 // PartialData::GetAvailableRangeCompleted() will be invoked on the owner |
41 // object when finished (unless Cancel() is called first). | 39 // object when finished (unless Cancel() is called first). |
42 int GetAvailableRange(disk_cache::Entry* entry, int64 offset, int len, | 40 int GetAvailableRange(disk_cache::Entry* entry, |
| 41 int64 offset, |
| 42 int len, |
43 int64* start); | 43 int64* start); |
44 | 44 |
45 // Cancels a pending operation. It is a mistake to call this method if there | 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. | 46 // is no operation in progress; in fact, there will be no object to do so. |
47 void Cancel(); | 47 void Cancel(); |
48 | 48 |
49 private: | 49 private: |
50 explicit Core(PartialData* owner); | 50 explicit Core(PartialData* owner); |
51 ~Core(); | 51 ~Core(); |
52 | 52 |
53 // Pending io completion routine. | 53 // Pending io completion routine. |
54 void OnIOComplete(int result); | 54 void OnIOComplete(int result); |
55 | 55 |
56 PartialData* owner_; | 56 PartialData* owner_; |
57 int64 start_; | 57 int64 start_; |
58 | 58 |
59 DISALLOW_COPY_AND_ASSIGN(Core); | 59 DISALLOW_COPY_AND_ASSIGN(Core); |
60 }; | 60 }; |
61 | 61 |
62 PartialData::Core::Core(PartialData* owner) | 62 PartialData::Core::Core(PartialData* owner) : owner_(owner), start_(0) { |
63 : owner_(owner), start_(0) { | |
64 DCHECK(!owner_->core_); | 63 DCHECK(!owner_->core_); |
65 owner_->core_ = this; | 64 owner_->core_ = this; |
66 } | 65 } |
67 | 66 |
68 PartialData::Core::~Core() { | 67 PartialData::Core::~Core() { |
69 if (owner_) | 68 if (owner_) |
70 owner_->core_ = NULL; | 69 owner_->core_ = NULL; |
71 } | 70 } |
72 | 71 |
73 void PartialData::Core::Cancel() { | 72 void PartialData::Core::Cancel() { |
74 DCHECK(owner_); | 73 DCHECK(owner_); |
75 owner_ = NULL; | 74 owner_ = NULL; |
76 } | 75 } |
77 | 76 |
78 int PartialData::Core::GetAvailableRange(disk_cache::Entry* entry, int64 offset, | 77 int PartialData::Core::GetAvailableRange(disk_cache::Entry* entry, |
79 int len, int64* start) { | 78 int64 offset, |
| 79 int len, |
| 80 int64* start) { |
80 int rv = entry->GetAvailableRange( | 81 int rv = entry->GetAvailableRange( |
81 offset, len, &start_, base::Bind(&PartialData::Core::OnIOComplete, | 82 offset, |
82 base::Unretained(this))); | 83 len, |
| 84 &start_, |
| 85 base::Bind(&PartialData::Core::OnIOComplete, base::Unretained(this))); |
83 if (rv != net::ERR_IO_PENDING) { | 86 if (rv != net::ERR_IO_PENDING) { |
84 // The callback will not be invoked. Lets cleanup. | 87 // The callback will not be invoked. Lets cleanup. |
85 *start = start_; | 88 *start = start_; |
86 delete this; | 89 delete this; |
87 } | 90 } |
88 return rv; | 91 return rv; |
89 } | 92 } |
90 | 93 |
91 void PartialData::Core::OnIOComplete(int result) { | 94 void PartialData::Core::OnIOComplete(int result) { |
92 if (owner_) | 95 if (owner_) |
(...skipping 27 matching lines...) Expand all Loading... |
120 return false; | 123 return false; |
121 | 124 |
122 // We can handle this range request. | 125 // We can handle this range request. |
123 byte_range_ = ranges[0]; | 126 byte_range_ = ranges[0]; |
124 if (!byte_range_.IsValid()) | 127 if (!byte_range_.IsValid()) |
125 return false; | 128 return false; |
126 | 129 |
127 resource_size_ = 0; | 130 resource_size_ = 0; |
128 current_range_start_ = byte_range_.first_byte_position(); | 131 current_range_start_ = byte_range_.first_byte_position(); |
129 | 132 |
130 DVLOG(1) << "Range start: " << current_range_start_ << " end: " << | 133 DVLOG(1) << "Range start: " << current_range_start_ |
131 byte_range_.last_byte_position(); | 134 << " end: " << byte_range_.last_byte_position(); |
132 return true; | 135 return true; |
133 } | 136 } |
134 | 137 |
135 void PartialData::SetHeaders(const HttpRequestHeaders& headers) { | 138 void PartialData::SetHeaders(const HttpRequestHeaders& headers) { |
136 DCHECK(extra_headers_.IsEmpty()); | 139 DCHECK(extra_headers_.IsEmpty()); |
137 extra_headers_.CopyFrom(headers); | 140 extra_headers_.CopyFrom(headers); |
138 } | 141 } |
139 | 142 |
140 void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const { | 143 void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const { |
141 DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange()); | 144 DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange()); |
142 int64 end = byte_range_.IsSuffixByteRange() ? | 145 int64 end = byte_range_.IsSuffixByteRange() |
143 byte_range_.suffix_length() : byte_range_.last_byte_position(); | 146 ? byte_range_.suffix_length() |
| 147 : byte_range_.last_byte_position(); |
144 | 148 |
145 headers->CopyFrom(extra_headers_); | 149 headers->CopyFrom(extra_headers_); |
146 if (truncated_ || !byte_range_.IsValid()) | 150 if (truncated_ || !byte_range_.IsValid()) |
147 return; | 151 return; |
148 | 152 |
149 if (current_range_start_ < 0) { | 153 if (current_range_start_ < 0) { |
150 headers->SetHeader(HttpRequestHeaders::kRange, | 154 headers->SetHeader(HttpRequestHeaders::kRange, |
151 HttpByteRange::Suffix(end).GetHeaderValue()); | 155 HttpByteRange::Suffix(end).GetHeaderValue()); |
152 } else { | 156 } else { |
153 headers->SetHeader(HttpRequestHeaders::kRange, | 157 headers->SetHeader( |
154 HttpByteRange::Bounded( | 158 HttpRequestHeaders::kRange, |
155 current_range_start_, end).GetHeaderValue()); | 159 HttpByteRange::Bounded(current_range_start_, end).GetHeaderValue()); |
156 } | 160 } |
157 } | 161 } |
158 | 162 |
159 int PartialData::ShouldValidateCache(disk_cache::Entry* entry, | 163 int PartialData::ShouldValidateCache(disk_cache::Entry* entry, |
160 const CompletionCallback& callback) { | 164 const CompletionCallback& callback) { |
161 DCHECK_GE(current_range_start_, 0); | 165 DCHECK_GE(current_range_start_, 0); |
162 | 166 |
163 // Scan the disk cache for the first cached portion within this range. | 167 // Scan the disk cache for the first cached portion within this range. |
164 int len = GetNextRangeLen(); | 168 int len = GetNextRangeLen(); |
165 if (!len) | 169 if (!len) |
166 return 0; | 170 return 0; |
167 | 171 |
168 DVLOG(3) << "ShouldValidateCache len: " << len; | 172 DVLOG(3) << "ShouldValidateCache len: " << len; |
169 | 173 |
170 if (sparse_entry_) { | 174 if (sparse_entry_) { |
171 DCHECK(callback_.is_null()); | 175 DCHECK(callback_.is_null()); |
172 Core* core = Core::CreateCore(this); | 176 Core* core = Core::CreateCore(this); |
173 cached_min_len_ = core->GetAvailableRange(entry, current_range_start_, len, | 177 cached_min_len_ = core->GetAvailableRange( |
174 &cached_start_); | 178 entry, current_range_start_, len, &cached_start_); |
175 | 179 |
176 if (cached_min_len_ == ERR_IO_PENDING) { | 180 if (cached_min_len_ == ERR_IO_PENDING) { |
177 callback_ = callback; | 181 callback_ = callback; |
178 return ERR_IO_PENDING; | 182 return ERR_IO_PENDING; |
179 } | 183 } |
180 } else if (!truncated_) { | 184 } else if (!truncated_) { |
181 if (byte_range_.HasFirstBytePosition() && | 185 if (byte_range_.HasFirstBytePosition() && |
182 byte_range_.first_byte_position() >= resource_size_) { | 186 byte_range_.first_byte_position() >= resource_size_) { |
183 // The caller should take care of this condition because we should have | 187 // The caller should take care of this condition because we should have |
184 // failed IsRequestedRangeOK(), but it's better to be consistent here. | 188 // failed IsRequestedRangeOK(), but it's better to be consistent here. |
(...skipping 18 matching lines...) Expand all Loading... |
203 int len = GetNextRangeLen(); | 207 int len = GetNextRangeLen(); |
204 DCHECK_NE(0, len); | 208 DCHECK_NE(0, len); |
205 range_present_ = false; | 209 range_present_ = false; |
206 | 210 |
207 headers->CopyFrom(extra_headers_); | 211 headers->CopyFrom(extra_headers_); |
208 | 212 |
209 if (!cached_min_len_) { | 213 if (!cached_min_len_) { |
210 // We don't have anything else stored. | 214 // We don't have anything else stored. |
211 final_range_ = true; | 215 final_range_ = true; |
212 cached_start_ = | 216 cached_start_ = |
213 byte_range_.HasLastBytePosition() ? current_range_start_ + len : 0; | 217 byte_range_.HasLastBytePosition() ? current_range_start_ + len : 0; |
214 } | 218 } |
215 | 219 |
216 if (current_range_start_ == cached_start_) { | 220 if (current_range_start_ == cached_start_) { |
217 // The data lives in the cache. | 221 // The data lives in the cache. |
218 range_present_ = true; | 222 range_present_ = true; |
219 if (len == cached_min_len_) | 223 if (len == cached_min_len_) |
220 final_range_ = true; | 224 final_range_ = true; |
221 headers->SetHeader( | 225 headers->SetHeader( |
222 HttpRequestHeaders::kRange, | 226 HttpRequestHeaders::kRange, |
223 net::HttpByteRange::Bounded( | 227 net::HttpByteRange::Bounded(current_range_start_, |
224 current_range_start_, | 228 cached_start_ + cached_min_len_ - 1) |
225 cached_start_ + cached_min_len_ - 1).GetHeaderValue()); | 229 .GetHeaderValue()); |
226 } else { | 230 } else { |
227 // This range is not in the cache. | 231 // This range is not in the cache. |
228 headers->SetHeader( | 232 headers->SetHeader( |
229 HttpRequestHeaders::kRange, | 233 HttpRequestHeaders::kRange, |
230 net::HttpByteRange::Bounded( | 234 net::HttpByteRange::Bounded(current_range_start_, cached_start_ - 1) |
231 current_range_start_, cached_start_ - 1).GetHeaderValue()); | 235 .GetHeaderValue()); |
232 } | 236 } |
233 } | 237 } |
234 | 238 |
235 bool PartialData::IsCurrentRangeCached() const { | 239 bool PartialData::IsCurrentRangeCached() const { |
236 return range_present_; | 240 return range_present_; |
237 } | 241 } |
238 | 242 |
239 bool PartialData::IsLastRange() const { | 243 bool PartialData::IsLastRange() const { |
240 return final_range_; | 244 return final_range_; |
241 } | 245 } |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
323 return rv; | 327 return rv; |
324 } | 328 } |
325 | 329 |
326 bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) { | 330 bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) { |
327 if (headers->response_code() == 304) { | 331 if (headers->response_code() == 304) { |
328 if (!byte_range_.IsValid() || truncated_) | 332 if (!byte_range_.IsValid() || truncated_) |
329 return true; | 333 return true; |
330 | 334 |
331 // We must have a complete range here. | 335 // We must have a complete range here. |
332 return byte_range_.HasFirstBytePosition() && | 336 return byte_range_.HasFirstBytePosition() && |
333 byte_range_.HasLastBytePosition(); | 337 byte_range_.HasLastBytePosition(); |
334 } | 338 } |
335 | 339 |
336 int64 start, end, total_length; | 340 int64 start, end, total_length; |
337 if (!headers->GetContentRange(&start, &end, &total_length)) | 341 if (!headers->GetContentRange(&start, &end, &total_length)) |
338 return false; | 342 return false; |
339 if (total_length <= 0) | 343 if (total_length <= 0) |
340 return false; | 344 return false; |
341 | 345 |
342 DCHECK_EQ(headers->response_code(), 206); | 346 DCHECK_EQ(headers->response_code(), 206); |
343 | 347 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 if (byte_range_.IsValid() && success) { | 389 if (byte_range_.IsValid() && success) { |
386 headers->UpdateWithNewRange(byte_range_, resource_size_, !sparse_entry_); | 390 headers->UpdateWithNewRange(byte_range_, resource_size_, !sparse_entry_); |
387 return; | 391 return; |
388 } | 392 } |
389 | 393 |
390 headers->RemoveHeader(kLengthHeader); | 394 headers->RemoveHeader(kLengthHeader); |
391 headers->RemoveHeader(kRangeHeader); | 395 headers->RemoveHeader(kRangeHeader); |
392 | 396 |
393 if (byte_range_.IsValid()) { | 397 if (byte_range_.IsValid()) { |
394 headers->ReplaceStatusLine("HTTP/1.1 416 Requested Range Not Satisfiable"); | 398 headers->ReplaceStatusLine("HTTP/1.1 416 Requested Range Not Satisfiable"); |
395 headers->AddHeader(base::StringPrintf("%s: bytes 0-0/%" PRId64, | 399 headers->AddHeader(base::StringPrintf( |
396 kRangeHeader, resource_size_)); | 400 "%s: bytes 0-0/%" PRId64, kRangeHeader, resource_size_)); |
397 headers->AddHeader(base::StringPrintf("%s: 0", kLengthHeader)); | 401 headers->AddHeader(base::StringPrintf("%s: 0", kLengthHeader)); |
398 } else { | 402 } else { |
399 // TODO(rvargas): Is it safe to change the protocol version? | 403 // TODO(rvargas): Is it safe to change the protocol version? |
400 headers->ReplaceStatusLine("HTTP/1.1 200 OK"); | 404 headers->ReplaceStatusLine("HTTP/1.1 200 OK"); |
401 DCHECK_NE(resource_size_, 0); | 405 DCHECK_NE(resource_size_, 0); |
402 headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader, | 406 headers->AddHeader( |
403 resource_size_)); | 407 base::StringPrintf("%s: %" PRId64, kLengthHeader, resource_size_)); |
404 } | 408 } |
405 } | 409 } |
406 | 410 |
407 void PartialData::FixContentLength(HttpResponseHeaders* headers) { | 411 void PartialData::FixContentLength(HttpResponseHeaders* headers) { |
408 headers->RemoveHeader(kLengthHeader); | 412 headers->RemoveHeader(kLengthHeader); |
409 headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader, | 413 headers->AddHeader( |
410 resource_size_)); | 414 base::StringPrintf("%s: %" PRId64, kLengthHeader, resource_size_)); |
411 } | 415 } |
412 | 416 |
413 int PartialData::CacheRead( | 417 int PartialData::CacheRead(disk_cache::Entry* entry, |
414 disk_cache::Entry* entry, IOBuffer* data, int data_len, | 418 IOBuffer* data, |
415 const net::CompletionCallback& callback) { | 419 int data_len, |
| 420 const net::CompletionCallback& callback) { |
416 int read_len = std::min(data_len, cached_min_len_); | 421 int read_len = std::min(data_len, cached_min_len_); |
417 if (!read_len) | 422 if (!read_len) |
418 return 0; | 423 return 0; |
419 | 424 |
420 int rv = 0; | 425 int rv = 0; |
421 if (sparse_entry_) { | 426 if (sparse_entry_) { |
422 rv = entry->ReadSparseData(current_range_start_, data, read_len, | 427 rv = entry->ReadSparseData(current_range_start_, data, read_len, callback); |
423 callback); | |
424 } else { | 428 } else { |
425 if (current_range_start_ > kint32max) | 429 if (current_range_start_ > kint32max) |
426 return ERR_INVALID_ARGUMENT; | 430 return ERR_INVALID_ARGUMENT; |
427 | 431 |
428 rv = entry->ReadData(kDataStream, static_cast<int>(current_range_start_), | 432 rv = entry->ReadData(kDataStream, |
429 data, read_len, callback); | 433 static_cast<int>(current_range_start_), |
| 434 data, |
| 435 read_len, |
| 436 callback); |
430 } | 437 } |
431 return rv; | 438 return rv; |
432 } | 439 } |
433 | 440 |
434 int PartialData::CacheWrite( | 441 int PartialData::CacheWrite(disk_cache::Entry* entry, |
435 disk_cache::Entry* entry, IOBuffer* data, int data_len, | 442 IOBuffer* data, |
436 const net::CompletionCallback& callback) { | 443 int data_len, |
| 444 const net::CompletionCallback& callback) { |
437 DVLOG(3) << "To write: " << data_len; | 445 DVLOG(3) << "To write: " << data_len; |
438 if (sparse_entry_) { | 446 if (sparse_entry_) { |
439 return entry->WriteSparseData( | 447 return entry->WriteSparseData( |
440 current_range_start_, data, data_len, callback); | 448 current_range_start_, data, data_len, callback); |
441 } else { | 449 } else { |
442 if (current_range_start_ > kint32max) | 450 if (current_range_start_ > kint32max) |
443 return ERR_INVALID_ARGUMENT; | 451 return ERR_INVALID_ARGUMENT; |
444 | 452 |
445 return entry->WriteData(kDataStream, static_cast<int>(current_range_start_), | 453 return entry->WriteData(kDataStream, |
446 data, data_len, callback, true); | 454 static_cast<int>(current_range_start_), |
| 455 data, |
| 456 data_len, |
| 457 callback, |
| 458 true); |
447 } | 459 } |
448 } | 460 } |
449 | 461 |
450 void PartialData::OnCacheReadCompleted(int result) { | 462 void PartialData::OnCacheReadCompleted(int result) { |
451 DVLOG(3) << "Read: " << result; | 463 DVLOG(3) << "Read: " << result; |
452 if (result > 0) { | 464 if (result > 0) { |
453 current_range_start_ += result; | 465 current_range_start_ += result; |
454 cached_min_len_ -= result; | 466 cached_min_len_ -= result; |
455 DCHECK_GE(cached_min_len_, 0); | 467 DCHECK_GE(cached_min_len_, 0); |
456 } | 468 } |
457 } | 469 } |
458 | 470 |
459 void PartialData::OnNetworkReadCompleted(int result) { | 471 void PartialData::OnNetworkReadCompleted(int result) { |
460 if (result > 0) | 472 if (result > 0) |
461 current_range_start_ += result; | 473 current_range_start_ += result; |
462 } | 474 } |
463 | 475 |
464 int PartialData::GetNextRangeLen() { | 476 int PartialData::GetNextRangeLen() { |
465 int64 range_len = | 477 int64 range_len = |
466 byte_range_.HasLastBytePosition() ? | 478 byte_range_.HasLastBytePosition() |
467 byte_range_.last_byte_position() - current_range_start_ + 1 : | 479 ? byte_range_.last_byte_position() - current_range_start_ + 1 |
468 kint32max; | 480 : kint32max; |
469 if (range_len > kint32max) | 481 if (range_len > kint32max) |
470 range_len = kint32max; | 482 range_len = kint32max; |
471 return static_cast<int32>(range_len); | 483 return static_cast<int32>(range_len); |
472 } | 484 } |
473 | 485 |
474 void PartialData::GetAvailableRangeCompleted(int result, int64 start) { | 486 void PartialData::GetAvailableRangeCompleted(int result, int64 start) { |
475 DCHECK(!callback_.is_null()); | 487 DCHECK(!callback_.is_null()); |
476 DCHECK_NE(ERR_IO_PENDING, result); | 488 DCHECK_NE(ERR_IO_PENDING, result); |
477 | 489 |
478 cached_start_ = start; | 490 cached_start_ = start; |
479 cached_min_len_ = result; | 491 cached_min_len_ = result; |
480 if (result >= 0) | 492 if (result >= 0) |
481 result = 1; // Return success, go ahead and validate the entry. | 493 result = 1; // Return success, go ahead and validate the entry. |
482 | 494 |
483 CompletionCallback cb = callback_; | 495 CompletionCallback cb = callback_; |
484 callback_.Reset(); | 496 callback_.Reset(); |
485 cb.Run(result); | 497 cb.Run(result); |
486 } | 498 } |
487 | 499 |
488 } // namespace net | 500 } // namespace net |
OLD | NEW |