| 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
|
|
|