Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1498)

Unified Diff: ipc/ipc_channel_reader_unittest.cc

Issue 1377483003: Trim IPC ChannelReader's buffer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@reserve-buffer
Patch Set: Fix USE_ATTACHMENT_BROKER && defined(OS_MACOSX) && !defined(OS_IOS) case Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ipc/ipc_channel_reader.cc ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « ipc/ipc_channel_reader.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698