Commit 8be31472 authored by Misha Efimov's avatar Misha Efimov Committed by Commit Bot

[Cronet] Implement native UploadDataStream API.

Bug: 786559
Cq-Include-Trybots: master.tryserver.chromium.android:android_cronet_tester;master.tryserver.chromium.mac:ios-simulator-cronet
Change-Id: Ied0c3de493c817e0836fcf42e09736509acbd2d1
Reviewed-on: https://chromium-review.googlesource.com/1086127
Commit-Queue: Misha Efimov <mef@chromium.org>
Reviewed-by: default avatarPaul Jensen <pauljensen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#584464}
parent c0893d34
......@@ -55,6 +55,8 @@ source_set("cronet_native_impl") {
"io_buffer_with_cronet_buffer.h",
"runnables.cc",
"runnables.h",
"upload_data_sink.cc",
"upload_data_sink.h",
"url_request.cc",
"url_request.h",
......
......@@ -4,9 +4,9 @@
#include "components/cronet/native/generated/cronet.idl_impl_interface.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/macros.h"
#include "base/no_destructor.h"
#include "base/numerics/safe_conversions.h"
namespace {
......@@ -23,9 +23,6 @@ class Cronet_BufferCallbackFree : public Cronet_BufferCallback {
DISALLOW_COPY_AND_ASSIGN(Cronet_BufferCallbackFree);
};
base::LazyInstance<Cronet_BufferCallbackFree>::Leaky
g_cronet_buffer_callback_free = LAZY_INSTANCE_INITIALIZER;
// Concrete implementation of abstract Cronet_Buffer interface.
class Cronet_BufferImpl : public Cronet_Buffer {
public:
......@@ -69,7 +66,8 @@ void Cronet_BufferImpl::InitWithAlloc(uint64_t size) {
if (!data_)
return;
size_ = size;
callback_ = g_cronet_buffer_callback_free.Pointer();
static base::NoDestructor<Cronet_BufferCallbackFree> static_callback;
callback_ = static_callback.get();
}
uint64_t Cronet_BufferImpl::GetSize() {
......
......@@ -855,28 +855,29 @@ interface UploadDataSink {
/**
* Called by UploadDataProvider when a read succeeds.
*
* @param bytes_read number of bytes read into buffer passed to read().
* @param final_chunk For chunked uploads, |true| if this is the final
* read. It must be |false| for non-chunked uploads.
*/
OnReadSucceeded(bool final_chunk);
OnReadSucceeded(uint64 bytes_read, bool final_chunk);
/**
* Called by UploadDataProvider when a read fails.
* @param error to pass on to UrlRequestCallback.onFailed().
* @param error_message to pass on to UrlRequestCallback.onFailed().
*/
OnReadError(Error error);
OnReadError(string error_message);
/**
* Called by UploadDataProvider when a rewind succeeds.
*/
OnRewindSucceded();
OnRewindSucceeded();
/**
* Called by UploadDataProvider when a rewind fails, or if rewinding
* uploads is not supported.
* @param error to pass on to UrlRequestCallback.onFailed().
* @param error_message to pass on to UrlRequestCallback.onFailed().
*/
OnRewindError(Error error);
OnRewindError(string error_message);
};
/**
......@@ -898,9 +899,7 @@ interface UploadDataProvider {
GetLength() => (int64 length);
/**
* Reads upload data into |buffer|. Upon completion, the buffer's
* position is updated to the end of the bytes that were read. The buffer's
* limit is not changed. Each call of this method must be followed be a
* Reads upload data into |buffer|. Each call of this method must be followed be a
* single call, either synchronous or asynchronous, to
* UploadDataSink.onReadSucceeded() on success
* or UploadDataSink.onReadError() on failure. Neither read nor rewind
......@@ -910,8 +909,7 @@ interface UploadDataProvider {
*
* @param upload_data_sink The object to notify when the read has completed,
* successfully or otherwise.
* @param buffer The buffer to copy the read bytes into. Do not change
* byteBuffer's limit.
* @param buffer The buffer to copy the read bytes into.
*/
Read(UploadDataSink upload_data_sink, Buffer buffer);
......
......@@ -468,34 +468,36 @@ Cronet_UploadDataSink_GetClientContext(Cronet_UploadDataSinkPtr self);
// The app calls them to manipulate Cronet_UploadDataSink.
CRONET_EXPORT
void Cronet_UploadDataSink_OnReadSucceeded(Cronet_UploadDataSinkPtr self,
uint64_t bytes_read,
bool final_chunk);
CRONET_EXPORT
void Cronet_UploadDataSink_OnReadError(Cronet_UploadDataSinkPtr self,
Cronet_ErrorPtr error);
Cronet_String error_message);
CRONET_EXPORT
void Cronet_UploadDataSink_OnRewindSucceded(Cronet_UploadDataSinkPtr self);
void Cronet_UploadDataSink_OnRewindSucceeded(Cronet_UploadDataSinkPtr self);
CRONET_EXPORT
void Cronet_UploadDataSink_OnRewindError(Cronet_UploadDataSinkPtr self,
Cronet_ErrorPtr error);
Cronet_String error_message);
// Concrete interface Cronet_UploadDataSink is implemented by Cronet.
// The app can implement these for testing / mocking.
typedef void (*Cronet_UploadDataSink_OnReadSucceededFunc)(
Cronet_UploadDataSinkPtr self,
uint64_t bytes_read,
bool final_chunk);
typedef void (*Cronet_UploadDataSink_OnReadErrorFunc)(
Cronet_UploadDataSinkPtr self,
Cronet_ErrorPtr error);
typedef void (*Cronet_UploadDataSink_OnRewindSuccededFunc)(
Cronet_String error_message);
typedef void (*Cronet_UploadDataSink_OnRewindSucceededFunc)(
Cronet_UploadDataSinkPtr self);
typedef void (*Cronet_UploadDataSink_OnRewindErrorFunc)(
Cronet_UploadDataSinkPtr self,
Cronet_ErrorPtr error);
Cronet_String error_message);
// Concrete interface Cronet_UploadDataSink is implemented by Cronet.
// The app can use this for testing / mocking.
CRONET_EXPORT Cronet_UploadDataSinkPtr Cronet_UploadDataSink_CreateWith(
Cronet_UploadDataSink_OnReadSucceededFunc OnReadSucceededFunc,
Cronet_UploadDataSink_OnReadErrorFunc OnReadErrorFunc,
Cronet_UploadDataSink_OnRewindSuccededFunc OnRewindSuccededFunc,
Cronet_UploadDataSink_OnRewindSucceededFunc OnRewindSucceededFunc,
Cronet_UploadDataSink_OnRewindErrorFunc OnRewindErrorFunc);
///////////////////////
......
......@@ -577,26 +577,27 @@ Cronet_ClientContext Cronet_UploadDataSink_GetClientContext(
}
void Cronet_UploadDataSink_OnReadSucceeded(Cronet_UploadDataSinkPtr self,
uint64_t bytes_read,
bool final_chunk) {
DCHECK(self);
self->OnReadSucceeded(final_chunk);
self->OnReadSucceeded(bytes_read, final_chunk);
}
void Cronet_UploadDataSink_OnReadError(Cronet_UploadDataSinkPtr self,
Cronet_ErrorPtr error) {
Cronet_String error_message) {
DCHECK(self);
self->OnReadError(error);
self->OnReadError(error_message);
}
void Cronet_UploadDataSink_OnRewindSucceded(Cronet_UploadDataSinkPtr self) {
void Cronet_UploadDataSink_OnRewindSucceeded(Cronet_UploadDataSinkPtr self) {
DCHECK(self);
self->OnRewindSucceded();
self->OnRewindSucceeded();
}
void Cronet_UploadDataSink_OnRewindError(Cronet_UploadDataSinkPtr self,
Cronet_ErrorPtr error) {
Cronet_String error_message) {
DCHECK(self);
self->OnRewindError(error);
self->OnRewindError(error_message);
}
// Implementation of Cronet_UploadDataSink that forwards calls to C functions
......@@ -606,34 +607,34 @@ class Cronet_UploadDataSinkStub : public Cronet_UploadDataSink {
Cronet_UploadDataSinkStub(
Cronet_UploadDataSink_OnReadSucceededFunc OnReadSucceededFunc,
Cronet_UploadDataSink_OnReadErrorFunc OnReadErrorFunc,
Cronet_UploadDataSink_OnRewindSuccededFunc OnRewindSuccededFunc,
Cronet_UploadDataSink_OnRewindSucceededFunc OnRewindSucceededFunc,
Cronet_UploadDataSink_OnRewindErrorFunc OnRewindErrorFunc)
: OnReadSucceededFunc_(OnReadSucceededFunc),
OnReadErrorFunc_(OnReadErrorFunc),
OnRewindSuccededFunc_(OnRewindSuccededFunc),
OnRewindSucceededFunc_(OnRewindSucceededFunc),
OnRewindErrorFunc_(OnRewindErrorFunc) {}
~Cronet_UploadDataSinkStub() override {}
protected:
void OnReadSucceeded(bool final_chunk) override {
OnReadSucceededFunc_(this, final_chunk);
void OnReadSucceeded(uint64_t bytes_read, bool final_chunk) override {
OnReadSucceededFunc_(this, bytes_read, final_chunk);
}
void OnReadError(Cronet_ErrorPtr error) override {
OnReadErrorFunc_(this, error);
void OnReadError(Cronet_String error_message) override {
OnReadErrorFunc_(this, error_message);
}
void OnRewindSucceded() override { OnRewindSuccededFunc_(this); }
void OnRewindSucceeded() override { OnRewindSucceededFunc_(this); }
void OnRewindError(Cronet_ErrorPtr error) override {
OnRewindErrorFunc_(this, error);
void OnRewindError(Cronet_String error_message) override {
OnRewindErrorFunc_(this, error_message);
}
private:
const Cronet_UploadDataSink_OnReadSucceededFunc OnReadSucceededFunc_;
const Cronet_UploadDataSink_OnReadErrorFunc OnReadErrorFunc_;
const Cronet_UploadDataSink_OnRewindSuccededFunc OnRewindSuccededFunc_;
const Cronet_UploadDataSink_OnRewindSucceededFunc OnRewindSucceededFunc_;
const Cronet_UploadDataSink_OnRewindErrorFunc OnRewindErrorFunc_;
DISALLOW_COPY_AND_ASSIGN(Cronet_UploadDataSinkStub);
......@@ -642,10 +643,11 @@ class Cronet_UploadDataSinkStub : public Cronet_UploadDataSink {
Cronet_UploadDataSinkPtr Cronet_UploadDataSink_CreateWith(
Cronet_UploadDataSink_OnReadSucceededFunc OnReadSucceededFunc,
Cronet_UploadDataSink_OnReadErrorFunc OnReadErrorFunc,
Cronet_UploadDataSink_OnRewindSuccededFunc OnRewindSuccededFunc,
Cronet_UploadDataSink_OnRewindSucceededFunc OnRewindSucceededFunc,
Cronet_UploadDataSink_OnRewindErrorFunc OnRewindErrorFunc) {
return new Cronet_UploadDataSinkStub(OnReadSucceededFunc, OnReadErrorFunc,
OnRewindSuccededFunc, OnRewindErrorFunc);
OnRewindSucceededFunc,
OnRewindErrorFunc);
}
// C functions of Cronet_UploadDataProvider that forward calls to C++
......
......@@ -166,10 +166,10 @@ struct Cronet_UploadDataSink {
}
Cronet_ClientContext client_context() const { return client_context_; }
virtual void OnReadSucceeded(bool final_chunk) = 0;
virtual void OnReadError(Cronet_ErrorPtr error) = 0;
virtual void OnRewindSucceded() = 0;
virtual void OnRewindError(Cronet_ErrorPtr error) = 0;
virtual void OnReadSucceeded(uint64_t bytes_read, bool final_chunk) = 0;
virtual void OnReadError(Cronet_String error_message) = 0;
virtual void OnRewindSucceeded() = 0;
virtual void OnRewindError(Cronet_String error_message) = 0;
private:
Cronet_ClientContext client_context_ = nullptr;
......
......@@ -66,7 +66,7 @@ Cronet_RawDataPtr TestCronet_Buffer_GetData(Cronet_BufferPtr self) {
CHECK(test);
test->GetData_called_ = true;
return static_cast<Cronet_RawDataPtr>(nullptr);
return static_cast<Cronet_RawDataPtr>(0);
}
} // namespace
......@@ -276,7 +276,7 @@ Cronet_String TestCronet_Engine_GetVersionString(Cronet_EnginePtr self) {
CHECK(test);
test->GetVersionString_called_ = true;
return static_cast<Cronet_String>(nullptr);
return static_cast<Cronet_String>(0);
}
Cronet_String TestCronet_Engine_GetDefaultUserAgent(Cronet_EnginePtr self) {
CHECK(self);
......@@ -285,7 +285,7 @@ Cronet_String TestCronet_Engine_GetDefaultUserAgent(Cronet_EnginePtr self) {
CHECK(test);
test->GetDefaultUserAgent_called_ = true;
return static_cast<Cronet_String>(nullptr);
return static_cast<Cronet_String>(0);
}
} // namespace
......@@ -485,7 +485,7 @@ class Cronet_UploadDataSinkTest : public ::testing::Test {
public:
bool OnReadSucceeded_called_ = false;
bool OnReadError_called_ = false;
bool OnRewindSucceded_called_ = false;
bool OnRewindSucceeded_called_ = false;
bool OnRewindError_called_ = false;
private:
......@@ -495,6 +495,7 @@ class Cronet_UploadDataSinkTest : public ::testing::Test {
namespace {
// Implementation of Cronet_UploadDataSink methods for testing.
void TestCronet_UploadDataSink_OnReadSucceeded(Cronet_UploadDataSinkPtr self,
uint64_t bytes_read,
bool final_chunk) {
CHECK(self);
Cronet_ClientContext client_context =
......@@ -504,7 +505,7 @@ void TestCronet_UploadDataSink_OnReadSucceeded(Cronet_UploadDataSinkPtr self,
test->OnReadSucceeded_called_ = true;
}
void TestCronet_UploadDataSink_OnReadError(Cronet_UploadDataSinkPtr self,
Cronet_ErrorPtr error) {
Cronet_String error_message) {
CHECK(self);
Cronet_ClientContext client_context =
Cronet_UploadDataSink_GetClientContext(self);
......@@ -512,16 +513,17 @@ void TestCronet_UploadDataSink_OnReadError(Cronet_UploadDataSinkPtr self,
CHECK(test);
test->OnReadError_called_ = true;
}
void TestCronet_UploadDataSink_OnRewindSucceded(Cronet_UploadDataSinkPtr self) {
void TestCronet_UploadDataSink_OnRewindSucceeded(
Cronet_UploadDataSinkPtr self) {
CHECK(self);
Cronet_ClientContext client_context =
Cronet_UploadDataSink_GetClientContext(self);
auto* test = static_cast<Cronet_UploadDataSinkTest*>(client_context);
CHECK(test);
test->OnRewindSucceded_called_ = true;
test->OnRewindSucceeded_called_ = true;
}
void TestCronet_UploadDataSink_OnRewindError(Cronet_UploadDataSinkPtr self,
Cronet_ErrorPtr error) {
Cronet_String error_message) {
CHECK(self);
Cronet_ClientContext client_context =
Cronet_UploadDataSink_GetClientContext(self);
......@@ -536,14 +538,14 @@ TEST_F(Cronet_UploadDataSinkTest, TestCreate) {
Cronet_UploadDataSinkPtr test = Cronet_UploadDataSink_CreateWith(
TestCronet_UploadDataSink_OnReadSucceeded,
TestCronet_UploadDataSink_OnReadError,
TestCronet_UploadDataSink_OnRewindSucceded,
TestCronet_UploadDataSink_OnRewindSucceeded,
TestCronet_UploadDataSink_OnRewindError);
CHECK(test);
Cronet_UploadDataSink_SetClientContext(test, this);
CHECK(!OnReadSucceeded_called_);
CHECK(!OnReadError_called_);
Cronet_UploadDataSink_OnRewindSucceded(test);
CHECK(OnRewindSucceded_called_);
Cronet_UploadDataSink_OnRewindSucceeded(test);
CHECK(OnRewindSucceeded_called_);
CHECK(!OnRewindError_called_);
Cronet_UploadDataSink_Destroy(test);
......
......@@ -4,8 +4,25 @@
#include "components/cronet/native/io_buffer_with_cronet_buffer.h"
#include "base/no_destructor.h"
#include "components/cronet/native/generated/cronet.idl_impl_interface.h"
namespace {
// Implementation of Cronet_BufferCallback that doesn't free the data as it
// is not owned by the buffer.
class Cronet_BufferCallbackUnowned : public Cronet_BufferCallback {
public:
Cronet_BufferCallbackUnowned() = default;
~Cronet_BufferCallbackUnowned() override = default;
void OnDestroy(Cronet_BufferPtr buffer) override {}
private:
DISALLOW_COPY_AND_ASSIGN(Cronet_BufferCallbackUnowned);
};
} // namespace
namespace cronet {
IOBufferWithCronet_Buffer::IOBufferWithCronet_Buffer(
......@@ -25,4 +42,16 @@ Cronet_BufferPtr IOBufferWithCronet_Buffer::Release() {
return cronet_buffer_.release();
}
Cronet_BufferWithIOBuffer::Cronet_BufferWithIOBuffer(net::IOBuffer* io_buffer,
size_t io_buffer_len)
: io_buffer_(io_buffer),
io_buffer_len_(io_buffer_len),
cronet_buffer_(Cronet_Buffer_Create()) {
static base::NoDestructor<Cronet_BufferCallbackUnowned> static_callback;
cronet_buffer_->InitWithDataAndCallback(io_buffer->data(), io_buffer_len,
static_callback.get());
}
Cronet_BufferWithIOBuffer::~Cronet_BufferWithIOBuffer() = default;
} // namespace cronet
......@@ -32,6 +32,29 @@ class IOBufferWithCronet_Buffer : public net::WrappedIOBuffer {
DISALLOW_COPY_AND_ASSIGN(IOBufferWithCronet_Buffer);
};
// Represents a Cronet_Buffer backed by a net::IOBuffer. Keeps both the
// net::IOBuffer and the Cronet_Buffer object alive until destroyed.
class Cronet_BufferWithIOBuffer {
public:
Cronet_BufferWithIOBuffer(net::IOBuffer* io_buffer, size_t io_buffer_len);
~Cronet_BufferWithIOBuffer();
const net::IOBuffer* io_buffer() const { return io_buffer_.get(); }
size_t io_buffer_len() const { return io_buffer_len_; }
// Returns pointer to Cronet buffer owned by |this|.
Cronet_BufferPtr cronet_buffer() { return cronet_buffer_.get(); }
private:
scoped_refptr<net::IOBuffer> io_buffer_;
size_t io_buffer_len_;
// Cronet buffer owned by |this|.
std::unique_ptr<Cronet_Buffer> cronet_buffer_;
DISALLOW_COPY_AND_ASSIGN(Cronet_BufferWithIOBuffer);
};
} // namespace cronet
#endif // COMPONENTS_CRONET_NATIVE_IO_BUFFER_WITH_CRONET_BUFFER_H_
......@@ -44,6 +44,8 @@ source_set("cronet_native_tests") {
"buffer_test.cc",
"engine_test.cc",
"executors_test.cc",
"test_upload_data_provider.cc",
"test_upload_data_provider.h",
"test_url_request_callback.cc",
"test_url_request_callback.h",
"url_request_test.cc",
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/cronet/native/test/test_upload_data_provider.h"
#include "base/bind.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
// Helper class that runs base::OnceClosure.
class TestRunnable {
public:
// Creates Cronet runnable that runs |task| once and destroys itself.
static Cronet_RunnablePtr CreateRunnable(base::OnceClosure task);
private:
explicit TestRunnable(base::OnceClosure task);
~TestRunnable();
// Runs |self| and destroys it.
static void Run(Cronet_RunnablePtr self);
// Closure to run.
base::OnceClosure task_;
DISALLOW_COPY_AND_ASSIGN(TestRunnable);
};
TestRunnable::TestRunnable(base::OnceClosure task) : task_(std::move(task)) {}
TestRunnable::~TestRunnable() = default;
// static
Cronet_RunnablePtr TestRunnable::CreateRunnable(base::OnceClosure task) {
Cronet_RunnablePtr runnable = Cronet_Runnable_CreateWith(TestRunnable::Run);
Cronet_Runnable_SetClientContext(runnable, new TestRunnable(std::move(task)));
return runnable;
}
// static
void TestRunnable::Run(Cronet_RunnablePtr self) {
CHECK(self);
Cronet_ClientContext context = Cronet_Runnable_GetClientContext(self);
TestRunnable* runnable = static_cast<TestRunnable*>(context);
CHECK(runnable);
std::move(runnable->task_).Run();
delete runnable;
Cronet_Runnable_Destroy(self);
}
} // namespace
namespace cronet {
// Various test utility functions for testing Cronet.
namespace test {
TestUploadDataProvider::TestUploadDataProvider(
SuccessCallbackMode success_callback_mode,
Cronet_ExecutorPtr executor)
: success_callback_mode_(success_callback_mode), executor_(executor) {}
TestUploadDataProvider::~TestUploadDataProvider() = default;
Cronet_UploadDataProviderPtr
TestUploadDataProvider::CreateUploadDataProvider() {
Cronet_UploadDataProviderPtr upload_data_provider =
Cronet_UploadDataProvider_CreateWith(
TestUploadDataProvider::GetLength, TestUploadDataProvider::Read,
TestUploadDataProvider::Rewind, TestUploadDataProvider::Close);
Cronet_UploadDataProvider_SetClientContext(upload_data_provider, this);
return upload_data_provider;
}
void TestUploadDataProvider::AddRead(std::string read) {
EXPECT_TRUE(!started_) << "Adding bytes after read";
reads_.push_back(read);
}
void TestUploadDataProvider::SetReadFailure(int read_fail_index,
FailMode read_fail_mode) {
read_fail_index_ = read_fail_index;
read_fail_mode_ = read_fail_mode;
}
void TestUploadDataProvider::SetRewindFailure(FailMode rewind_fail_mode) {
rewind_fail_mode_ = rewind_fail_mode;
}
int64_t TestUploadDataProvider::GetLength() const {
EXPECT_TRUE(!closed_.IsSet()) << "Data Provider is closed";
if (bad_length_ != -1)
return bad_length_;
return GetUploadedLength();
}
int64_t TestUploadDataProvider::GetUploadedLength() const {
if (chunked_)
return -1ll;
int64_t length = 0ll;
for (const auto& read : reads_)
length += read.size();
return length;
}
void TestUploadDataProvider::Read(Cronet_UploadDataSinkPtr upload_data_sink,
Cronet_BufferPtr buffer) {
int current_read_call = num_read_calls_;
++num_read_calls_;
EXPECT_TRUE(!closed_.IsSet()) << "Data Provider is closed";
AssertIdle();
if (MaybeFailRead(current_read_call, upload_data_sink)) {
failed_ = true;
return;
}
read_pending_ = true;
started_ = true;
bool final_chunk = (chunked_ && next_read_ == reads_.size() - 1);
EXPECT_TRUE(next_read_ < reads_.size()) << "Too many reads: " << next_read_;
const auto& read = reads_[next_read_];
EXPECT_TRUE(read.size() < Cronet_Buffer_GetSize(buffer))
<< "Read buffer smaller than expected.";
memcpy(Cronet_Buffer_GetData(buffer), read.data(), read.size());
++next_read_;
auto complete_closure = base::BindOnce(
[](TestUploadDataProvider* upload_data_provider,
Cronet_UploadDataSink* upload_data_sink, uint64_t bytes_read,
bool final_chunk) {
upload_data_provider->read_pending_ = false;
Cronet_UploadDataSink_OnReadSucceeded(upload_data_sink, bytes_read,
final_chunk);
},
this, upload_data_sink, read.size(), final_chunk);
if (success_callback_mode_ == SYNC) {
std::move(complete_closure).Run();
} else {
PostTaskToExecutor(std::move(complete_closure));
}
}
void TestUploadDataProvider::Rewind(Cronet_UploadDataSinkPtr upload_data_sink) {
++num_rewind_calls_;
EXPECT_TRUE(!closed_.IsSet()) << "Data Provider is closed";
AssertIdle();
if (MaybeFailRewind(upload_data_sink)) {
failed_ = true;
return;
}
// Should never try and rewind when rewinding does nothing.
EXPECT_TRUE(next_read_ != 0) << "Unexpected rewind when already at beginning";
rewind_pending_ = true;
next_read_ = 0;
auto complete_closure = base::BindOnce(
[](TestUploadDataProvider* upload_data_provider,
Cronet_UploadDataSink* upload_data_sink) {
upload_data_provider->rewind_pending_ = false;
Cronet_UploadDataSink_OnRewindSucceeded(upload_data_sink);
},
this, upload_data_sink);
if (success_callback_mode_ == SYNC) {
std::move(complete_closure).Run();
} else {
PostTaskToExecutor(std::move(complete_closure));
}
}
void TestUploadDataProvider::PostTaskToExecutor(base::OnceClosure task) {
EXPECT_TRUE(executor_);
// |runnable| is passed to executor, which destroys it after execution.
Cronet_Executor_Execute(executor_,
TestRunnable::CreateRunnable(std::move(task)));
}
void TestUploadDataProvider::AssertIdle() const {
EXPECT_TRUE(!read_pending_) << "Unexpected operation during read";
EXPECT_TRUE(!rewind_pending_) << "Unexpected operation during rewind";
EXPECT_TRUE(!failed_) << "Unexpected operation after failure";
}
bool TestUploadDataProvider::MaybeFailRead(
int read_index,
Cronet_UploadDataSinkPtr upload_data_sink) {
if (read_index != read_fail_index_)
return false;
if (read_fail_mode_ == NONE)
return false;
if (read_fail_mode_ == CALLBACK_SYNC) {
Cronet_UploadDataSink_OnReadError(upload_data_sink, "Sync read failure");
return true;
}
EXPECT_EQ(read_fail_mode_, CALLBACK_ASYNC);
PostTaskToExecutor(base::BindOnce(
[](Cronet_UploadDataSink* upload_data_sink) {
Cronet_UploadDataSink_OnReadError(upload_data_sink,
"Async read failure");
},
upload_data_sink));
return true;
}
bool TestUploadDataProvider::MaybeFailRewind(
Cronet_UploadDataSinkPtr upload_data_sink) {
if (rewind_fail_mode_ == NONE)
return false;
if (rewind_fail_mode_ == CALLBACK_SYNC) {
Cronet_UploadDataSink_OnRewindError(upload_data_sink,
"Sync rewind failure");
return true;
}
EXPECT_EQ(rewind_fail_mode_, CALLBACK_ASYNC);
PostTaskToExecutor(base::BindOnce(
[](Cronet_UploadDataSink* upload_data_sink) {
Cronet_UploadDataSink_OnRewindError(upload_data_sink,
"Async rewind failure");
},
upload_data_sink));
return true;
}
void TestUploadDataProvider::Close() {
EXPECT_TRUE(!closed_.IsSet()) << "Closed twice";
closed_.Set();
awaiting_close_.Signal();
}
void TestUploadDataProvider::AssertClosed() {
awaiting_close_.TimedWait(base::TimeDelta::FromMilliseconds(5000));
EXPECT_TRUE(closed_.IsSet()) << "Was not closed";
}
/* static */
TestUploadDataProvider* TestUploadDataProvider::GetThis(
Cronet_UploadDataProviderPtr self) {
return static_cast<TestUploadDataProvider*>(
Cronet_UploadDataProvider_GetClientContext(self));
}
/* static */
int64_t TestUploadDataProvider::GetLength(Cronet_UploadDataProviderPtr self) {
return GetThis(self)->GetLength();
}
/* static */
void TestUploadDataProvider::Read(Cronet_UploadDataProviderPtr self,
Cronet_UploadDataSinkPtr upload_data_sink,
Cronet_BufferPtr buffer) {
return GetThis(self)->Read(upload_data_sink, buffer);
}
/* static */
void TestUploadDataProvider::Rewind(Cronet_UploadDataProviderPtr self,
Cronet_UploadDataSinkPtr upload_data_sink) {
return GetThis(self)->Rewind(upload_data_sink);
}
/* static */
void TestUploadDataProvider::Close(Cronet_UploadDataProviderPtr self) {
return GetThis(self)->Close();
}
} // namespace test
} // namespace cronet
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_CRONET_NATIVE_TEST_TEST_UPLOAD_DATA_PROVIDER_H_
#define COMPONENTS_CRONET_NATIVE_TEST_TEST_UPLOAD_DATA_PROVIDER_H_
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "cronet_c.h"
#include "base/bind.h"
#include "base/macros.h"
#include "base/synchronization/atomic_flag.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "base/threading/thread.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cronet {
// Various test utility functions for testing Cronet.
namespace test {
/**
* An UploadDataProvider implementation used in tests.
*/
class TestUploadDataProvider {
public:
// Indicates whether all success callbacks are synchronous or asynchronous.
// Doesn't apply to errors.
enum SuccessCallbackMode { SYNC, ASYNC };
// Indicates whether failures should invoke callbacks synchronously, or
// invoke callback asynchronously.
enum FailMode { NONE, CALLBACK_SYNC, CALLBACK_ASYNC };
TestUploadDataProvider(SuccessCallbackMode success_callback_mode,
Cronet_ExecutorPtr executor);
~TestUploadDataProvider();
Cronet_UploadDataProviderPtr CreateUploadDataProvider();
// Adds the result to be returned by a successful read request. The
// returned bytes must all fit within the read buffer provided by Cronet.
// After a rewind, if there is one, all reads will be repeated.
void AddRead(std::string read);
void SetReadFailure(int read_fail_index, FailMode read_fail_mode);
void SetRewindFailure(FailMode rewind_fail_mode);
void set_bad_length(int64_t bad_length) { bad_length_ = bad_length; }
void set_chunked(bool chunked) { chunked_ = chunked; }
int num_read_calls() const { return num_read_calls_; }
int num_rewind_calls() const { return num_rewind_calls_; }
/**
* Returns the cumulative length of all data added by calls to addRead.
*/
int64_t GetLength() const;
int64_t GetUploadedLength() const;
void Read(Cronet_UploadDataSinkPtr upload_data_sink, Cronet_BufferPtr buffer);
void Rewind(Cronet_UploadDataSinkPtr upload_data_sink);
void AssertClosed();
private:
void PostTaskToExecutor(base::OnceClosure task);
void AssertIdle() const;
bool MaybeFailRead(int read_index, Cronet_UploadDataSinkPtr upload_data_sink);
bool MaybeFailRewind(Cronet_UploadDataSinkPtr upload_data_sink);
void Close();
// Implementation of Cronet_UploadDataProvider methods.
static TestUploadDataProvider* GetThis(Cronet_UploadDataProviderPtr self);
static int64_t GetLength(Cronet_UploadDataProviderPtr self);
static void Read(Cronet_UploadDataProviderPtr self,
Cronet_UploadDataSinkPtr upload_data_sink,
Cronet_BufferPtr buffer);
static void Rewind(Cronet_UploadDataProviderPtr self,
Cronet_UploadDataSinkPtr upload_data_sink);
static void Close(Cronet_UploadDataProviderPtr self);
std::vector<std::string> reads_;
const SuccessCallbackMode success_callback_mode_ = SYNC;
const Cronet_ExecutorPtr executor_;
bool chunked_ = false;
// Index of read to fail on.
int read_fail_index_ = -1;
// Indicates how to fail on a read.
FailMode read_fail_mode_ = NONE;
FailMode rewind_fail_mode_ = NONE;
// Report bad length if not set to -1.
int64_t bad_length_ = -1;
int num_read_calls_ = 0;
int num_rewind_calls_ = 0;
size_t next_read_ = 0;
bool started_ = false;
bool read_pending_ = false;
bool rewind_pending_ = false;
// Used to ensure there are no read/rewind requests after a failure.
bool failed_ = false;
base::AtomicFlag closed_;
base::WaitableEvent awaiting_close_;
};
} // namespace test
} // namespace cronet
#endif // COMPONENTS_CRONET_NATIVE_TEST_TEST_UPLOAD_DATA_PROVIDER_H_
......@@ -68,15 +68,21 @@ TestUrlRequestCallback::~TestUrlRequestCallback() {
}
Cronet_ExecutorPtr TestUrlRequestCallback::GetExecutor(bool direct) {
CHECK(!executor_);
if (executor_) {
CHECK(direct == allow_direct_executor_);
return executor_;
}
allow_direct_executor_ = direct;
if (direct)
return Cronet_Executor_CreateWith(TestUrlRequestCallback::ExecuteDirect);
executor_thread_ =
std::make_unique<base::Thread>("TestUrlRequestCallback executor");
executor_thread_->Start();
executor_ = Cronet_Executor_CreateWith(TestUrlRequestCallback::Execute);
Cronet_Executor_SetClientContext(executor_, this);
if (direct) {
executor_ =
Cronet_Executor_CreateWith(TestUrlRequestCallback::ExecuteDirect);
} else {
executor_thread_ =
std::make_unique<base::Thread>("TestUrlRequestCallback executor");
executor_thread_->Start();
executor_ = Cronet_Executor_CreateWith(TestUrlRequestCallback::Execute);
Cronet_Executor_SetClientContext(executor_, this);
}
return executor_;
}
......@@ -186,6 +192,8 @@ void TestUrlRequestCallback::OnFailed(Cronet_UrlRequestPtr request,
if (info)
response_info_ = std::make_unique<UrlResponseInfo>(info);
last_error_ = error;
last_error_code_ = Cronet_Error_error_code_get(error);
last_error_message_ = Cronet_Error_message_get(error);
SignalDone();
MaybeCancelOrPause(request);
}
......
......@@ -72,6 +72,10 @@ class TestUrlRequestCallback {
std::unique_ptr<UrlResponseInfo> response_info_;
// Owned by UrlRequest, only valid until UrlRequest is destroyed.
Cronet_ErrorPtr last_error_ = nullptr;
// Values copied from |last_error_| valid after UrlRequest is destroyed.
Cronet_Error_ERROR_CODE last_error_code_ =
Cronet_Error_ERROR_CODE_ERROR_OTHER;
std::string last_error_message_;
ResponseStep response_step_ = NOTHING;
......
This diff is collapsed.
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_CRONET_NATIVE_UPLOAD_DATA_SINK_H_
#define COMPONENTS_CRONET_NATIVE_UPLOAD_DATA_SINK_H_
#include <memory>
#include <string>
#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "components/cronet/cronet_upload_data_stream.h"
#include "components/cronet/cronet_url_request.h"
#include "components/cronet/cronet_url_request_context.h"
#include "components/cronet/native/generated/cronet.idl_impl_interface.h"
namespace cronet {
class Cronet_UrlRequestImpl;
class Cronet_BufferWithIOBuffer;
// Implementation of Cronet_UploadDataSink that uses CronetUploadDataStream.
// Always accessed on client executor.
class Cronet_UploadDataSinkImpl : public Cronet_UploadDataSink {
public:
Cronet_UploadDataSinkImpl(Cronet_UrlRequestImpl* url_request,
Cronet_UploadDataProvider* upload_data_provider,
Cronet_Executor* upload_data_provider_executor);
~Cronet_UploadDataSinkImpl() override;
// Initialize length and attach upload to request. Called on client thread.
bool InitRequest(CronetURLRequest* request);
// Mark stream as closed and post |Close()| callback to consumer.
void PostCloseToExecutor();
private:
class NetworkTasks;
enum UserCallback { READ, REWIND, GET_LENGTH, NOT_IN_CALLBACK };
// Cronet_UploadDataSink
void OnReadSucceeded(uint64_t bytes_read, bool final_chunk) override;
void OnReadError(Cronet_String error_message) override;
void OnRewindSucceeded() override;
void OnRewindError(Cronet_String error_message) override;
// CronetUploadDataStream::Delegate methods posted from the network thread.
void InitializeUploadDataStream(
base::WeakPtr<CronetUploadDataStream> upload_data_stream,
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner);
void Read(net::IOBuffer* buffer, int buf_len);
void Rewind();
void Close();
void CheckState(UserCallback expected_state);
// Cronet objects not owned by |this| and accessed on client thread.
// The request, which owns |this|.
Cronet_UrlRequestImpl* const url_request_ = nullptr;
// Executor for provider callback, used, but not owned, by |this|. Always
// outlives |this| callback.
Cronet_ExecutorPtr const upload_data_provider_executor_ = nullptr;
// These are initialized in InitializeUploadDataStream(), so are safe to
// access during client callbacks, which all happen after initialization.
scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
base::WeakPtr<CronetUploadDataStream> upload_data_stream_;
bool is_chunked_ = false;
uint64_t length_ = 0;
uint64_t remaining_length_ = 0;
// Synchronize access to |buffer_| and other objects below from different
// threads.
base::Lock lock_;
// Data provider callback interface, used, but not owned, by |this|.
// Set to nullptr when data provider is closed.
Cronet_UploadDataProviderPtr upload_data_provider_ = nullptr;
UserCallback in_which_user_callback_ = NOT_IN_CALLBACK;
// Close data provider once it returns from the callback.
bool close_when_not_in_callback_ = false;
// Keeps the net::IOBuffer and Cronet ByteBuffer alive until the next Read().
std::unique_ptr<Cronet_BufferWithIOBuffer> buffer_;
DISALLOW_COPY_AND_ASSIGN(Cronet_UploadDataSinkImpl);
};
} // namespace cronet
#endif // COMPONENTS_CRONET_NATIVE_UPLOAD_DATA_SINK_H_
This diff is collapsed.
......@@ -10,7 +10,6 @@
#include "base/macros.h"
#include "base/synchronization/lock.h"
#include "base/synchronization/waitable_event.h"
#include "components/cronet/cronet_url_request.h"
#include "components/cronet/cronet_url_request_context.h"
#include "components/cronet/native/generated/cronet.idl_impl_interface.h"
......@@ -18,6 +17,7 @@
namespace cronet {
class Cronet_EngineImpl;
class Cronet_UploadDataSinkImpl;
// Implementation of Cronet_UrlRequest that uses CronetURLRequestContext.
class Cronet_UrlRequestImpl : public Cronet_UrlRequest {
......@@ -38,8 +38,12 @@ class Cronet_UrlRequestImpl : public Cronet_UrlRequest {
bool IsDone() override;
void GetStatus(Cronet_UrlRequestStatusListenerPtr listener) override;
// Upload data provider has reported error while reading or rewinding
// so request must fail.
void OnUploadDataProviderError(const std::string& error_message);
private:
class Callback;
class NetworkTasks;
// Return |true| if request has started and is now done.
// Must be called under |lock_| held.
......@@ -57,6 +61,19 @@ class Cronet_UrlRequestImpl : public Cronet_UrlRequest {
bool DestroyRequestUnlessDoneLocked(
Cronet_RequestFinishedInfo_FINISHED_REASON finished_reason);
// Helper method to post |task| to the |executor_|.
void PostTaskToExecutor(base::OnceClosure task);
// Helper methods to invoke application |callback_|.
void InvokeCallbackOnRedirectReceived();
void InvokeCallbackOnResponseStarted();
void InvokeCallbackOnReadCompleted(
std::unique_ptr<Cronet_Buffer> cronet_buffer,
int bytes_read);
void InvokeCallbackOnSucceeded();
void InvokeCallbackOnFailed();
void InvokeCallbackOnCanceled();
// Synchronize access to |request_| and other objects below from different
// threads.
base::Lock lock_;
......@@ -72,6 +89,14 @@ class Cronet_UrlRequestImpl : public Cronet_UrlRequest {
// The error reported by request. May be nullptr if no error has occurred.
std::unique_ptr<Cronet_Error> error_;
// The upload data stream if specified.
std::unique_ptr<Cronet_UploadDataSinkImpl> upload_data_sink_;
// Application callback interface, used, but not owned, by |this|.
Cronet_UrlRequestCallbackPtr callback_ = nullptr;
// Executor for application callback, used, but not owned, by |this|.
Cronet_ExecutorPtr executor_ = nullptr;
// Cronet Engine used to run network operations. Not owned, accessed from
// client thread. Must outlive this request.
Cronet_EngineImpl* engine_;
......
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