Commit 6035f138 authored by Maks Orlovich's avatar Maks Orlovich Committed by Commit Bot

SimpleURLLoader: Implement download progress callback.

Cq-Include-Trybots: luci.chromium.try:linux_mojo
Change-Id: If1cebe592b61a84eee86c0daf74c9524128fe4c2
Reviewed-on: https://chromium-review.googlesource.com/1142350
Commit-Queue: Maks Orlovich <morlovich@chromium.org>
Reviewed-by: default avatarMatt Menke <mmenke@chromium.org>
Cr-Commit-Position: refs/heads/master@{#583024}
parent 5b61e43a
...@@ -121,6 +121,13 @@ class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader { ...@@ -121,6 +121,13 @@ class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader {
using UploadProgressCallback = using UploadProgressCallback =
base::RepeatingCallback<void(uint64_t position, uint64_t total)>; base::RepeatingCallback<void(uint64_t position, uint64_t total)>;
// Callback used for reporting upload or download progress.
// |current| is the number of bytes transferred thus far for the current
// fetch attempt (so in case of retries, it might appear to go backwards). It
// is safe to delete the SimpleURLLoader during the callback.
using DownloadProgressCallback =
base::RepeatingCallback<void(uint64_t current)>;
// Creates a SimpleURLLoader for |resource_request|. The request can be // Creates a SimpleURLLoader for |resource_request|. The request can be
// started by calling any one of the Download methods once. The loader may not // started by calling any one of the Download methods once. The loader may not
// be reused. // be reused.
...@@ -217,6 +224,16 @@ class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader { ...@@ -217,6 +224,16 @@ class COMPONENT_EXPORT(NETWORK_CPP) SimpleURLLoader {
virtual void SetOnUploadProgressCallback( virtual void SetOnUploadProgressCallback(
UploadProgressCallback on_upload_progress_callback) = 0; UploadProgressCallback on_upload_progress_callback) = 0;
// Sets callback to be invoked to notify of body download progress.
// Note that this may be non-monotonic in case of retries.
// DownloadHeadersOnly() will disregard this setting, and never invoke the
// callback; otherwise it's guaranteed to fire at least once, with the final
// size.
//
// Callback may delete the SimpleURLLoader.
virtual void SetOnDownloadProgressCallback(
DownloadProgressCallback on_download_progress_callback) = 0;
// Sets whether partially received results are allowed. Defaults to false. // Sets whether partially received results are allowed. Defaults to false.
// When true, if an error is received after reading the body starts or the max // When true, if an error is received after reading the body starts or the max
// allowed body size exceeded, the partial response body that was received // allowed body size exceeded, the partial response body that was received
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "base/test/bind_test_util.h"
#include "base/test/scoped_task_environment.h" #include "base/test/scoped_task_environment.h"
#include "mojo/public/c/system/types.h" #include "mojo/public/c/system/types.h"
#include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/bindings/binding.h"
...@@ -2344,6 +2345,38 @@ TEST_P(SimpleURLLoaderTest, MoreDataThanExpected) { ...@@ -2344,6 +2345,38 @@ TEST_P(SimpleURLLoaderTest, MoreDataThanExpected) {
EXPECT_FALSE(test_helper->response_body()); EXPECT_FALSE(test_helper->response_body());
} }
TEST_P(SimpleURLLoaderTest, DownloadProgressCallbackIncremental) {
// Make sure that intermediate states of download are reported to the
// progress callback.
MockURLLoaderFactory loader_factory(&scoped_task_environment_);
loader_factory.AddEvents(
{TestLoaderEvent::kReceivedResponse, TestLoaderEvent::kBodyBufferReceived,
TestLoaderEvent::kBodyDataRead, TestLoaderEvent::kBodyDataRead});
std::unique_ptr<SimpleLoaderTestHelper> test_helper =
CreateHelperForURL(GURL("foo://bar/"));
std::vector<uint64_t> progress;
test_helper->simple_url_loader()->SetOnDownloadProgressCallback(
base::BindLambdaForTesting(
[&](uint64_t current) { progress.push_back(current); }));
loader_factory.RunTest(test_helper.get(), false);
if (GetParam() == SimpleLoaderTestHelper::DownloadType::HEADERS_ONLY) {
EXPECT_EQ(0u, progress.size());
} else {
// Since the request doesn't complete this is guaranteed to receive
// all the in-progress events, as there is no risk of completion happening
// beforehand and cancelling them.
ASSERT_EQ(2u, progress.size());
EXPECT_EQ(1u, progress[0]);
EXPECT_EQ(2u, progress[1]);
}
// Clean the file up.
test_helper->DestroySimpleURLLoader();
scoped_task_environment_.RunUntilIdle();
}
TEST_P(SimpleURLLoaderTest, RetryOn5xx) { TEST_P(SimpleURLLoaderTest, RetryOn5xx) {
const GURL kInitialURL("foo://bar/initial"); const GURL kInitialURL("foo://bar/initial");
struct TestCase { struct TestCase {
...@@ -2961,6 +2994,24 @@ TEST_P(SimpleURLLoaderTest, OnUploadProgressCallback) { ...@@ -2961,6 +2994,24 @@ TEST_P(SimpleURLLoaderTest, OnUploadProgressCallback) {
} }
} }
TEST_P(SimpleURLLoaderTest, OnDownloadProgressCallback) {
const uint32_t kResponseSize = 512 * 1024;
std::unique_ptr<SimpleLoaderTestHelper> test_helper =
CreateHelperForURL(test_server_.GetURL(
base::StringPrintf("/response-size?%u", kResponseSize)));
uint64_t progress = 0;
test_helper->simple_url_loader()->SetOnDownloadProgressCallback(
base::BindLambdaForTesting([&](uint64_t current) {
EXPECT_GE(current, progress);
progress = current;
}));
test_helper->StartSimpleLoaderAndWait(url_loader_factory_.get());
if (GetParam() == SimpleLoaderTestHelper::DownloadType::HEADERS_ONLY)
EXPECT_EQ(0u, progress);
else
EXPECT_EQ(kResponseSize, progress);
}
// Ensure that deleting the SimpleURLLoader in the upload progress // Ensure that deleting the SimpleURLLoader in the upload progress
// callback is safe // callback is safe
TEST_P(SimpleURLLoaderTest, DeleteInOnUploadProgressCallback) { TEST_P(SimpleURLLoaderTest, DeleteInOnUploadProgressCallback) {
...@@ -2987,5 +3038,54 @@ TEST_P(SimpleURLLoaderTest, DeleteInOnUploadProgressCallback) { ...@@ -2987,5 +3038,54 @@ TEST_P(SimpleURLLoaderTest, DeleteInOnUploadProgressCallback) {
run_loop.Run(); run_loop.Run();
} }
// Ensure that deleting the SimpleURLLoader in the upload progress
// callback is safe --- first invocation.
TEST_P(SimpleURLLoaderTest, DeleteInDownloadProgressCallback) {
if (GetParam() == SimpleLoaderTestHelper::DownloadType::HEADERS_ONLY)
return; // No progress callback to delete stuff in.
const uint32_t kResponseSize = 512 * 1024;
std::unique_ptr<SimpleLoaderTestHelper> test_helper =
CreateHelperForURL(test_server_.GetURL(
base::StringPrintf("/response-size?%u", kResponseSize)));
base::RunLoop run_loop;
auto callback = base::BindLambdaForTesting([&](uint64_t current) {
test_helper->DestroySimpleURLLoader(); // cleanup files.
scoped_task_environment_.RunUntilIdle();
test_helper.reset();
run_loop.Quit();
});
test_helper->simple_url_loader()->SetOnDownloadProgressCallback(callback);
test_helper->StartSimpleLoader(url_loader_factory_.get());
run_loop.Run();
}
// Ensure that deleting the SimpleURLLoader in the upload progress
// callback is safe --- completion invocation.
TEST_P(SimpleURLLoaderTest, DeleteInDownloadProgressCallback2) {
if (GetParam() == SimpleLoaderTestHelper::DownloadType::HEADERS_ONLY)
return; // No progress callback to delete stuff in.
const uint32_t kResponseSize = 512 * 1024;
std::unique_ptr<SimpleLoaderTestHelper> test_helper =
CreateHelperForURL(test_server_.GetURL(
base::StringPrintf("/response-size?%u", kResponseSize)));
base::RunLoop run_loop;
auto callback = base::BindLambdaForTesting([&](uint64_t current) {
if (current == kResponseSize) {
test_helper->DestroySimpleURLLoader(); // cleanup files.
scoped_task_environment_.RunUntilIdle();
test_helper.reset();
run_loop.Quit();
}
});
test_helper->simple_url_loader()->SetOnDownloadProgressCallback(callback);
test_helper->StartSimpleLoader(url_loader_factory_.get());
run_loop.Run();
}
} // namespace } // namespace
} // namespace network } // namespace network
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment