| Index: ipc/ipc_channel_reader_unittest.cc
|
| diff --git a/ipc/ipc_channel_reader_unittest.cc b/ipc/ipc_channel_reader_unittest.cc
|
| index fdf31446b005bb464cc3c0928512a3c630686b28..f49c275b0e3a1cb7ecd76505dab1067158d502a9 100644
|
| --- a/ipc/ipc_channel_reader_unittest.cc
|
| +++ b/ipc/ipc_channel_reader_unittest.cc
|
| @@ -13,6 +13,14 @@
|
| #include "ipc/placeholder_brokerable_attachment.h"
|
| #include "testing/gtest/include/gtest/gtest.h"
|
|
|
| +// Whether IPC::Message::FindNext() can determine message size for
|
| +// partial messages. The condition is from FindNext() implementation.
|
| +#if USE_ATTACHMENT_BROKER && defined(OS_MACOSX) && !defined(OS_IOS)
|
| +#define MESSAGE_FINDNEXT_PARTIAL 0
|
| +#else
|
| +#define MESSAGE_FINDNEXT_PARTIAL 1
|
| +#endif
|
| +
|
| namespace IPC {
|
| namespace internal {
|
|
|
| @@ -64,7 +72,14 @@ class MockChannelReader : public ChannelReader {
|
| : ChannelReader(nullptr), last_dispatched_message_(nullptr) {}
|
|
|
| ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) override {
|
| - return READ_FAILED;
|
| + 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; }
|
| @@ -92,9 +107,18 @@ class MockChannelReader : public ChannelReader {
|
|
|
| void set_broker(AttachmentBroker* broker) { broker_ = broker; }
|
|
|
| + 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:
|
| Message* last_dispatched_message_;
|
| AttachmentBroker* broker_;
|
| + std::string data_;
|
| };
|
|
|
| class ExposedMessage: public Message {
|
| @@ -103,6 +127,9 @@ class ExposedMessage: public Message {
|
| using Message::header;
|
| };
|
|
|
| +// Payload that makes messages large
|
| +const size_t LargePayloadSize = Channel::kMaximumReadBufferSize * 3 / 2;
|
| +
|
| } // namespace
|
|
|
| #if USE_ATTACHMENT_BROKER
|
| @@ -192,5 +219,155 @@ TEST(ChannelReaderTest, InvalidMessageSize) {
|
|
|
| #endif // !USE_ATTACHMENT_BROKER
|
|
|
| +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());
|
| +
|
| +#if MESSAGE_FINDNEXT_PARTIAL
|
| + // 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());
|
| +#else
|
| + // We couldn't determine message size, so we didn't resize the buffer.
|
| +#endif
|
| +
|
| + // 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());
|
| +
|
| +#if MESSAGE_FINDNEXT_PARTIAL
|
| + // 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());
|
| +#else
|
| + // We couldn't determine message size for the second (partial) message,
|
| + // so we trimmed the buffer.
|
| + EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
|
| +#endif
|
| + }
|
| +
|
| + // 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());
|
| +
|
| +#if MESSAGE_FINDNEXT_PARTIAL
|
| + // 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());
|
| +#else
|
| + // We couldn't determine message size for the second (partial) message,
|
| + // so we trimmed the buffer.
|
| + EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
|
| +#endif
|
| + }
|
| +
|
| + // 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());
|
| +
|
| +#if MESSAGE_FINDNEXT_PARTIAL
|
| + // 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());
|
| +#else
|
| + // We couldn't determine size for the second (partial) message, and
|
| + // first message was small, so we did nothing.
|
| +#endif
|
| + }
|
| +}
|
| +
|
| } // namespace internal
|
| } // namespace IPC
|
|
|