#include "net/socket/socket_bio_adapter.h"
#include <string.h>
#include <memory>
#include "base/check_op.h"
#include "base/compiler_specific.h"
#include "base/containers/span.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/run_loop.h"
#include "build/build_config.h"
#include "crypto/openssl_util.h"
#include "net/base/address_list.h"
#include "net/base/completion_once_callback.h"
#include "net/base/net_errors.h"
#include "net/log/net_log_source.h"
#include "net/socket/socket_test_util.h"
#include "net/socket/stream_socket.h"
#include "net/ssl/openssl_ssl_util.h"
#include "net/test/test_with_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/boringssl/src/include/openssl/bio.h"
#include "third_party/boringssl/src/include/openssl/err.h"
#include "third_party/boringssl/src/include/openssl/ssl.h"
namespace net {
enum ReadIfReadySupport {
READ_IF_READY_SUPPORTED,
READ_IF_READY_NOT_SUPPORTED,
};
class SocketBIOAdapterTest : public testing::TestWithParam<ReadIfReadySupport>,
public SocketBIOAdapter::Delegate,
public WithTaskEnvironment {
protected:
void SetUp() override {
if (GetParam() == READ_IF_READY_SUPPORTED) {
factory_.set_enable_read_if_ready(true);
}
}
std::unique_ptr<StreamSocket> MakeTestSocket(SocketDataProvider* data) {
data->set_connect_data(MockConnect(SYNCHRONOUS, OK));
factory_.AddSocketDataProvider(data);
std::unique_ptr<StreamSocket> socket = factory_.CreateTransportClientSocket(
AddressList(), nullptr, nullptr, nullptr, NetLogSource());
CHECK_EQ(OK, socket->Connect(CompletionOnceCallback()));
return socket;
}
void set_reset_on_write_ready(
std::unique_ptr<SocketBIOAdapter>* reset_on_write_ready) {
reset_on_write_ready_ = reset_on_write_ready;
}
void ExpectReadError(BIO* bio,
int error,
const crypto::OpenSSLErrStackTracer& tracer) {
char buf;
EXPECT_EQ(-1, BIO_read(bio, &buf, 1));
EXPECT_EQ(error, MapOpenSSLError(SSL_ERROR_SSL, tracer));
EXPECT_FALSE(BIO_should_read(bio));
EXPECT_EQ(-1, BIO_read(bio, &buf, 1));
EXPECT_EQ(error, MapOpenSSLError(SSL_ERROR_SSL, tracer));
EXPECT_FALSE(BIO_should_read(bio));
}
void ExpectBlockingRead(BIO* bio, void* buf, int len) {
EXPECT_EQ(-1, BIO_read(bio, buf, len));
EXPECT_TRUE(BIO_should_read(bio));
EXPECT_EQ(0u, ERR_peek_error());
EXPECT_EQ(-1, BIO_read(bio, buf, len));
EXPECT_TRUE(BIO_should_read(bio));
EXPECT_EQ(0u, ERR_peek_error());
}
void ExpectWriteError(BIO* bio,
int error,
const crypto::OpenSSLErrStackTracer& tracer) {
char buf = '?';
EXPECT_EQ(-1, BIO_write(bio, &buf, 1));
EXPECT_EQ(error, MapOpenSSLError(SSL_ERROR_SSL, tracer));
EXPECT_FALSE(BIO_should_write(bio));
EXPECT_EQ(-1, BIO_write(bio, &buf, 1));
EXPECT_EQ(error, MapOpenSSLError(SSL_ERROR_SSL, tracer));
EXPECT_FALSE(BIO_should_write(bio));
}
void ExpectBlockingWrite(BIO* bio, const void* buf, int len) {
EXPECT_EQ(-1, BIO_write(bio, buf, len));
EXPECT_TRUE(BIO_should_write(bio));
EXPECT_EQ(0u, ERR_peek_error());
EXPECT_EQ(-1, BIO_write(bio, buf, len));
EXPECT_TRUE(BIO_should_write(bio));
EXPECT_EQ(0u, ERR_peek_error());
}
void WaitForReadReady() {
expect_read_ready_ = true;
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(expect_read_ready_);
}
void WaitForWriteReady(SequencedSocketData* to_resume) {
expect_write_ready_ = true;
if (to_resume) {
to_resume->Resume();
}
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(expect_write_ready_);
}
void WaitForBothReady() {
expect_read_ready_ = true;
expect_write_ready_ = true;
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(expect_read_ready_);
EXPECT_FALSE(expect_write_ready_);
}
void OnReadReady() override {
EXPECT_TRUE(expect_read_ready_);
expect_read_ready_ = false;
}
void OnWriteReady() override {
EXPECT_TRUE(expect_write_ready_);
expect_write_ready_ = false;
if (reset_on_write_ready_)
reset_on_write_ready_->reset();
}
private:
bool expect_read_ready_ = false;
bool expect_write_ready_ = false;
MockClientSocketFactory factory_;
raw_ptr<std::unique_ptr<SocketBIOAdapter>> reset_on_write_ready_ = nullptr;
};
INSTANTIATE_TEST_SUITE_P(All,
SocketBIOAdapterTest,
testing::Values(READ_IF_READY_SUPPORTED,
READ_IF_READY_NOT_SUPPORTED));
TEST_P(SocketBIOAdapterTest, ReadSync) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockRead reads[] = {
MockRead(SYNCHRONOUS, 0, "hello"), MockRead(SYNCHRONOUS, 1, "world"),
MockRead(SYNCHRONOUS, ERR_CONNECTION_RESET, 2),
};
SequencedSocketData data(reads, base::span<MockWrite>());
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 100, 100, this);
BIO* bio = adapter->bio();
EXPECT_FALSE(adapter->HasPendingReadData());
char buf[10];
EXPECT_EQ(5, BIO_read(bio, buf, sizeof(buf)));
UNSAFE_TODO(EXPECT_EQ(0, memcmp("hello", buf, 5)));
EXPECT_FALSE(adapter->HasPendingReadData());
EXPECT_EQ(1, BIO_read(bio, buf, 1));
EXPECT_EQ('w', buf[0]);
EXPECT_TRUE(adapter->HasPendingReadData());
EXPECT_EQ(1, BIO_read(bio, buf, 1));
EXPECT_EQ('o', buf[0]);
EXPECT_TRUE(adapter->HasPendingReadData());
EXPECT_EQ(3, BIO_read(bio, buf, sizeof(buf)));
UNSAFE_TODO(EXPECT_EQ(0, memcmp("rld", buf, 3)));
EXPECT_FALSE(adapter->HasPendingReadData());
ExpectReadError(bio, ERR_CONNECTION_RESET, tracer);
}
TEST_P(SocketBIOAdapterTest, ReadAsync) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockRead reads[] = {
MockRead(ASYNC, 0, "hello"), MockRead(ASYNC, 1, "world"),
MockRead(ASYNC, ERR_CONNECTION_RESET, 2),
};
SequencedSocketData data(reads, base::span<MockWrite>());
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 100, 100, this);
BIO* bio = adapter->bio();
EXPECT_FALSE(adapter->HasPendingReadData());
char buf[10];
ExpectBlockingRead(bio, buf, sizeof(buf));
EXPECT_FALSE(adapter->HasPendingReadData());
WaitForReadReady();
if (GetParam() == READ_IF_READY_SUPPORTED) {
EXPECT_FALSE(adapter->HasPendingReadData());
} else {
EXPECT_TRUE(adapter->HasPendingReadData());
}
EXPECT_EQ(5, BIO_read(bio, buf, sizeof(buf)));
UNSAFE_TODO(EXPECT_EQ(0, memcmp("hello", buf, 5)));
EXPECT_FALSE(adapter->HasPendingReadData());
base::RunLoop().RunUntilIdle();
EXPECT_FALSE(adapter->HasPendingReadData());
ExpectBlockingRead(bio, buf, 1);
EXPECT_FALSE(adapter->HasPendingReadData());
WaitForReadReady();
if (GetParam() == READ_IF_READY_SUPPORTED) {
EXPECT_FALSE(adapter->HasPendingReadData());
} else {
EXPECT_TRUE(adapter->HasPendingReadData());
}
EXPECT_EQ(5, BIO_read(bio, buf, sizeof(buf)));
UNSAFE_TODO(EXPECT_EQ(0, memcmp("world", buf, 5)));
EXPECT_FALSE(adapter->HasPendingReadData());
ExpectBlockingRead(bio, buf, sizeof(buf));
WaitForReadReady();
ExpectReadError(bio, ERR_CONNECTION_RESET, tracer);
}
TEST_P(SocketBIOAdapterTest, ReadEOFSync) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockRead reads[] = {
MockRead(SYNCHRONOUS, 0, 0),
};
SequencedSocketData data(reads, base::span<MockWrite>());
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 100, 100, this);
ExpectReadError(adapter->bio(), ERR_CONNECTION_CLOSED, tracer);
}
#if BUILDFLAG(IS_ANDROID)
#define MAYBE_ReadEOFAsync DISABLED_ReadEOFAsync
#else
#define MAYBE_ReadEOFAsync ReadEOFAsync
#endif
TEST_P(SocketBIOAdapterTest, MAYBE_ReadEOFAsync) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockRead reads[] = {
MockRead(ASYNC, 0, 0),
};
SequencedSocketData data(reads, base::span<MockWrite>());
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 100, 100, this);
char buf;
ExpectBlockingRead(adapter->bio(), &buf, 1);
WaitForReadReady();
ExpectReadError(adapter->bio(), ERR_CONNECTION_CLOSED, tracer);
}
TEST_P(SocketBIOAdapterTest, WriteSync) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, 0, "hello"),
MockWrite(SYNCHRONOUS, 1, "wor"),
MockWrite(SYNCHRONOUS, 2, "ld"),
MockWrite(SYNCHRONOUS, 3, "helloworld"),
MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET, 4),
};
SequencedSocketData data(base::span<MockRead>(), writes);
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 10, 10, this);
BIO* bio = adapter->bio();
EXPECT_EQ(5, BIO_write(bio, "hello", 5));
EXPECT_EQ(5, BIO_write(bio, "world", 5));
EXPECT_EQ(10, BIO_write(bio, "helloworldhelloworld", 20));
EXPECT_EQ(5, BIO_write(bio, "aaaaa", 5));
ExpectWriteError(bio, ERR_CONNECTION_RESET, tracer);
}
TEST_P(SocketBIOAdapterTest, WriteAsync) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockWrite writes[] = {
MockWrite(ASYNC, 0, "aaa"),
MockWrite(ASYNC, ERR_IO_PENDING, 1),
MockWrite(ASYNC, 2, "aabbbbb"),
MockWrite(ASYNC, 3, "ccc"),
MockWrite(ASYNC, 4, "ddd"),
MockWrite(ASYNC, ERR_IO_PENDING, 5),
MockWrite(ASYNC, 6, "dd"),
MockWrite(SYNCHRONOUS, 7, "e"),
MockWrite(SYNCHRONOUS, 8, "e"),
MockWrite(ASYNC, 9, "e"),
MockWrite(ASYNC, 10, "ee"),
MockWrite(ASYNC, ERR_IO_PENDING, 11),
MockWrite(ASYNC, 12, "eff"),
MockWrite(ASYNC, 13, "ggggggg"),
MockWrite(ASYNC, ERR_CONNECTION_RESET, 14),
};
SequencedSocketData data(base::span<MockRead>(), writes);
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 10, 10, this);
BIO* bio = adapter->bio();
EXPECT_EQ(5, BIO_write(bio, "aaaaa", 5));
EXPECT_EQ(5, BIO_write(bio, "bbbbb", 5));
ExpectBlockingWrite(bio, "zzzzz", 5);
WaitForWriteReady(nullptr);
EXPECT_TRUE(data.IsPaused());
EXPECT_EQ(3, BIO_write(bio, "cccccccccc", 10));
WaitForWriteReady(&data);
EXPECT_EQ(5, BIO_write(bio, "ddddd", 5));
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(data.IsPaused());
EXPECT_EQ(6, BIO_write(bio, "eeeeee", 6));
EXPECT_EQ(2, BIO_write(bio, "ffffffffff", 10));
WaitForWriteReady(&data);
EXPECT_TRUE(data.IsPaused());
EXPECT_EQ(7, BIO_write(bio, "gggggggggg", 10));
ExpectBlockingWrite(bio, "zzzzz", 5);
WaitForWriteReady(&data);
EXPECT_EQ(5, BIO_write(bio, "hhhhh", 5));
base::RunLoop().RunUntilIdle();
ExpectWriteError(bio, ERR_CONNECTION_RESET, tracer);
}
TEST_P(SocketBIOAdapterTest, WriteStopsRead) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET, 0),
};
SequencedSocketData data(base::span<MockRead>(), writes);
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 100, 100, this);
BIO* bio = adapter->bio();
EXPECT_EQ(5, BIO_write(bio, "aaaaa", 5));
ExpectReadError(bio, ERR_CONNECTION_RESET, tracer);
}
TEST_P(SocketBIOAdapterTest, SyncWriteInterruptsRead) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0),
};
MockWrite writes[] = {
MockWrite(SYNCHRONOUS, ERR_CONNECTION_RESET, 1),
};
SequencedSocketData data(reads, writes);
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 100, 100, this);
BIO* bio = adapter->bio();
char buf;
ExpectBlockingRead(adapter->bio(), &buf, 1);
EXPECT_EQ(5, BIO_write(bio, "aaaaa", 5));
WaitForReadReady();
ExpectReadError(bio, ERR_CONNECTION_RESET, tracer);
}
TEST_P(SocketBIOAdapterTest, AsyncWriteInterruptsRead) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0),
};
MockWrite writes[] = {
MockWrite(ASYNC, ERR_CONNECTION_RESET, 1),
};
SequencedSocketData data(reads, writes);
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 100, 100, this);
BIO* bio = adapter->bio();
char buf;
ExpectBlockingRead(adapter->bio(), &buf, 1);
EXPECT_EQ(5, BIO_write(bio, "aaaaa", 5));
WaitForReadReady();
ExpectReadError(bio, ERR_CONNECTION_RESET, tracer);
}
TEST_P(SocketBIOAdapterTest, AsyncWriteInterruptsBoth) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0),
};
MockWrite writes[] = {
MockWrite(ASYNC, ERR_CONNECTION_RESET, 1),
};
SequencedSocketData data(reads, writes);
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 5, 5, this);
BIO* bio = adapter->bio();
char buf;
ExpectBlockingRead(adapter->bio(), &buf, 1);
EXPECT_EQ(5, BIO_write(bio, "aaaaa", 5));
WaitForBothReady();
ExpectReadError(bio, ERR_CONNECTION_RESET, tracer);
}
TEST_P(SocketBIOAdapterTest, DeleteOnWriteReady) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
MockRead reads[] = {
MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0),
};
MockWrite writes[] = {
MockWrite(ASYNC, ERR_CONNECTION_RESET, 1),
};
SequencedSocketData data(reads, writes);
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 5, 5, this);
BIO* bio = adapter->bio();
char buf;
ExpectBlockingRead(adapter->bio(), &buf, 1);
EXPECT_EQ(5, BIO_write(bio, "aaaaa", 5));
set_reset_on_write_ready(&adapter);
WaitForWriteReady(nullptr);
EXPECT_FALSE(adapter);
}
TEST_P(SocketBIOAdapterTest, Detached) {
crypto::OpenSSLErrStackTracer tracer(FROM_HERE);
SequencedSocketData data;
std::unique_ptr<StreamSocket> socket = MakeTestSocket(&data);
std::unique_ptr<SocketBIOAdapter> adapter =
std::make_unique<SocketBIOAdapter>(socket.get(), 100, 100, this);
bssl::UniquePtr<BIO> bio = bssl::UpRef(adapter->bio());
adapter.reset();
ExpectReadError(bio.get(), ERR_UNEXPECTED, tracer);
ExpectWriteError(bio.get(), ERR_UNEXPECTED, tracer);
}
}