1 // Copyright 2014 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 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9
10 #include "net/server/http_connection.h"
11
12 #include <string>
13 #include <string_view>
14
15 #include "base/memory/ref_counted.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17
18 namespace net {
19 namespace {
20
GetTestString(int size)21 std::string GetTestString(int size) {
22 std::string test_string;
23 for (int i = 0; i < size; ++i) {
24 test_string.push_back('A' + (i % 26));
25 }
26 return test_string;
27 }
28
TEST(HttpConnectionTest,ReadIOBuffer_SetCapacity)29 TEST(HttpConnectionTest, ReadIOBuffer_SetCapacity) {
30 scoped_refptr<HttpConnection::ReadIOBuffer> buffer =
31 base::MakeRefCounted<HttpConnection::ReadIOBuffer>();
32 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize + 0,
33 buffer->GetCapacity());
34 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize + 0,
35 buffer->RemainingCapacity());
36 EXPECT_EQ(0, buffer->GetSize());
37
38 const int kNewCapacity = HttpConnection::ReadIOBuffer::kInitialBufSize + 128;
39 buffer->SetCapacity(kNewCapacity);
40 EXPECT_EQ(kNewCapacity, buffer->GetCapacity());
41 EXPECT_EQ(kNewCapacity, buffer->RemainingCapacity());
42 EXPECT_EQ(0, buffer->GetSize());
43 }
44
TEST(HttpConnectionTest,ReadIOBuffer_SetCapacity_WithData)45 TEST(HttpConnectionTest, ReadIOBuffer_SetCapacity_WithData) {
46 scoped_refptr<HttpConnection::ReadIOBuffer> buffer =
47 base::MakeRefCounted<HttpConnection::ReadIOBuffer>();
48 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize + 0,
49 buffer->GetCapacity());
50 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize + 0,
51 buffer->RemainingCapacity());
52
53 // Write arbitrary data up to kInitialBufSize.
54 const std::string kReadData(
55 GetTestString(HttpConnection::ReadIOBuffer::kInitialBufSize));
56 memcpy(buffer->data(), kReadData.data(), kReadData.size());
57 buffer->DidRead(kReadData.size());
58 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize + 0,
59 buffer->GetCapacity());
60 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize -
61 static_cast<int>(kReadData.size()),
62 buffer->RemainingCapacity());
63 EXPECT_EQ(static_cast<int>(kReadData.size()), buffer->GetSize());
64 EXPECT_EQ(kReadData,
65 std::string_view(buffer->StartOfBuffer(), buffer->GetSize()));
66
67 // Check if read data in the buffer is same after SetCapacity().
68 const int kNewCapacity = HttpConnection::ReadIOBuffer::kInitialBufSize + 128;
69 buffer->SetCapacity(kNewCapacity);
70 EXPECT_EQ(kNewCapacity, buffer->GetCapacity());
71 EXPECT_EQ(kNewCapacity - static_cast<int>(kReadData.size()),
72 buffer->RemainingCapacity());
73 EXPECT_EQ(static_cast<int>(kReadData.size()), buffer->GetSize());
74 EXPECT_EQ(kReadData,
75 std::string_view(buffer->StartOfBuffer(), buffer->GetSize()));
76 }
77
TEST(HttpConnectionTest,ReadIOBuffer_IncreaseCapacity)78 TEST(HttpConnectionTest, ReadIOBuffer_IncreaseCapacity) {
79 scoped_refptr<HttpConnection::ReadIOBuffer> buffer =
80 base::MakeRefCounted<HttpConnection::ReadIOBuffer>();
81 EXPECT_TRUE(buffer->IncreaseCapacity());
82 const int kExpectedInitialBufSize =
83 HttpConnection::ReadIOBuffer::kInitialBufSize *
84 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor;
85 EXPECT_EQ(kExpectedInitialBufSize, buffer->GetCapacity());
86 EXPECT_EQ(kExpectedInitialBufSize, buffer->RemainingCapacity());
87 EXPECT_EQ(0, buffer->GetSize());
88
89 // Increase capacity until it fails.
90 while (buffer->IncreaseCapacity());
91 EXPECT_FALSE(buffer->IncreaseCapacity());
92 EXPECT_EQ(HttpConnection::ReadIOBuffer::kDefaultMaxBufferSize + 0,
93 buffer->max_buffer_size());
94 EXPECT_EQ(HttpConnection::ReadIOBuffer::kDefaultMaxBufferSize + 0,
95 buffer->GetCapacity());
96
97 // Enlarge capacity limit.
98 buffer->set_max_buffer_size(buffer->max_buffer_size() * 2);
99 EXPECT_TRUE(buffer->IncreaseCapacity());
100 EXPECT_EQ(HttpConnection::ReadIOBuffer::kDefaultMaxBufferSize *
101 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor,
102 buffer->GetCapacity());
103
104 // Shrink capacity limit. It doesn't change capacity itself.
105 buffer->set_max_buffer_size(
106 HttpConnection::ReadIOBuffer::kDefaultMaxBufferSize / 2);
107 EXPECT_FALSE(buffer->IncreaseCapacity());
108 EXPECT_EQ(HttpConnection::ReadIOBuffer::kDefaultMaxBufferSize *
109 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor,
110 buffer->GetCapacity());
111 }
112
TEST(HttpConnectionTest,ReadIOBuffer_IncreaseCapacity_WithData)113 TEST(HttpConnectionTest, ReadIOBuffer_IncreaseCapacity_WithData) {
114 scoped_refptr<HttpConnection::ReadIOBuffer> buffer =
115 base::MakeRefCounted<HttpConnection::ReadIOBuffer>();
116 EXPECT_TRUE(buffer->IncreaseCapacity());
117 const int kExpectedInitialBufSize =
118 HttpConnection::ReadIOBuffer::kInitialBufSize *
119 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor;
120 EXPECT_EQ(kExpectedInitialBufSize, buffer->GetCapacity());
121 EXPECT_EQ(kExpectedInitialBufSize, buffer->RemainingCapacity());
122 EXPECT_EQ(0, buffer->GetSize());
123
124 // Write arbitrary data up to kExpectedInitialBufSize.
125 std::string kReadData(GetTestString(kExpectedInitialBufSize));
126 memcpy(buffer->data(), kReadData.data(), kReadData.size());
127 buffer->DidRead(kReadData.size());
128 EXPECT_EQ(kExpectedInitialBufSize, buffer->GetCapacity());
129 EXPECT_EQ(kExpectedInitialBufSize - static_cast<int>(kReadData.size()),
130 buffer->RemainingCapacity());
131 EXPECT_EQ(static_cast<int>(kReadData.size()), buffer->GetSize());
132 EXPECT_EQ(kReadData,
133 std::string_view(buffer->StartOfBuffer(), buffer->GetSize()));
134
135 // Increase capacity until it fails and check if read data in the buffer is
136 // same.
137 while (buffer->IncreaseCapacity());
138 EXPECT_FALSE(buffer->IncreaseCapacity());
139 EXPECT_EQ(HttpConnection::ReadIOBuffer::kDefaultMaxBufferSize + 0,
140 buffer->max_buffer_size());
141 EXPECT_EQ(HttpConnection::ReadIOBuffer::kDefaultMaxBufferSize + 0,
142 buffer->GetCapacity());
143 EXPECT_EQ(HttpConnection::ReadIOBuffer::kDefaultMaxBufferSize -
144 static_cast<int>(kReadData.size()),
145 buffer->RemainingCapacity());
146 EXPECT_EQ(static_cast<int>(kReadData.size()), buffer->GetSize());
147 EXPECT_EQ(kReadData,
148 std::string_view(buffer->StartOfBuffer(), buffer->GetSize()));
149 }
150
TEST(HttpConnectionTest,ReadIOBuffer_DidRead_DidConsume)151 TEST(HttpConnectionTest, ReadIOBuffer_DidRead_DidConsume) {
152 scoped_refptr<HttpConnection::ReadIOBuffer> buffer =
153 base::MakeRefCounted<HttpConnection::ReadIOBuffer>();
154 const char* start_of_buffer = buffer->StartOfBuffer();
155 EXPECT_EQ(start_of_buffer, buffer->data());
156
157 // Read data.
158 const int kReadLength = 128;
159 const std::string kReadData(GetTestString(kReadLength));
160 memcpy(buffer->data(), kReadData.data(), kReadLength);
161 buffer->DidRead(kReadLength);
162 // No change in total capacity.
163 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize + 0,
164 buffer->GetCapacity());
165 // Change in unused capacity because of read data.
166 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize - kReadLength,
167 buffer->RemainingCapacity());
168 EXPECT_EQ(kReadLength, buffer->GetSize());
169 // No change in start pointers of read data.
170 EXPECT_EQ(start_of_buffer, buffer->StartOfBuffer());
171 // Change in start pointer of unused buffer.
172 EXPECT_EQ(start_of_buffer + kReadLength, buffer->data());
173 // Test read data.
174 EXPECT_EQ(kReadData, std::string(buffer->StartOfBuffer(), buffer->GetSize()));
175
176 // Consume data partially.
177 const int kConsumedLength = 32;
178 ASSERT_LT(kConsumedLength, kReadLength);
179 buffer->DidConsume(kConsumedLength);
180 // Capacity reduced because read data was too small comparing to capacity.
181 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize /
182 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor,
183 buffer->GetCapacity());
184 // Change in unused capacity because of read data.
185 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize /
186 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor -
187 kReadLength + kConsumedLength,
188 buffer->RemainingCapacity());
189 // Change in read size.
190 EXPECT_EQ(kReadLength - kConsumedLength, buffer->GetSize());
191 // Start data could be changed even when capacity is reduced.
192 start_of_buffer = buffer->StartOfBuffer();
193 // Change in start pointer of unused buffer.
194 EXPECT_EQ(start_of_buffer + kReadLength - kConsumedLength, buffer->data());
195 // Change in read data.
196 EXPECT_EQ(kReadData.substr(kConsumedLength),
197 std::string(buffer->StartOfBuffer(), buffer->GetSize()));
198
199 // Read more data.
200 const int kReadLength2 = 64;
201 buffer->DidRead(kReadLength2);
202 // No change in total capacity.
203 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize /
204 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor,
205 buffer->GetCapacity());
206 // Change in unused capacity because of read data.
207 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize /
208 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor -
209 kReadLength + kConsumedLength - kReadLength2,
210 buffer->RemainingCapacity());
211 // Change in read size
212 EXPECT_EQ(kReadLength - kConsumedLength + kReadLength2, buffer->GetSize());
213 // No change in start pointer of read part.
214 EXPECT_EQ(start_of_buffer, buffer->StartOfBuffer());
215 // Change in start pointer of unused buffer.
216 EXPECT_EQ(start_of_buffer + kReadLength - kConsumedLength + kReadLength2,
217 buffer->data());
218
219 // Consume data fully.
220 buffer->DidConsume(kReadLength - kConsumedLength + kReadLength2);
221 // Capacity reduced again because read data was too small.
222 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize /
223 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor /
224 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor,
225 buffer->GetCapacity());
226 EXPECT_EQ(HttpConnection::ReadIOBuffer::kInitialBufSize /
227 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor /
228 HttpConnection::ReadIOBuffer::kCapacityIncreaseFactor,
229 buffer->RemainingCapacity());
230 // All reverts to initial because no data is left.
231 EXPECT_EQ(0, buffer->GetSize());
232 // Start data could be changed even when capacity is reduced.
233 start_of_buffer = buffer->StartOfBuffer();
234 EXPECT_EQ(start_of_buffer, buffer->data());
235 }
236
TEST(HttpConnectionTest,QueuedWriteIOBuffer_Append_DidConsume)237 TEST(HttpConnectionTest, QueuedWriteIOBuffer_Append_DidConsume) {
238 scoped_refptr<HttpConnection::QueuedWriteIOBuffer> buffer =
239 base::MakeRefCounted<HttpConnection::QueuedWriteIOBuffer>();
240 EXPECT_TRUE(buffer->IsEmpty());
241 EXPECT_EQ(0, buffer->GetSizeToWrite());
242 EXPECT_EQ(0, buffer->total_size());
243
244 const std::string kData("data to write");
245 EXPECT_TRUE(buffer->Append(kData));
246 EXPECT_FALSE(buffer->IsEmpty());
247 EXPECT_EQ(static_cast<int>(kData.size()), buffer->GetSizeToWrite());
248 EXPECT_EQ(static_cast<int>(kData.size()), buffer->total_size());
249 // First data to write is same to kData.
250 EXPECT_EQ(kData, std::string_view(buffer->data(), buffer->GetSizeToWrite()));
251
252 const std::string kData2("more data to write");
253 EXPECT_TRUE(buffer->Append(kData2));
254 EXPECT_FALSE(buffer->IsEmpty());
255 // No change in size to write.
256 EXPECT_EQ(static_cast<int>(kData.size()), buffer->GetSizeToWrite());
257 // Change in total size.
258 EXPECT_EQ(static_cast<int>(kData.size() + kData2.size()),
259 buffer->total_size());
260 // First data to write has not been changed. Same to kData.
261 EXPECT_EQ(kData, std::string_view(buffer->data(), buffer->GetSizeToWrite()));
262
263 // Consume data partially.
264 const int kConsumedLength = kData.length() - 1;
265 buffer->DidConsume(kConsumedLength);
266 EXPECT_FALSE(buffer->IsEmpty());
267 // Change in size to write.
268 EXPECT_EQ(static_cast<int>(kData.size()) - kConsumedLength,
269 buffer->GetSizeToWrite());
270 // Change in total size.
271 EXPECT_EQ(static_cast<int>(kData.size() + kData2.size()) - kConsumedLength,
272 buffer->total_size());
273 // First data to write has shrinked.
274 EXPECT_EQ(kData.substr(kConsumedLength),
275 std::string_view(buffer->data(), buffer->GetSizeToWrite()));
276
277 // Consume first data fully.
278 buffer->DidConsume(kData.size() - kConsumedLength);
279 EXPECT_FALSE(buffer->IsEmpty());
280 // Now, size to write is size of data added second.
281 EXPECT_EQ(static_cast<int>(kData2.size()), buffer->GetSizeToWrite());
282 // Change in total size.
283 EXPECT_EQ(static_cast<int>(kData2.size()), buffer->total_size());
284 // First data to write has changed to kData2.
285 EXPECT_EQ(kData2, std::string_view(buffer->data(), buffer->GetSizeToWrite()));
286
287 // Consume second data fully.
288 buffer->DidConsume(kData2.size());
289 EXPECT_TRUE(buffer->IsEmpty());
290 EXPECT_EQ(0, buffer->GetSizeToWrite());
291 EXPECT_EQ(0, buffer->total_size());
292 }
293
TEST(HttpConnectionTest,QueuedWriteIOBuffer_TotalSizeLimit)294 TEST(HttpConnectionTest, QueuedWriteIOBuffer_TotalSizeLimit) {
295 scoped_refptr<HttpConnection::QueuedWriteIOBuffer> buffer =
296 base::MakeRefCounted<HttpConnection::QueuedWriteIOBuffer>();
297 EXPECT_EQ(HttpConnection::QueuedWriteIOBuffer::kDefaultMaxBufferSize + 0,
298 buffer->max_buffer_size());
299
300 // Set total size limit very small.
301 buffer->set_max_buffer_size(10);
302
303 const int kDataLength = 4;
304 const std::string kData(kDataLength, 'd');
305 EXPECT_TRUE(buffer->Append(kData));
306 EXPECT_EQ(kDataLength, buffer->total_size());
307 EXPECT_TRUE(buffer->Append(kData));
308 EXPECT_EQ(kDataLength * 2, buffer->total_size());
309
310 // Cannot append more data because it exceeds the limit.
311 EXPECT_FALSE(buffer->Append(kData));
312 EXPECT_EQ(kDataLength * 2, buffer->total_size());
313
314 // Consume data partially.
315 const int kConsumedLength = 2;
316 buffer->DidConsume(kConsumedLength);
317 EXPECT_EQ(kDataLength * 2 - kConsumedLength, buffer->total_size());
318
319 // Can add more data.
320 EXPECT_TRUE(buffer->Append(kData));
321 EXPECT_EQ(kDataLength * 3 - kConsumedLength, buffer->total_size());
322
323 // Cannot append more data because it exceeds the limit.
324 EXPECT_FALSE(buffer->Append(kData));
325 EXPECT_EQ(kDataLength * 3 - kConsumedLength, buffer->total_size());
326
327 // Enlarge limit.
328 buffer->set_max_buffer_size(20);
329 // Can add more data.
330 EXPECT_TRUE(buffer->Append(kData));
331 EXPECT_EQ(kDataLength * 4 - kConsumedLength, buffer->total_size());
332 }
333
TEST(HttpConnectionTest,QueuedWriteIOBuffer_DataPointerStability)334 TEST(HttpConnectionTest, QueuedWriteIOBuffer_DataPointerStability) {
335 // This is a regression test that makes sure that QueuedWriteIOBuffer deals
336 // with base::queue's semantics differences vs. std::queue right, and still
337 // makes sure our data() pointers are stable.
338 scoped_refptr<HttpConnection::QueuedWriteIOBuffer> buffer =
339 base::MakeRefCounted<HttpConnection::QueuedWriteIOBuffer>();
340
341 // We append a short string to make it fit within any short string
342 // optimization, so that if the underlying queue moves the std::string,
343 // the data should change.
344 buffer->Append("abcdefgh");
345
346 // Read part of it, to make sure this handles the case of data() pointing
347 // to something other than start of string right.
348 buffer->DidConsume(3);
349 const char* old_data = buffer->data();
350 EXPECT_EQ("defgh", std::string_view(buffer->data(), 5));
351
352 // Now append a whole bunch of other things to make the underlying queue
353 // grow, and likely need to move stuff around in memory.
354 for (int i = 0; i < 256; ++i)
355 buffer->Append("some other string data");
356
357 // data() should still be right.
358 EXPECT_EQ("defgh", std::string_view(buffer->data(), 5));
359
360 // ... it should also be bitwise the same, since the IOBuffer can get passed
361 // to async calls and then have Append's come in.
362 EXPECT_TRUE(buffer->data() == old_data);
363 }
364
365 } // namespace
366 } // namespace net
367