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" |
11 #include "base/strings/string_number_conversions.h" | 11 #include "base/strings/string_number_conversions.h" |
12 #include "base/strings/string_util.h" | 12 #include "base/strings/string_util.h" |
13 #include "base/strings/stringprintf.h" | 13 #include "base/strings/stringprintf.h" |
14 #include "net/base/net_errors.h" | 14 #include "net/base/net_errors.h" |
15 #include "net/disk_cache/disk_cache.h" | 15 #include "net/disk_cache/disk_cache.h" |
16 #include "net/http/http_response_headers.h" | 16 #include "net/http/http_response_headers.h" |
17 #include "net/http/http_util.h" | 17 #include "net/http/http_util.h" |
18 | 18 |
19 namespace net { | 19 namespace net { |
20 | 20 |
21 namespace { | 21 namespace { |
22 | 22 |
23 // The headers that we have to process. | 23 // The headers that we have to process. |
24 const char kLengthHeader[] = "Content-Length"; | 24 const char kLengthHeader[] = "Content-Length"; |
25 const char kRangeHeader[] = "Content-Range"; | 25 const char kRangeHeader[] = "Content-Range"; |
26 const int kDataStream = 1; | 26 const int kDataStream = 1; |
| 27 const int64 kUnbounded = kint64max; |
27 | 28 |
28 } // namespace | 29 } // namespace |
29 | 30 |
30 PartialData::PartialData() | 31 PartialData::PartialData() |
31 : current_range_start_(0), | 32 : current_range_start_(0), |
32 current_range_end_(0), | 33 current_range_end_(0), |
33 cached_start_(0), | 34 cached_start_(0), |
34 resource_size_(0), | 35 resource_size_(0), |
35 cached_min_len_(0), | 36 cached_min_len_(0), |
36 range_present_(false), | 37 range_present_(false), |
(...skipping 16 matching lines...) Expand all Loading... |
53 if (!HttpUtil::ParseRangeHeader(range_header, &ranges) || ranges.size() != 1) | 54 if (!HttpUtil::ParseRangeHeader(range_header, &ranges) || ranges.size() != 1) |
54 return false; | 55 return false; |
55 | 56 |
56 // We can handle this range request. | 57 // We can handle this range request. |
57 byte_range_ = ranges[0]; | 58 byte_range_ = ranges[0]; |
58 if (!byte_range_.IsValid()) | 59 if (!byte_range_.IsValid()) |
59 return false; | 60 return false; |
60 | 61 |
61 current_range_start_ = byte_range_.first_byte_position(); | 62 current_range_start_ = byte_range_.first_byte_position(); |
62 | 63 |
63 DVLOG(1) << "Range start: " << current_range_start_ << " end: " << | 64 DVLOG(1) << "Range start: " << current_range_start_ |
64 byte_range_.last_byte_position(); | 65 << " end: " << byte_range_.last_byte_position(); |
65 return true; | 66 return true; |
66 } | 67 } |
67 | 68 |
68 void PartialData::SetHeaders(const HttpRequestHeaders& headers) { | 69 void PartialData::SetHeaders(const HttpRequestHeaders& headers) { |
69 DCHECK(extra_headers_.IsEmpty()); | 70 DCHECK(extra_headers_.IsEmpty()); |
70 extra_headers_.CopyFrom(headers); | 71 extra_headers_.CopyFrom(headers); |
71 } | 72 } |
72 | 73 |
73 void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const { | 74 void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const { |
74 DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange()); | 75 DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange()); |
(...skipping 12 matching lines...) Expand all Loading... |
87 HttpByteRange::Bounded( | 88 HttpByteRange::Bounded( |
88 current_range_start_, end).GetHeaderValue()); | 89 current_range_start_, end).GetHeaderValue()); |
89 } | 90 } |
90 } | 91 } |
91 | 92 |
92 int PartialData::ShouldValidateCache(disk_cache::Entry* entry, | 93 int PartialData::ShouldValidateCache(disk_cache::Entry* entry, |
93 const CompletionCallback& callback) { | 94 const CompletionCallback& callback) { |
94 DCHECK_GE(current_range_start_, 0); | 95 DCHECK_GE(current_range_start_, 0); |
95 | 96 |
96 // Scan the disk cache for the first cached portion within this range. | 97 // Scan the disk cache for the first cached portion within this range. |
97 int len = GetNextRangeLen(); | 98 int64 current_range_len = |
98 if (!len) | 99 byte_range_.HasLastBytePosition() |
| 100 ? byte_range_.last_byte_position() - current_range_start_ + 1 |
| 101 : kUnbounded; |
| 102 if (!current_range_len) |
99 return 0; | 103 return 0; |
100 | 104 |
101 DVLOG(3) << "ShouldValidateCache len: " << len; | 105 DVLOG(3) << "ShouldValidateCache current_range_len: " << current_range_len; |
102 | 106 |
103 if (sparse_entry_) { | 107 if (sparse_entry_) { |
104 DCHECK(callback_.is_null()); | 108 DCHECK(callback_.is_null()); |
105 int64* start = new int64; | 109 int64* start = new int64; |
| 110 // TODO(asanka): Use the full |current_range_len| when int64_t is plumbed |
| 111 // all the way through. |
| 112 int cached_len = std::min<int64>(kint32max, current_range_len); |
| 113 |
106 // This callback now owns "start". We make sure to keep it | 114 // This callback now owns "start". We make sure to keep it |
107 // in a local variable since we want to use it later. | 115 // in a local variable since we want to use it later. |
108 CompletionCallback cb = | 116 CompletionCallback cb = |
109 base::Bind(&PartialData::GetAvailableRangeCompleted, | 117 base::Bind(&PartialData::GetAvailableRangeCompleted, |
110 weak_factory_.GetWeakPtr(), base::Owned(start)); | 118 weak_factory_.GetWeakPtr(), base::Owned(start)); |
111 cached_min_len_ = | 119 cached_min_len_ = |
112 entry->GetAvailableRange(current_range_start_, len, start, cb); | 120 entry->GetAvailableRange(current_range_start_, cached_len, start, cb); |
113 | 121 |
114 if (cached_min_len_ == ERR_IO_PENDING) { | 122 if (cached_min_len_ == ERR_IO_PENDING) { |
115 callback_ = callback; | 123 callback_ = callback; |
116 return ERR_IO_PENDING; | 124 return ERR_IO_PENDING; |
117 } else { | 125 } else { |
118 cached_start_ = *start; | 126 cached_start_ = *start; |
119 } | 127 } |
120 } else if (!truncated_) { | 128 } else if (!truncated_) { |
121 if (byte_range_.HasFirstBytePosition() && | 129 if (byte_range_.HasFirstBytePosition() && |
122 byte_range_.first_byte_position() >= resource_size_) { | 130 byte_range_.first_byte_position() >= resource_size_) { |
123 // The caller should take care of this condition because we should have | 131 // The caller should take care of this condition because we should have |
124 // failed IsRequestedRangeOK(), but it's better to be consistent here. | 132 // failed IsRequestedRangeOK(), but it's better to be consistent here. |
125 len = 0; | 133 current_range_len = 0; |
126 } | 134 } |
127 cached_min_len_ = len; | 135 cached_min_len_ = current_range_len; |
128 cached_start_ = current_range_start_; | 136 cached_start_ = current_range_start_; |
129 } | 137 } |
130 | 138 |
131 if (cached_min_len_ < 0) | 139 if (cached_min_len_ < 0) |
132 return cached_min_len_; | 140 return cached_min_len_; |
133 | 141 |
134 // Return a positive number to indicate success (versus error or finished). | 142 // Return a positive number to indicate success (versus error or finished). |
135 return 1; | 143 return 1; |
136 } | 144 } |
137 | 145 |
138 void PartialData::PrepareCacheValidation(disk_cache::Entry* entry, | 146 void PartialData::PrepareCacheValidation(disk_cache::Entry* entry, |
139 HttpRequestHeaders* headers) { | 147 HttpRequestHeaders* headers) { |
140 DCHECK_GE(current_range_start_, 0); | 148 DCHECK_GE(current_range_start_, 0); |
141 DCHECK_GE(cached_min_len_, 0); | 149 DCHECK_GE(cached_min_len_, 0); |
142 | 150 |
143 int len = GetNextRangeLen(); | 151 int64 current_range_len = |
144 DCHECK_NE(0, len); | 152 byte_range_.HasLastBytePosition() |
| 153 ? byte_range_.last_byte_position() - current_range_start_ + 1 |
| 154 : kUnbounded; |
| 155 // PrepareCacheValidation shouldn't have been called if ShouldValidateCache() |
| 156 // returned 0. |
| 157 DCHECK_NE(0, current_range_len); |
145 range_present_ = false; | 158 range_present_ = false; |
146 | 159 |
147 headers->CopyFrom(extra_headers_); | 160 headers->CopyFrom(extra_headers_); |
148 | 161 |
149 if (!cached_min_len_) { | 162 if (!cached_min_len_) { |
150 // We don't have anything else stored. | 163 // We don't have anything else stored. |
151 final_range_ = true; | 164 final_range_ = true; |
152 cached_start_ = | 165 cached_start_ = byte_range_.HasLastBytePosition() |
153 byte_range_.HasLastBytePosition() ? current_range_start_ + len : 0; | 166 ? current_range_start_ + current_range_len |
| 167 : 0; |
154 } | 168 } |
155 | 169 |
156 if (current_range_start_ == cached_start_) { | 170 if (current_range_start_ == cached_start_ && cached_min_len_) { |
157 // The data lives in the cache. | 171 // The data lives in the cache. |
158 range_present_ = true; | 172 range_present_ = true; |
159 current_range_end_ = cached_start_ + cached_min_len_ - 1; | 173 current_range_end_ = cached_start_ + cached_min_len_ - 1; |
160 if (len == cached_min_len_) | 174 if (current_range_len == cached_min_len_) |
161 final_range_ = true; | 175 final_range_ = true; |
162 } else { | 176 } else { |
163 // This range is not in the cache. | 177 // This range is not in the cache. |
164 current_range_end_ = cached_start_ - 1; | 178 current_range_end_ = cached_start_ - 1; |
165 } | 179 } |
| 180 |
166 headers->SetHeader( | 181 headers->SetHeader( |
167 HttpRequestHeaders::kRange, | 182 HttpRequestHeaders::kRange, |
168 HttpByteRange::Bounded(current_range_start_, current_range_end_) | 183 HttpByteRange::Bounded(current_range_start_, current_range_end_) |
169 .GetHeaderValue()); | 184 .GetHeaderValue()); |
170 } | 185 } |
171 | 186 |
172 bool PartialData::IsCurrentRangeCached() const { | 187 bool PartialData::IsCurrentRangeCached() const { |
173 return range_present_; | 188 return range_present_; |
174 } | 189 } |
175 | 190 |
176 bool PartialData::IsLastRange() const { | 191 bool PartialData::IsLastRange() const { |
177 return final_range_; | 192 return final_range_; |
178 } | 193 } |
179 | 194 |
180 bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers, | 195 bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers, |
181 disk_cache::Entry* entry, | 196 disk_cache::Entry* entry, |
182 bool truncated) { | 197 bool truncated) { |
183 resource_size_ = 0; | 198 resource_size_ = 0; |
184 if (truncated) { | 199 if (truncated) { |
185 DCHECK_EQ(headers->response_code(), 200); | 200 DCHECK_EQ(headers->response_code(), 200); |
186 // We don't have the real length and the user may be trying to create a | 201 // 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. | 202 // sparse entry so let's not write to this entry. |
| 203 std::string header_string; |
| 204 headers->GetNormalizedHeaders(&header_string); |
188 if (byte_range_.IsValid()) | 205 if (byte_range_.IsValid()) |
189 return false; | 206 return false; |
190 | 207 |
191 if (!headers->HasStrongValidators()) | 208 if (!headers->HasStrongValidators()) |
192 return false; | 209 return false; |
193 | 210 |
194 // Now we avoid resume if there is no content length, but that was not | 211 // Now we avoid resume if there is no content length, but that was not |
195 // always the case so double check here. | 212 // always the case so double check here. |
196 int64 total_length = headers->GetContentLength(); | 213 int64 total_length = headers->GetContentLength(); |
197 if (total_length <= 0) | 214 if (total_length <= 0) |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 } | 248 } |
232 | 249 |
233 void PartialData::SetRangeToStartDownload() { | 250 void PartialData::SetRangeToStartDownload() { |
234 DCHECK(truncated_); | 251 DCHECK(truncated_); |
235 DCHECK(!sparse_entry_); | 252 DCHECK(!sparse_entry_); |
236 current_range_start_ = 0; | 253 current_range_start_ = 0; |
237 cached_start_ = 0; | 254 cached_start_ = 0; |
238 initial_validation_ = false; | 255 initial_validation_ = false; |
239 } | 256 } |
240 | 257 |
| 258 bool PartialData::SkipCacheForRemainder() { |
| 259 if (byte_range_.HasLastBytePosition() && |
| 260 current_range_start_ > byte_range_.last_byte_position()) { |
| 261 return false; |
| 262 } |
| 263 |
| 264 // Don't look for any more cached sparse ranges. |
| 265 sparse_entry_ = false; |
| 266 |
| 267 // Ignoring the remainder of the cached entry is equivalent to the cache entry |
| 268 // having been truncated. |
| 269 truncated_ = true; |
| 270 |
| 271 // Current range is not cached. |
| 272 cached_start_ = 0; |
| 273 cached_min_len_ = 0; |
| 274 return true; |
| 275 } |
| 276 |
241 bool PartialData::IsRequestedRangeOK() { | 277 bool PartialData::IsRequestedRangeOK() { |
242 if (byte_range_.IsValid()) { | 278 if (byte_range_.IsValid()) { |
243 if (!byte_range_.ComputeBounds(resource_size_)) | 279 if (!byte_range_.ComputeBounds(resource_size_)) |
244 return false; | 280 return false; |
245 if (truncated_) | 281 if (truncated_) |
246 return true; | 282 return true; |
247 | 283 |
248 if (current_range_start_ < 0) | 284 if (current_range_start_ < 0) |
249 current_range_start_ = byte_range_.first_byte_position(); | 285 current_range_start_ = byte_range_.first_byte_position(); |
250 } else { | 286 } else { |
(...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
358 void PartialData::FixContentLength(HttpResponseHeaders* headers) { | 394 void PartialData::FixContentLength(HttpResponseHeaders* headers) { |
359 headers->RemoveHeader(kLengthHeader); | 395 headers->RemoveHeader(kLengthHeader); |
360 headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader, | 396 headers->AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader, |
361 resource_size_)); | 397 resource_size_)); |
362 } | 398 } |
363 | 399 |
364 int PartialData::CacheRead(disk_cache::Entry* entry, | 400 int PartialData::CacheRead(disk_cache::Entry* entry, |
365 IOBuffer* data, | 401 IOBuffer* data, |
366 int data_len, | 402 int data_len, |
367 const CompletionCallback& callback) { | 403 const CompletionCallback& callback) { |
368 int read_len = std::min(data_len, cached_min_len_); | 404 int read_len = std::min<int64>(data_len, cached_min_len_); |
369 if (!read_len) | 405 if (!read_len) |
370 return 0; | 406 return 0; |
371 | 407 |
372 int rv = 0; | 408 int rv = 0; |
373 if (sparse_entry_) { | 409 if (sparse_entry_) { |
374 rv = entry->ReadSparseData(current_range_start_, data, read_len, | 410 rv = entry->ReadSparseData(current_range_start_, data, read_len, |
375 callback); | 411 callback); |
376 } else { | 412 } else { |
377 if (current_range_start_ > kint32max) | 413 if (current_range_start_ > kint32max) |
378 return ERR_INVALID_ARGUMENT; | 414 return ERR_INVALID_ARGUMENT; |
(...skipping 28 matching lines...) Expand all Loading... |
407 cached_min_len_ -= result; | 443 cached_min_len_ -= result; |
408 DCHECK_GE(cached_min_len_, 0); | 444 DCHECK_GE(cached_min_len_, 0); |
409 } | 445 } |
410 } | 446 } |
411 | 447 |
412 void PartialData::OnNetworkReadCompleted(int result) { | 448 void PartialData::OnNetworkReadCompleted(int result) { |
413 if (result > 0) | 449 if (result > 0) |
414 current_range_start_ += result; | 450 current_range_start_ += result; |
415 } | 451 } |
416 | 452 |
417 int PartialData::GetNextRangeLen() { | |
418 int64 range_len = | |
419 byte_range_.HasLastBytePosition() ? | |
420 byte_range_.last_byte_position() - current_range_start_ + 1 : | |
421 kint32max; | |
422 if (range_len > kint32max) | |
423 range_len = kint32max; | |
424 return static_cast<int32>(range_len); | |
425 } | |
426 | |
427 void PartialData::GetAvailableRangeCompleted(int64* start, int result) { | 453 void PartialData::GetAvailableRangeCompleted(int64* start, int result) { |
428 DCHECK(!callback_.is_null()); | 454 DCHECK(!callback_.is_null()); |
429 DCHECK_NE(ERR_IO_PENDING, result); | 455 DCHECK_NE(ERR_IO_PENDING, result); |
430 | 456 |
431 cached_start_ = *start; | 457 cached_start_ = *start; |
432 cached_min_len_ = result; | 458 cached_min_len_ = result; |
433 if (result >= 0) | 459 if (result >= 0) |
434 result = 1; // Return success, go ahead and validate the entry. | 460 result = 1; // Return success, go ahead and validate the entry. |
435 | 461 |
436 CompletionCallback cb = callback_; | 462 CompletionCallback cb = callback_; |
437 callback_.Reset(); | 463 callback_.Reset(); |
438 cb.Run(result); | 464 cb.Run(result); |
439 } | 465 } |
440 | 466 |
441 } // namespace net | 467 } // namespace net |
OLD | NEW |