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