xref: /aosp_15_r20/external/cronet/ipc/ipc_channel_reader_unittest.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2015 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/memory/raw_ptr.h"
6 #include "build/build_config.h"
7 
8 #include <stddef.h>
9 #include <stdint.h>
10 
11 #include <limits>
12 #include <memory>
13 #include <set>
14 
15 #include "base/run_loop.h"
16 #include "ipc/ipc_channel_reader.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 
19 namespace IPC {
20 namespace internal {
21 
22 namespace {
23 
24 class MockChannelReader : public ChannelReader {
25  public:
MockChannelReader()26   MockChannelReader()
27       : ChannelReader(nullptr), last_dispatched_message_(nullptr) {}
28 
ReadData(char * buffer,int buffer_len,int * bytes_read)29   ReadState ReadData(char* buffer, int buffer_len, int* bytes_read) override {
30     if (data_.empty())
31       return READ_PENDING;
32 
33     size_t read_len = std::min(static_cast<size_t>(buffer_len), data_.size());
34     memcpy(buffer, data_.data(), read_len);
35     *bytes_read = static_cast<int>(read_len);
36     data_.erase(0, read_len);
37     return READ_SUCCEEDED;
38   }
39 
ShouldDispatchInputMessage(Message * msg)40   bool ShouldDispatchInputMessage(Message* msg) override { return true; }
41 
GetAttachments(Message * msg)42   bool GetAttachments(Message* msg) override { return true; }
43 
DidEmptyInputBuffers()44   bool DidEmptyInputBuffers() override { return true; }
45 
HandleInternalMessage(const Message & msg)46   void HandleInternalMessage(const Message& msg) override {}
47 
DispatchMessage(Message * m)48   void DispatchMessage(Message* m) override { last_dispatched_message_ = m; }
49 
get_last_dispatched_message()50   Message* get_last_dispatched_message() { return last_dispatched_message_; }
51 
AppendData(const void * data,size_t size)52   void AppendData(const void* data, size_t size) {
53     data_.append(static_cast<const char*>(data), size);
54   }
55 
AppendMessageData(const Message & message)56   void AppendMessageData(const Message& message) {
57     AppendData(message.data(), message.size());
58   }
59 
60  private:
61   raw_ptr<Message> last_dispatched_message_;
62   std::string data_;
63 };
64 
65 class ExposedMessage: public Message {
66  public:
67   using Message::Header;
68   using Message::header;
69 };
70 
71 // Payload that makes messages large
72 const size_t LargePayloadSize = Channel::kMaximumReadBufferSize * 3 / 2;
73 
74 }  // namespace
75 
76 // We can determine message size from its header (and hence resize the buffer)
77 // only when attachment broker is not used, see IPC::Message::FindNext().
78 
TEST(ChannelReaderTest,ResizeOverflowBuffer)79 TEST(ChannelReaderTest, ResizeOverflowBuffer) {
80   MockChannelReader reader;
81 
82   ExposedMessage::Header header = {};
83 
84   header.payload_size = 128 * 1024;
85   EXPECT_LT(reader.input_overflow_buf_.capacity(), header.payload_size);
86   EXPECT_TRUE(reader.TranslateInputData(
87       reinterpret_cast<const char*>(&header), sizeof(header)));
88 
89   // Once message header is available we resize overflow buffer to
90   // fit the entire message.
91   EXPECT_GE(reader.input_overflow_buf_.capacity(), header.payload_size);
92 }
93 
TEST(ChannelReaderTest,InvalidMessageSize)94 TEST(ChannelReaderTest, InvalidMessageSize) {
95   MockChannelReader reader;
96 
97   ExposedMessage::Header header = {};
98 
99   size_t capacity_before = reader.input_overflow_buf_.capacity();
100 
101   // Message is slightly larger than maximum allowed size
102   header.payload_size = Channel::kMaximumMessageSize + 1;
103   EXPECT_FALSE(reader.TranslateInputData(
104       reinterpret_cast<const char*>(&header), sizeof(header)));
105   EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
106 
107   // Payload size is negative, overflow is detected by Pickle::PeekNext()
108   header.payload_size = static_cast<uint32_t>(-1);
109   EXPECT_FALSE(reader.TranslateInputData(
110       reinterpret_cast<const char*>(&header), sizeof(header)));
111   EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
112 
113   // Payload size is maximum int32_t value
114   header.payload_size = std::numeric_limits<int32_t>::max();
115   EXPECT_FALSE(reader.TranslateInputData(
116       reinterpret_cast<const char*>(&header), sizeof(header)));
117   EXPECT_LE(reader.input_overflow_buf_.capacity(), capacity_before);
118 }
119 
TEST(ChannelReaderTest,TrimBuffer)120 TEST(ChannelReaderTest, TrimBuffer) {
121   // ChannelReader uses std::string as a buffer, and calls reserve()
122   // to trim it to kMaximumReadBufferSize. However, an implementation
123   // is free to actually reserve a larger amount.
124   size_t trimmed_buffer_size;
125   {
126     std::string buf;
127     buf.reserve(Channel::kMaximumReadBufferSize);
128     trimmed_buffer_size = buf.capacity();
129   }
130 
131   // Buffer is trimmed after message is processed.
132   {
133     MockChannelReader reader;
134 
135     Message message;
136     message.WriteString(std::string(LargePayloadSize, 'X'));
137 
138     // Sanity check
139     EXPECT_TRUE(message.size() > trimmed_buffer_size);
140 
141     // Initially buffer is small
142     EXPECT_LE(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
143 
144     // Write and process large message
145     reader.AppendMessageData(message);
146     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
147               reader.ProcessIncomingMessages());
148 
149     // After processing large message buffer is trimmed
150     EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
151   }
152 
153   // Buffer is trimmed only after entire message is processed.
154   {
155     MockChannelReader reader;
156 
157     ExposedMessage message;
158     message.WriteString(std::string(LargePayloadSize, 'X'));
159 
160     // Write and process message header
161     reader.AppendData(message.header(), sizeof(ExposedMessage::Header));
162     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
163               reader.ProcessIncomingMessages());
164 
165     // We determined message size for the message from its header, so
166     // we resized the buffer to fit.
167     EXPECT_GE(reader.input_overflow_buf_.capacity(), message.size());
168 
169     // Write and process payload
170     reader.AppendData(message.payload_bytes().data(),
171                       message.payload_bytes().size());
172     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
173               reader.ProcessIncomingMessages());
174 
175     // But once we process the message, we trim the buffer
176     EXPECT_EQ(reader.input_overflow_buf_.capacity(), trimmed_buffer_size);
177   }
178 
179   // Buffer is not trimmed if the next message is also large.
180   {
181     MockChannelReader reader;
182 
183     // Write large message
184     Message message1;
185     message1.WriteString(std::string(LargePayloadSize * 2, 'X'));
186     reader.AppendMessageData(message1);
187 
188     // Write header for the next large message
189     ExposedMessage message2;
190     message2.WriteString(std::string(LargePayloadSize, 'Y'));
191     reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
192 
193     // Process messages
194     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
195               reader.ProcessIncomingMessages());
196 
197     // We determined message size for the second (partial) message, so
198     // we resized the buffer to fit.
199     EXPECT_GE(reader.input_overflow_buf_.capacity(), message1.size());
200   }
201 
202   // Buffer resized appropriately if next message is larger than the first.
203   // (Similar to the test above except for the order of messages.)
204   {
205     MockChannelReader reader;
206 
207     // Write large message
208     Message message1;
209     message1.WriteString(std::string(LargePayloadSize, 'Y'));
210     reader.AppendMessageData(message1);
211 
212     // Write header for the next even larger message
213     ExposedMessage message2;
214     message2.WriteString(std::string(LargePayloadSize * 2, 'X'));
215     reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
216 
217     // Process messages
218     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
219               reader.ProcessIncomingMessages());
220 
221     // We determined message size for the second (partial) message, and
222     // resized the buffer to fit it.
223     EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
224   }
225 
226   // Buffer is not trimmed if we've just resized it to accommodate large
227   // incoming message.
228   {
229     MockChannelReader reader;
230 
231     // Write small message
232     Message message1;
233     message1.WriteString(std::string(11, 'X'));
234     reader.AppendMessageData(message1);
235 
236     // Write header for the next large message
237     ExposedMessage message2;
238     message2.WriteString(std::string(LargePayloadSize, 'Y'));
239     reader.AppendData(message2.header(), sizeof(ExposedMessage::Header));
240 
241     EXPECT_EQ(ChannelReader::DISPATCH_FINISHED,
242               reader.ProcessIncomingMessages());
243 
244     // We determined message size for the second (partial) message, so
245     // we resized the buffer to fit.
246     EXPECT_GE(reader.input_overflow_buf_.capacity(), message2.size());
247   }
248 }
249 
250 }  // namespace internal
251 }  // namespace IPC
252