partial_data.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461
  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
  3. // found in the LICENSE file.
  4. #include "net/http/partial_data.h"
  5. #include <limits>
  6. #include <utility>
  7. #include "base/bind.h"
  8. #include "base/callback_helpers.h"
  9. #include "base/format_macros.h"
  10. #include "base/logging.h"
  11. #include "base/strings/string_number_conversions.h"
  12. #include "base/strings/string_util.h"
  13. #include "base/strings/stringprintf.h"
  14. #include "net/base/net_errors.h"
  15. #include "net/disk_cache/disk_cache.h"
  16. #include "net/http/http_response_headers.h"
  17. #include "net/http/http_status_code.h"
  18. #include "net/http/http_util.h"
  19. namespace net {
  20. namespace {
  21. // The headers that we have to process.
  22. const char kLengthHeader[] = "Content-Length";
  23. const char kRangeHeader[] = "Content-Range";
  24. const int kDataStream = 1;
  25. } // namespace
  26. PartialData::PartialData() = default;
  27. PartialData::~PartialData() = default;
  28. bool PartialData::Init(const HttpRequestHeaders& headers) {
  29. std::string range_header;
  30. if (!headers.GetHeader(HttpRequestHeaders::kRange, &range_header)) {
  31. range_requested_ = false;
  32. return false;
  33. }
  34. range_requested_ = true;
  35. std::vector<HttpByteRange> ranges;
  36. if (!HttpUtil::ParseRangeHeader(range_header, &ranges) || ranges.size() != 1)
  37. return false;
  38. // We can handle this range request.
  39. byte_range_ = ranges[0];
  40. if (!byte_range_.IsValid())
  41. return false;
  42. current_range_start_ = byte_range_.first_byte_position();
  43. DVLOG(1) << "Range start: " << current_range_start_ << " end: " <<
  44. byte_range_.last_byte_position();
  45. return true;
  46. }
  47. void PartialData::SetHeaders(const HttpRequestHeaders& headers) {
  48. DCHECK(extra_headers_.IsEmpty());
  49. extra_headers_.CopyFrom(headers);
  50. }
  51. void PartialData::RestoreHeaders(HttpRequestHeaders* headers) const {
  52. DCHECK(current_range_start_ >= 0 || byte_range_.IsSuffixByteRange());
  53. int64_t end = byte_range_.IsSuffixByteRange()
  54. ? byte_range_.suffix_length()
  55. : byte_range_.last_byte_position();
  56. headers->CopyFrom(extra_headers_);
  57. if (truncated_ || !byte_range_.IsValid())
  58. return;
  59. if (current_range_start_ < 0) {
  60. headers->SetHeader(HttpRequestHeaders::kRange,
  61. HttpByteRange::Suffix(end).GetHeaderValue());
  62. } else {
  63. headers->SetHeader(HttpRequestHeaders::kRange,
  64. HttpByteRange::Bounded(
  65. current_range_start_, end).GetHeaderValue());
  66. }
  67. }
  68. int PartialData::ShouldValidateCache(disk_cache::Entry* entry,
  69. CompletionOnceCallback callback) {
  70. DCHECK_GE(current_range_start_, 0);
  71. // Scan the disk cache for the first cached portion within this range.
  72. int len = GetNextRangeLen();
  73. if (!len)
  74. return 0;
  75. DVLOG(3) << "ShouldValidateCache len: " << len;
  76. if (sparse_entry_) {
  77. DCHECK(callback_.is_null());
  78. disk_cache::RangeResultCallback cb = base::BindOnce(
  79. &PartialData::GetAvailableRangeCompleted, weak_factory_.GetWeakPtr());
  80. disk_cache::RangeResult range =
  81. entry->GetAvailableRange(current_range_start_, len, std::move(cb));
  82. cached_min_len_ =
  83. range.net_error == OK ? range.available_len : range.net_error;
  84. if (cached_min_len_ == ERR_IO_PENDING) {
  85. callback_ = std::move(callback);
  86. return ERR_IO_PENDING;
  87. } else {
  88. cached_start_ = range.start;
  89. }
  90. } else if (!truncated_) {
  91. if (byte_range_.HasFirstBytePosition() &&
  92. byte_range_.first_byte_position() >= resource_size_) {
  93. // The caller should take care of this condition because we should have
  94. // failed IsRequestedRangeOK(), but it's better to be consistent here.
  95. len = 0;
  96. }
  97. cached_min_len_ = len;
  98. cached_start_ = current_range_start_;
  99. }
  100. if (cached_min_len_ < 0)
  101. return cached_min_len_;
  102. // Return a positive number to indicate success (versus error or finished).
  103. return 1;
  104. }
  105. void PartialData::PrepareCacheValidation(disk_cache::Entry* entry,
  106. HttpRequestHeaders* headers) {
  107. DCHECK_GE(current_range_start_, 0);
  108. DCHECK_GE(cached_min_len_, 0);
  109. int len = GetNextRangeLen();
  110. DCHECK_NE(0, len);
  111. range_present_ = false;
  112. headers->CopyFrom(extra_headers_);
  113. if (!cached_min_len_) {
  114. // We don't have anything else stored.
  115. final_range_ = true;
  116. cached_start_ =
  117. byte_range_.HasLastBytePosition() ? current_range_start_ + len : 0;
  118. }
  119. if (current_range_start_ == cached_start_) {
  120. // The data lives in the cache.
  121. range_present_ = true;
  122. current_range_end_ = cached_start_ + cached_min_len_ - 1;
  123. if (len == cached_min_len_)
  124. final_range_ = true;
  125. } else {
  126. // This range is not in the cache.
  127. current_range_end_ = cached_start_ - 1;
  128. }
  129. headers->SetHeader(
  130. HttpRequestHeaders::kRange,
  131. HttpByteRange::Bounded(current_range_start_, current_range_end_)
  132. .GetHeaderValue());
  133. }
  134. bool PartialData::IsCurrentRangeCached() const {
  135. return range_present_;
  136. }
  137. bool PartialData::IsLastRange() const {
  138. return final_range_;
  139. }
  140. bool PartialData::UpdateFromStoredHeaders(const HttpResponseHeaders* headers,
  141. disk_cache::Entry* entry,
  142. bool truncated,
  143. bool writing_in_progress) {
  144. resource_size_ = 0;
  145. if (truncated) {
  146. DCHECK_EQ(headers->response_code(), 200);
  147. // We don't have the real length and the user may be trying to create a
  148. // sparse entry so let's not write to this entry.
  149. if (byte_range_.IsValid())
  150. return false;
  151. if (!headers->HasStrongValidators())
  152. return false;
  153. // Now we avoid resume if there is no content length, but that was not
  154. // always the case so double check here.
  155. int64_t total_length = headers->GetContentLength();
  156. if (total_length <= 0)
  157. return false;
  158. // In case we see a truncated entry, we first send a network request for
  159. // 1 byte range with If-Range: to probe server support for resumption.
  160. // The setting of |current_range_start_| and |cached_start_| below (with any
  161. // positive value of |cached_min_len_|) results in that.
  162. //
  163. // Setting |initial_validation_| to true is how this communicates to
  164. // HttpCache::Transaction that we're doing that (and that it's not the user
  165. // asking for one byte), so if it sees a 206 with that flag set it will call
  166. // SetRangeToStartDownload(), and then restart the process looking for the
  167. // entire file (which is what the user wanted), with the cache handling
  168. // the previous portion, and then a second network request for the entire
  169. // rest of the range. A 200 in response to the probe request can be simply
  170. // returned directly to the user.
  171. truncated_ = true;
  172. initial_validation_ = true;
  173. sparse_entry_ = false;
  174. int current_len = entry->GetDataSize(kDataStream);
  175. byte_range_.set_first_byte_position(current_len);
  176. resource_size_ = total_length;
  177. current_range_start_ = current_len;
  178. cached_min_len_ = current_len;
  179. cached_start_ = current_len + 1;
  180. return true;
  181. }
  182. sparse_entry_ = (headers->response_code() == net::HTTP_PARTIAL_CONTENT);
  183. if (writing_in_progress || sparse_entry_) {
  184. // |writing_in_progress| means another Transaction is still fetching the
  185. // body, so the only way we can see the length is if the server sent it
  186. // in Content-Length -- GetDataSize would just return what got written
  187. // thus far.
  188. //
  189. // |sparse_entry_| means a 206, and for those FixContentLength arranges it
  190. // so that Content-Length written to the cache has the full length (on wire
  191. // it's for a particular range only); while GetDataSize would be unusable
  192. // since the data is stored using WriteSparseData, and not in the usual data
  193. // stream.
  194. resource_size_ = headers->GetContentLength();
  195. if (resource_size_ <= 0)
  196. return false;
  197. } else {
  198. // If we can safely use GetDataSize, it's preferrable since it's usable for
  199. // things w/o Content-Length, such as chunked content.
  200. resource_size_ = entry->GetDataSize(kDataStream);
  201. }
  202. DVLOG(2) << "UpdateFromStoredHeaders size: " << resource_size_;
  203. if (sparse_entry_) {
  204. // If our previous is a 206, we need strong validators as we may be
  205. // stiching the cached data and network data together.
  206. if (!headers->HasStrongValidators())
  207. return false;
  208. // Make sure that this is really a sparse entry.
  209. return entry->CouldBeSparse();
  210. }
  211. return true;
  212. }
  213. void PartialData::SetRangeToStartDownload() {
  214. DCHECK(truncated_);
  215. DCHECK(!sparse_entry_);
  216. current_range_start_ = 0;
  217. cached_start_ = 0;
  218. initial_validation_ = false;
  219. }
  220. bool PartialData::IsRequestedRangeOK() {
  221. if (byte_range_.IsValid()) {
  222. if (!byte_range_.ComputeBounds(resource_size_))
  223. return false;
  224. if (truncated_)
  225. return true;
  226. if (current_range_start_ < 0)
  227. current_range_start_ = byte_range_.first_byte_position();
  228. } else {
  229. // This is not a range request but we have partial data stored.
  230. current_range_start_ = 0;
  231. byte_range_.set_last_byte_position(resource_size_ - 1);
  232. }
  233. bool rv = current_range_start_ >= 0;
  234. if (!rv)
  235. current_range_start_ = 0;
  236. return rv;
  237. }
  238. bool PartialData::ResponseHeadersOK(const HttpResponseHeaders* headers) {
  239. if (headers->response_code() == net::HTTP_NOT_MODIFIED) {
  240. if (!byte_range_.IsValid() || truncated_)
  241. return true;
  242. // We must have a complete range here.
  243. return byte_range_.HasFirstBytePosition() &&
  244. byte_range_.HasLastBytePosition();
  245. }
  246. int64_t start, end, total_length;
  247. if (!headers->GetContentRangeFor206(&start, &end, &total_length))
  248. return false;
  249. if (total_length <= 0)
  250. return false;
  251. DCHECK_EQ(headers->response_code(), 206);
  252. // A server should return a valid content length with a 206 (per the standard)
  253. // but relax the requirement because some servers don't do that.
  254. int64_t content_length = headers->GetContentLength();
  255. if (content_length > 0 && content_length != end - start + 1)
  256. return false;
  257. if (!resource_size_) {
  258. // First response. Update our values with the ones provided by the server.
  259. resource_size_ = total_length;
  260. if (!byte_range_.HasFirstBytePosition()) {
  261. byte_range_.set_first_byte_position(start);
  262. current_range_start_ = start;
  263. }
  264. if (!byte_range_.HasLastBytePosition())
  265. byte_range_.set_last_byte_position(end);
  266. } else if (resource_size_ != total_length) {
  267. return false;
  268. }
  269. if (truncated_) {
  270. if (!byte_range_.HasLastBytePosition())
  271. byte_range_.set_last_byte_position(end);
  272. }
  273. if (start != current_range_start_)
  274. return false;
  275. if (!current_range_end_) {
  276. // There is nothing in the cache.
  277. DCHECK(byte_range_.HasLastBytePosition());
  278. current_range_end_ = byte_range_.last_byte_position();
  279. if (current_range_end_ >= resource_size_) {
  280. // We didn't know the real file size, and the server is saying that the
  281. // requested range goes beyond the size. Fix it.
  282. current_range_end_ = end;
  283. byte_range_.set_last_byte_position(end);
  284. }
  285. }
  286. // If we received a range, but it's not exactly the range we asked for, avoid
  287. // trouble and signal an error.
  288. if (end != current_range_end_)
  289. return false;
  290. return true;
  291. }
  292. // We are making multiple requests to complete the range requested by the user.
  293. // Just assume that everything is fine and say that we are returning what was
  294. // requested.
  295. void PartialData::FixResponseHeaders(HttpResponseHeaders* headers,
  296. bool success) {
  297. if (truncated_)
  298. return;
  299. if (byte_range_.IsValid() && success) {
  300. headers->UpdateWithNewRange(byte_range_, resource_size_, !sparse_entry_);
  301. return;
  302. }
  303. if (byte_range_.IsValid()) {
  304. headers->ReplaceStatusLine("HTTP/1.1 416 Requested Range Not Satisfiable");
  305. headers->SetHeader(
  306. kRangeHeader, base::StringPrintf("bytes 0-0/%" PRId64, resource_size_));
  307. headers->SetHeader(kLengthHeader, "0");
  308. } else {
  309. // TODO(rvargas): Is it safe to change the protocol version?
  310. headers->ReplaceStatusLine("HTTP/1.1 200 OK");
  311. DCHECK_NE(resource_size_, 0);
  312. headers->RemoveHeader(kRangeHeader);
  313. headers->SetHeader(kLengthHeader,
  314. base::StringPrintf("%" PRId64, resource_size_));
  315. }
  316. }
  317. void PartialData::FixContentLength(HttpResponseHeaders* headers) {
  318. headers->SetHeader(kLengthHeader,
  319. base::StringPrintf("%" PRId64, resource_size_));
  320. }
  321. int PartialData::CacheRead(disk_cache::Entry* entry,
  322. IOBuffer* data,
  323. int data_len,
  324. CompletionOnceCallback callback) {
  325. int read_len = std::min(data_len, cached_min_len_);
  326. if (!read_len)
  327. return 0;
  328. int rv = 0;
  329. if (sparse_entry_) {
  330. rv = entry->ReadSparseData(current_range_start_, data, read_len,
  331. std::move(callback));
  332. } else {
  333. if (current_range_start_ > std::numeric_limits<int32_t>::max())
  334. return ERR_INVALID_ARGUMENT;
  335. rv = entry->ReadData(kDataStream, static_cast<int>(current_range_start_),
  336. data, read_len, std::move(callback));
  337. }
  338. return rv;
  339. }
  340. int PartialData::CacheWrite(disk_cache::Entry* entry,
  341. IOBuffer* data,
  342. int data_len,
  343. CompletionOnceCallback callback) {
  344. DVLOG(3) << "To write: " << data_len;
  345. if (sparse_entry_) {
  346. return entry->WriteSparseData(current_range_start_, data, data_len,
  347. std::move(callback));
  348. } else {
  349. if (current_range_start_ > std::numeric_limits<int32_t>::max())
  350. return ERR_INVALID_ARGUMENT;
  351. return entry->WriteData(kDataStream, static_cast<int>(current_range_start_),
  352. data, data_len, std::move(callback), true);
  353. }
  354. }
  355. void PartialData::OnCacheReadCompleted(int result) {
  356. DVLOG(3) << "Read: " << result;
  357. if (result > 0) {
  358. current_range_start_ += result;
  359. cached_min_len_ -= result;
  360. DCHECK_GE(cached_min_len_, 0);
  361. }
  362. }
  363. void PartialData::OnNetworkReadCompleted(int result) {
  364. if (result > 0)
  365. current_range_start_ += result;
  366. }
  367. int PartialData::GetNextRangeLen() {
  368. int64_t range_len =
  369. byte_range_.HasLastBytePosition()
  370. ? byte_range_.last_byte_position() - current_range_start_ + 1
  371. : std::numeric_limits<int32_t>::max();
  372. if (range_len > std::numeric_limits<int32_t>::max())
  373. range_len = std::numeric_limits<int32_t>::max();
  374. return static_cast<int32_t>(range_len);
  375. }
  376. void PartialData::GetAvailableRangeCompleted(
  377. const disk_cache::RangeResult& result) {
  378. DCHECK(!callback_.is_null());
  379. DCHECK_NE(ERR_IO_PENDING, result.net_error);
  380. int len_or_error =
  381. result.net_error == OK ? result.available_len : result.net_error;
  382. cached_start_ = result.start;
  383. cached_min_len_ = len_or_error;
  384. // ShouldValidateCache has an unusual convention where 0 denotes EOF,
  385. // so convert end of range to success (since there may be things that need
  386. // fetching from network or other ranges).
  387. std::move(callback_).Run(len_or_error >= 0 ? 1 : len_or_error);
  388. }
  389. } // namespace net