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

Unified Diff: content/browser/download/download_browsertest.cc

Issue 1544603003: [Downloads] Do not store error responses during resumption. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@unify-downloader-core
Patch Set: Created 4 years, 11 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 side-by-side diff with in-line comments
Download patch
Index: content/browser/download/download_browsertest.cc
diff --git a/content/browser/download/download_browsertest.cc b/content/browser/download/download_browsertest.cc
index 794e8327bf8dc9fe14eab0a932ba8036bffc26db..bd44f00446b329e6cc477b338b86be26f5e10f06 100644
--- a/content/browser/download/download_browsertest.cc
+++ b/content/browser/download/download_browsertest.cc
@@ -1121,6 +1121,197 @@ IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, StrongValidators) {
value);
}
+// Resumption should only attempt to contact the final URL if the download has a
+// URL chain.
+IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RedirectBeforeResume) {
+ TestDownloadRequestHandler request_handler_1(
+ GURL("http://example.com/first-url"));
+ request_handler_1.StartServingStaticResponse(
+ "HTTP/1.1 302 Redirect\r\n"
+ "Location: http://example.com/second-url\r\n"
+ "\r\n");
+
+ TestDownloadRequestHandler request_handler_2(
+ GURL("http://example.com/second-url"));
+ request_handler_2.StartServingStaticResponse(
+ "HTTP/1.1 302 Redirect\r\n"
+ "Location: http://example.com/third-url\r\n"
+ "\r\n");
+
+ TestDownloadRequestHandler request_handler_3(
+ GURL("http://example.com/third-url"));
+ request_handler_3.StartServingStaticResponse(
+ "HTTP/1.1 302 Redirect\r\n"
+ "Location: http://example.com/download\r\n"
+ "\r\n");
+
+ TestDownloadRequestHandler resumable_request_handler(
+ GURL("http://example.com/download"));
+ TestDownloadRequestHandler::Parameters parameters =
+ TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+ resumable_request_handler.StartServing(parameters);
+
+ DownloadItem* download = StartDownloadAndReturnItem(
+ initiator_shell_for_resumption(), request_handler_1.url());
+ WaitForInterrupt(download);
+
+ EXPECT_EQ(4u, download->GetUrlChain().size());
+ EXPECT_EQ(request_handler_1.url(), download->GetOriginalUrl());
+ EXPECT_EQ(resumable_request_handler.url(), download->GetURL());
+
+ // Now that the download is interrupted, make all intermediate servers return
+ // a 404. The only way a resumption request would succeed if the resumption
+ // request is sent to the final server in the chain.
+ const char k404Response[] = "HTTP/1.1 404 Not found\r\n\r\n";
+ request_handler_1.StartServingStaticResponse(k404Response);
+ request_handler_2.StartServingStaticResponse(k404Response);
+ request_handler_3.StartServingStaticResponse(k404Response);
+
+ PrepareToResume();
+ download->Resume();
+ WaitForCompletion(download);
+
+ ASSERT_NO_FATAL_FAILURE(ReadAndVerifyFileContents(
+ parameters.pattern_generator_seed, parameters.size,
+ download->GetTargetFilePath()));
+}
+
+// If a resumption request results in a redirect, the response should be ignored
+// and the download should be marked as interrupted again.
+IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, RedirectWhileResume) {
+ TestDownloadRequestHandler request_handler(
+ GURL("http://example.com/first-url"));
+ TestDownloadRequestHandler::Parameters parameters =
+ TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+ ++parameters.pattern_generator_seed;
+ request_handler.StartServing(parameters);
+
+ // We should never send a request to the decoy. If we do, the request will
+ // always succeed, which results in behavior that diverges from what we want,
+ // which is for the download to return to being interrupted.
+ TestDownloadRequestHandler decoy_request_handler(
+ GURL("http://example.com/decoy"));
+ decoy_request_handler.StartServing(TestDownloadRequestHandler::Parameters());
+
+ DownloadItem* download = StartDownloadAndReturnItem(
+ initiator_shell_for_resumption(), request_handler.url());
+ WaitForInterrupt(download);
+
+ // Upon resumption, the server starts responding with a redirect. This
+ // response should not be accepted.
+ request_handler.StartServingStaticResponse(
+ "HTTP/1.1 302 Redirect\r\n"
+ "Location: http://example.com/decoy\r\n"
+ "\r\n");
+ PrepareToResume();
+ download->Resume();
+ WaitForInterrupt(download);
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_UNREACHABLE,
+ download->GetLastReason());
+
+ // Back to the original request handler. Resumption should now succeed, and
+ // use the partial data it had prior to the first interruption.
+ request_handler.StartServing(parameters);
+ download->Resume();
+ WaitForCompletion(download);
+
+ ASSERT_EQ(parameters.size, download->GetReceivedBytes());
+ ASSERT_EQ(parameters.size, download->GetTotalBytes());
+ ASSERT_NO_FATAL_FAILURE(ReadAndVerifyFileContents(
+ parameters.pattern_generator_seed, parameters.size,
+ download->GetTargetFilePath()));
+
+ // Characterization risk: The next portion of the test examines the requests
+ // that were sent out while downloading our resource. These requests
+ // correspond to the requests that were generated by the browser and the
+ // downloads system and may change as implementation details change.
+ TestDownloadRequestHandler::CompletedRequests requests;
+ request_handler.GetCompletedRequestInfo(&requests);
+
+ ASSERT_EQ(3u, requests.size());
+
+ // None of the request should have transferred the entire resource. The
+ // redirect response shows up as a response with 0 bytes transferred.
+ EXPECT_GT(parameters.size, requests[0].transferred_byte_count);
+ EXPECT_EQ(0, requests[1].transferred_byte_count);
+ EXPECT_GT(parameters.size, requests[2].transferred_byte_count);
+}
+
+// If the server response for the resumption request specifies a bad range (i.e.
+// not the range that was requested or an invalid or missing Content-Range
+// header), then the download should be marked as interrupted again without
+// discarding the partial state.
+IN_PROC_BROWSER_TEST_P(DownloadResumptionContentTest, BadRangeHeader) {
+ TestDownloadRequestHandler request_handler;
+ TestDownloadRequestHandler::Parameters parameters =
+ TestDownloadRequestHandler::Parameters::WithSingleInterruption();
+ request_handler.StartServing(parameters);
+
+ DownloadItem* download = StartDownloadAndReturnItem(
+ initiator_shell_for_resumption(), request_handler.url());
+ WaitForInterrupt(download);
+
+ // Upon resumption, the server starts responding with a bad range header.
+ request_handler.StartServingStaticResponse(
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: bytes 1000000-2000000/3000000\r\n"
+ "\r\n");
+ PrepareToResume();
+ download->Resume();
+ WaitForInterrupt(download);
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
+ download->GetLastReason());
+
+ // Or this time, the server sends a response with an invalid Content-Range
+ // header.
+ request_handler.StartServingStaticResponse(
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Content-Range: ooga-booga-booga-booga\r\n"
+ "\r\n");
+ download->Resume();
+ WaitForInterrupt(download);
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
+ download->GetLastReason());
+
+ // Or no Content-Range header at all.
+ request_handler.StartServingStaticResponse(
+ "HTTP/1.1 206 Partial Content\r\n"
+ "Some-Headers: ooga-booga-booga-booga\r\n"
+ "\r\n");
+ download->Resume();
+ WaitForInterrupt(download);
+ EXPECT_EQ(DOWNLOAD_INTERRUPT_REASON_SERVER_BAD_CONTENT,
+ download->GetLastReason());
+
+ // Back to the original request handler. Resumption should now succeed, and
+ // use the partial data it had prior to the first interruption.
+ request_handler.StartServing(parameters);
+ download->Resume();
+ WaitForCompletion(download);
+
+ ASSERT_EQ(parameters.size, download->GetReceivedBytes());
+ ASSERT_EQ(parameters.size, download->GetTotalBytes());
+ ASSERT_NO_FATAL_FAILURE(ReadAndVerifyFileContents(
+ parameters.pattern_generator_seed, parameters.size,
+ download->GetTargetFilePath()));
+
+ // Characterization risk: The next portion of the test examines the requests
+ // that were sent out while downloading our resource. These requests
+ // correspond to the requests that were generated by the browser and the
+ // downloads system and may change as implementation details change.
+ TestDownloadRequestHandler::CompletedRequests requests;
+ request_handler.GetCompletedRequestInfo(&requests);
+
+ ASSERT_EQ(5u, requests.size());
+
+ // None of the request should have transferred the entire resource.
+ EXPECT_GT(parameters.size, requests[0].transferred_byte_count);
+ EXPECT_EQ(0, requests[1].transferred_byte_count);
+ EXPECT_EQ(0, requests[2].transferred_byte_count);
+ EXPECT_EQ(0, requests[3].transferred_byte_count);
+ EXPECT_GT(parameters.size, requests[4].transferred_byte_count);
+}
+
// A partial resumption results in an HTTP 200 response. I.e. the server ignored
// the range request and sent the entire resource instead. For If-Range requests
// (as opposed to If-Match), the behavior for a precondition failure is also to

Powered by Google App Engine
This is Rietveld 408576698