#include "base/memory/raw_ptr.h"
#include "build/build_config.h"
#include <stddef.h>
#include <stdint.h>
#include <limits>
#include <memory>
#include <set>
#include "base/run_loop.h"
#include "ipc/ipc_channel_reader.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace IPC {
namespace internal {
namespace {
class MockChannelReader : public ChannelReader {
public:
MockChannelReader()
: ChannelReader(nullptr), last_dispatched_message_(nullptr) {}
ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) override {
if (data_.empty())
return READ_PENDING;
size_t read_len = std::min(static_cast<size_t>(buffer_len), data_.size());
memcpy(buffer, data_.data(), read_len);
*bytes_read = static_cast<int>(read_len);
data_.erase(0, read_len);
return READ_SUCCEEDED;
}
bool ShouldDispatchInputMessage(Message* msg) override { return true; }
bool GetAttachments(Message* msg) override { return true; }
bool DidEmptyInputBuffers() override { return true; }
void HandleInternalMessage(const Message& msg) override {}
void DispatchMessage(Message* m) override { last_dispatched_message_ = m; }
Message* get_last_dispatched_message() { return last_dispatched_message_; }
void AppendData(const void* data, size_t size) {
data_.append(static_cast<const char*>(data), size);
}
void AppendMessageData(const Message& message) {
AppendData(message.data(), message.size());
}
private:
raw_ptr<Message> last_dispatched_message_;
std::string data_;
};
class ExposedMessage: public Message {
public:
using Message::Header;
using Message::header;
};
const size_t LargePayloadSize = Channel::kMaximumReadBufferSize * 3 / 2;
}
TEST(ChannelReaderTest, ResizeOverflowBuffer) {
MockChannelReader reader;
ExposedMessage::Header header = {};
header.payload_size = 128 * 1024;
EXPECT_LT(reader.input_overflow_buf_.capacity(), header.payload_size);
EXPECT_TRUE(reader.TranslateInputData(
reinterpret_cast<const char*>(&header), sizeof(header)));
EXPECT_GE(reader.input_overflow_buf_.capacity(), header.payload_size);
}
TEST(ChannelReaderTest, InvalidMessageSize) {
MockChannelReader reader;
ExposedMessage::Header header = {};
size_t capacity_before = reader.input_overflow_buf_.capacity();
header.payload_size = Channel::kMaximumMessageSize + 1;
EXPECT_FALSE(reader.TranslateInputData(
reinterpret_cast<const char*>(&header), sizeof(header)));
EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
header.payload_size = static_cast<uint32_t>(-1);
EXPECT_FALSE(reader.TranslateInputData(
reinterpret_cast<const char*>(&header), sizeof(header)));
EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
header.payload_size = std::numeric_limits<int32_t>::max();
EXPECT_FALSE(reader.TranslateInputData(
reinterpret_cast<const char*>(&header), sizeof(header)));
EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
}
TEST(ChannelReaderTest, TrimBuffer) {
size_t trimmed_buffer_size;
{
std::string buf;
buf.reserve(Channel::kMaximumReadBufferSize);
trimmed_buffer_size = buf.capacity();
}
{
MockChannelReader reader;
Message message;
message.WriteString(std::string(LargePayloadSize, 'X'));
EXPECT_TRUE(message.size() > trimmed_buffer_size);
EXPECT_LE(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
reader.AppendMessageData(message);
EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
reader.ProcessIncomingMessages());
EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
}
{
MockChannelReader reader;
ExposedMessage message;
message.WriteString(std::string(LargePayloadSize, 'X'));
reader.AppendData(message.header(), sizeof(ExposedMessage::Header));
EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
reader.ProcessIncomingMessages());
EXPECT_GE(reader.input_overflow_buf_.capacity(), message.size());
reader.AppendData(message.payload(), message.payload_size());
EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
reader.ProcessIncomingMessages());
EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
}
{
MockChannelReader reader;
Message message1;
message1.WriteString(std::string(LargePayloadSize * 2, 'X'));
reader.AppendMessageData(message1);
ExposedMessage message2;
message2.WriteString(std::string(LargePayloadSize, 'Y'));
reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
reader.ProcessIncomingMessages());
EXPECT_GE(reader.input_overflow_buf_.capacity(), message1.size());
}
{
MockChannelReader reader;
Message message1;
message1.WriteString(std::string(LargePayloadSize, 'Y'));
reader.AppendMessageData(message1);
ExposedMessage message2;
message2.WriteString(std::string(LargePayloadSize * 2, 'X'));
reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
reader.ProcessIncomingMessages());
EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
}
{
MockChannelReader reader;
Message message1;
message1.WriteString(std::string(11, 'X'));
reader.AppendMessageData(message1);
ExposedMessage message2;
message2.WriteString(std::string(LargePayloadSize, 'Y'));
reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
reader.ProcessIncomingMessages());
EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
}
}
}
}