123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- // Copyright 2015 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 "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;
- };
- // Payload that makes messages large
- const size_t LargePayloadSize = Channel::kMaximumReadBufferSize * 3 / 2;
- } // namespace
- // We can determine message size from its header (and hence resize the buffer)
- // only when attachment broker is not used, see IPC::Message::FindNext().
- 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)));
- // Once message header is available we resize overflow buffer to
- // fit the entire message.
- 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();
- // Message is slightly larger than maximum allowed size
- 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);
- // Payload size is negative, overflow is detected by Pickle::PeekNext()
- 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);
- // Payload size is maximum int32_t value
- 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) {
- // ChannelReader uses std::string as a buffer, and calls reserve()
- // to trim it to kMaximumReadBufferSize. However, an implementation
- // is free to actually reserve a larger amount.
- size_t trimmed_buffer_size;
- {
- std::string buf;
- buf.reserve(Channel::kMaximumReadBufferSize);
- trimmed_buffer_size = buf.capacity();
- }
- // Buffer is trimmed after message is processed.
- {
- MockChannelReader reader;
- Message message;
- message.WriteString(std::string(LargePayloadSize, 'X'));
- // Sanity check
- EXPECT_TRUE(message.size() > trimmed_buffer_size);
- // Initially buffer is small
- EXPECT_LE(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
- // Write and process large message
- reader.AppendMessageData(message);
- EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
- reader.ProcessIncomingMessages());
- // After processing large message buffer is trimmed
- EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
- }
- // Buffer is trimmed only after entire message is processed.
- {
- MockChannelReader reader;
- ExposedMessage message;
- message.WriteString(std::string(LargePayloadSize, 'X'));
- // Write and process message header
- reader.AppendData(message.header(), sizeof(ExposedMessage::Header));
- EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
- reader.ProcessIncomingMessages());
- // We determined message size for the message from its header, so
- // we resized the buffer to fit.
- EXPECT_GE(reader.input_overflow_buf_.capacity(), message.size());
- // Write and process payload
- reader.AppendData(message.payload(), message.payload_size());
- EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
- reader.ProcessIncomingMessages());
- // But once we process the message, we trim the buffer
- EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
- }
- // Buffer is not trimmed if the next message is also large.
- {
- MockChannelReader reader;
- // Write large message
- Message message1;
- message1.WriteString(std::string(LargePayloadSize * 2, 'X'));
- reader.AppendMessageData(message1);
- // Write header for the next large message
- ExposedMessage message2;
- message2.WriteString(std::string(LargePayloadSize, 'Y'));
- reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
- // Process messages
- EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
- reader.ProcessIncomingMessages());
- // We determined message size for the second (partial) message, so
- // we resized the buffer to fit.
- EXPECT_GE(reader.input_overflow_buf_.capacity(), message1.size());
- }
- // Buffer resized appropriately if next message is larger than the first.
- // (Similar to the test above except for the order of messages.)
- {
- MockChannelReader reader;
- // Write large message
- Message message1;
- message1.WriteString(std::string(LargePayloadSize, 'Y'));
- reader.AppendMessageData(message1);
- // Write header for the next even larger message
- ExposedMessage message2;
- message2.WriteString(std::string(LargePayloadSize * 2, 'X'));
- reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
- // Process messages
- EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
- reader.ProcessIncomingMessages());
- // We determined message size for the second (partial) message, and
- // resized the buffer to fit it.
- EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
- }
- // Buffer is not trimmed if we've just resized it to accommodate large
- // incoming message.
- {
- MockChannelReader reader;
- // Write small message
- Message message1;
- message1.WriteString(std::string(11, 'X'));
- reader.AppendMessageData(message1);
- // Write header for the next large message
- ExposedMessage message2;
- message2.WriteString(std::string(LargePayloadSize, 'Y'));
- reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
- EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
- reader.ProcessIncomingMessages());
- // We determined message size for the second (partial) message, so
- // we resized the buffer to fit.
- EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
- }
- }
- } // namespace internal
- } // namespace IPC
|