Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1123)

Side by Side Diff: content/browser/download/download_request_core.cc

Issue 2660783002: Range request support for parallel download in DownloadRequestCore. (Closed)
Patch Set: Strong validator for all range request. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 "content/browser/download/download_request_core.h" 5 #include "content/browser/download/download_request_core.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/callback_helpers.h" 10 #include "base/callback_helpers.h"
(...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after
151 else 151 else
152 load_flags |= net::LOAD_SKIP_CACHE_VALIDATION; 152 load_flags |= net::LOAD_SKIP_CACHE_VALIDATION;
153 } else { 153 } else {
154 load_flags |= net::LOAD_DISABLE_CACHE; 154 load_flags |= net::LOAD_DISABLE_CACHE;
155 } 155 }
156 request->SetLoadFlags(load_flags); 156 request->SetLoadFlags(load_flags);
157 157
158 bool has_last_modified = !params->last_modified().empty(); 158 bool has_last_modified = !params->last_modified().empty();
159 bool has_etag = !params->etag().empty(); 159 bool has_etag = !params->etag().empty();
160 160
161 // If we've asked for a range, we want to make sure that we only get that 161 // Strong validator(i.e. etag or last modified) is required in range requests
162 // range if our current copy of the information is good. We shouldn't be 162 // for download resumption and parallel download.
163 // asked to continue if we don't have a verifier. 163 DCHECK((params->offset() == 0 &&
164 DCHECK(params->offset() == 0 || has_etag || has_last_modified); 164 params->length() == DownloadSaveInfo::kLengthUnknown) ||
165 has_etag || has_last_modified);
165 166
166 // If we're not at the beginning of the file, retrieve only the remaining 167 // Add "Range" and "If-Range" request header fields for download resumption
167 // portion. 168 // with strong validator.
168 if (params->offset() > 0 && (has_etag || has_last_modified)) { 169 if (params->offset() > 0 &&
170 params->length() == DownloadSaveInfo::kLengthUnknown &&
171 (has_etag || has_last_modified)) {
169 request->SetExtraRequestHeaderByName( 172 request->SetExtraRequestHeaderByName(
170 "Range", base::StringPrintf("bytes=%" PRId64 "-", params->offset()), 173 "Range", base::StringPrintf("bytes=%" PRId64 "-", params->offset()),
171 true); 174 true);
172 175
173 // In accordance with RFC 2616 Section 14.27, use If-Range to specify that 176 // In accordance with RFC 2616 Section 14.27, use If-Range to specify that
asanka 2017/02/01 02:53:36 This is now RFC 7233 Section 3.2 ( https://tools.i
xingliu 2017/02/01 20:25:46 Oh, yes, updated all RFC 2616 to new standards in
174 // the server return the entire entity if the validator doesn't match. 177 // the server return the entire entity if the validator doesn't match.
175 // Last-Modified can be used in the absence of ETag as a validator if the 178 // Last-Modified can be used in the absence of ETag as a validator if the
176 // response headers satisfied the HttpUtil::HasStrongValidators() predicate. 179 // response headers satisfied the HttpUtil::HasStrongValidators() predicate.
177 // 180 //
178 // This function assumes that HasStrongValidators() was true and that the 181 // This function assumes that HasStrongValidators() was true and that the
179 // ETag and Last-Modified header values supplied are valid. 182 // ETag and Last-Modified header values supplied are valid.
180 request->SetExtraRequestHeaderByName( 183 request->SetExtraRequestHeaderByName(
181 "If-Range", has_etag ? params->etag() : params->last_modified(), true); 184 "If-Range", has_etag ? params->etag() : params->last_modified(), true);
182 } 185 }
183 186
187 // Add "Range" request header for new download if length is specified.
188 // Strong validator is required to ensure range requests are downloading the
189 // same content.
190 if (params->length() > 0 && (has_etag || has_last_modified)) {
191 request->SetExtraRequestHeaderByName(
asanka 2017/02/01 02:53:36 Also need an If-Range header for this case. Can y
xingliu 2017/02/01 20:25:46 Done.
192 "Range",
193 base::StringPrintf("bytes=%" PRId64 "-%" PRId64, params->offset(),
194 params->offset() + params->length() - 1),
195 true);
196 }
197
184 // Downloads are treated as top level navigations. Hence the first-party 198 // Downloads are treated as top level navigations. Hence the first-party
185 // origin for cookies is always based on the target URL and is updated on 199 // origin for cookies is always based on the target URL and is updated on
186 // redirects. 200 // redirects.
187 request->set_first_party_for_cookies(params->url()); 201 request->set_first_party_for_cookies(params->url());
188 request->set_first_party_url_policy( 202 request->set_first_party_url_policy(
189 net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT); 203 net::URLRequest::UPDATE_FIRST_PARTY_URL_ON_REDIRECT);
190 request->set_initiator(params->initiator()); 204 request->set_initiator(params->initiator());
191 205
192 for (const auto& header : params->request_headers()) 206 for (const auto& header : params->request_headers())
193 request->SetExtraRequestHeaderByName(header.first, header.second, 207 request->SetExtraRequestHeaderByName(header.first, header.second,
(...skipping 385 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 return DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN; 593 return DOWNLOAD_INTERRUPT_REASON_SERVER_FORBIDDEN;
580 break; 594 break;
581 default: // All other errors. 595 default: // All other errors.
582 // Redirection and informational codes should have been handled earlier 596 // Redirection and informational codes should have been handled earlier
583 // in the stack. 597 // in the stack.
584 DCHECK_NE(3, http_headers.response_code() / 100); 598 DCHECK_NE(3, http_headers.response_code() / 100);
585 DCHECK_NE(1, http_headers.response_code() / 100); 599 DCHECK_NE(1, http_headers.response_code() / 100);
586 return DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED; 600 return DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED;
587 } 601 }
588 602
589 if (save_info && save_info->offset > 0) { 603 // The caller is expecting a partial response.
590 // The caller is expecting a partial response. 604 if (save_info && (save_info->offset > 0 || save_info->length > 0)) {
591
592 if (http_headers.response_code() != net::HTTP_PARTIAL_CONTENT) { 605 if (http_headers.response_code() != net::HTTP_PARTIAL_CONTENT) {
asanka 2017/02/01 02:53:37 For cases where we were attempting a slice, this s
xingliu 2017/02/01 20:25:46 Done. This will pair with the If-Range added abov
593 // Requested a partial range, but received the entire response. 606 // Requested a partial range, but received the entire response.
594 save_info->offset = 0; 607 save_info->offset = 0;
608 save_info->length = DownloadSaveInfo::kLengthUnknown;
595 save_info->hash_of_partial_file.clear(); 609 save_info->hash_of_partial_file.clear();
596 save_info->hash_state.reset(); 610 save_info->hash_state.reset();
597 return DOWNLOAD_INTERRUPT_REASON_NONE; 611 return DOWNLOAD_INTERRUPT_REASON_NONE;
598 } 612 }
599 613
600 int64_t first_byte = -1; 614 int64_t first_byte = -1;
601 int64_t last_byte = -1; 615 int64_t last_byte = -1;
602 int64_t length = -1; 616 int64_t length = -1;
603 if (!http_headers.GetContentRangeFor206(&first_byte, &last_byte, &length)) 617 if (!http_headers.GetContentRangeFor206(&first_byte, &last_byte, &length))
604 return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; 618 return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT;
605 DCHECK_GE(first_byte, 0); 619 DCHECK_GE(first_byte, 0);
606 620
607 if (first_byte != save_info->offset) { 621 if (first_byte != save_info->offset ||
622 (save_info->length > 0 &&
623 last_byte != save_info->offset + save_info->length - 1)) {
608 // The server returned a different range than the one we requested. Assume 624 // The server returned a different range than the one we requested. Assume
609 // the response is bad. 625 // the response is bad.
610 // 626 //
611 // In the future we should consider allowing offsets that are less than 627 // In the future we should consider allowing offsets that are less than
612 // the offset we've requested, since in theory we can truncate the partial 628 // the offset we've requested, since in theory we can truncate the partial
613 // file at the offset and continue. 629 // file at the offset and continue.
614 return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; 630 return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT;
615 } 631 }
616 632
617 return DOWNLOAD_INTERRUPT_REASON_NONE; 633 return DOWNLOAD_INTERRUPT_REASON_NONE;
618 } 634 }
619 635
620 if (http_headers.response_code() == net::HTTP_PARTIAL_CONTENT) 636 if (http_headers.response_code() == net::HTTP_PARTIAL_CONTENT)
621 return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT; 637 return DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT;
622 638
623 return DOWNLOAD_INTERRUPT_REASON_NONE; 639 return DOWNLOAD_INTERRUPT_REASON_NONE;
624 } 640 }
625 641
626 } // namespace content 642 } // namespace content
OLDNEW
« no previous file with comments | « no previous file | content/browser/download/download_request_core_unittest.cc » ('j') | content/public/browser/download_save_info.h » ('J')

Powered by Google App Engine
This is Rietveld 408576698