1 // Copyright 2014 The Chromium Authors. All rights reserved.
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 "net/base/chunked_upload_data_stream.h"
6
7 #include <memory>
8 #include <string>
9
10 #include "base/stl_util.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13 #include "net/base/test_completion_callback.h"
14 #include "net/base/upload_data_stream.h"
15 #include "net/log/net_log_with_source.h"
16 #include "net/test/gtest_util.h"
17 #include "testing/gmock/include/gmock/gmock.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19
20 using net::test::IsError;
21 using net::test::IsOk;
22
23 namespace net {
24
25 namespace {
26
27 constexpr char kTestData[] = "0123456789";
28 constexpr size_t kTestDataSize = base::size(kTestData) - 1;
29 constexpr size_t kTestBufferSize = 1 << 14; // 16KB.
30
31 } // namespace
32
33 // Reads data once from the upload data stream, and returns the data as string.
34 // Expects the read to succeed synchronously.
ReadSync(UploadDataStream * stream,int buffer_size)35 std::string ReadSync(UploadDataStream* stream, int buffer_size) {
36 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(buffer_size);
37 int result = stream->Read(buf.get(),
38 buffer_size,
39 TestCompletionCallback().callback());
40 EXPECT_GE(result, 0);
41 return std::string(buf->data(), result);
42 }
43
44 // Check the case data is added after the first read attempt.
TEST(ChunkedUploadDataStreamTest,AppendOnce)45 TEST(ChunkedUploadDataStreamTest, AppendOnce) {
46 ChunkedUploadDataStream stream(0);
47
48 ASSERT_THAT(
49 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
50 IsOk());
51 EXPECT_FALSE(stream.IsInMemory());
52 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
53 EXPECT_EQ(0u, stream.position());
54 EXPECT_FALSE(stream.IsEOF());
55
56 TestCompletionCallback callback;
57 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kTestBufferSize);
58 int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
59 ASSERT_THAT(result, IsError(ERR_IO_PENDING));
60
61 stream.AppendData(kTestData, kTestDataSize, true);
62 int read = callback.WaitForResult();
63 ASSERT_GE(read, 0);
64 EXPECT_EQ(kTestData, std::string(buf->data(), read));
65 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
66 EXPECT_EQ(kTestDataSize, stream.position());
67 EXPECT_TRUE(stream.IsEOF());
68 }
69
TEST(ChunkedUploadDataStreamTest,AppendOnceBeforeRead)70 TEST(ChunkedUploadDataStreamTest, AppendOnceBeforeRead) {
71 ChunkedUploadDataStream stream(0);
72
73 ASSERT_THAT(
74 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
75 IsOk());
76 EXPECT_FALSE(stream.IsInMemory());
77 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
78 EXPECT_EQ(0u, stream.position());
79 EXPECT_FALSE(stream.IsEOF());
80
81 stream.AppendData(kTestData, kTestDataSize, true);
82 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
83 EXPECT_EQ(0u, stream.position());
84 EXPECT_FALSE(stream.IsEOF());
85
86 std::string data = ReadSync(&stream, kTestBufferSize);
87 EXPECT_EQ(kTestData, data);
88 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
89 EXPECT_EQ(kTestDataSize, stream.position());
90 EXPECT_TRUE(stream.IsEOF());
91 }
92
TEST(ChunkedUploadDataStreamTest,AppendOnceBeforeInit)93 TEST(ChunkedUploadDataStreamTest, AppendOnceBeforeInit) {
94 ChunkedUploadDataStream stream(0);
95
96 stream.AppendData(kTestData, kTestDataSize, true);
97 ASSERT_THAT(
98 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
99 IsOk());
100 EXPECT_FALSE(stream.IsInMemory());
101 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
102 EXPECT_EQ(0u, stream.position());
103 EXPECT_FALSE(stream.IsEOF());
104
105 std::string data = ReadSync(&stream, kTestBufferSize);
106 EXPECT_EQ(kTestData, data);
107 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
108 EXPECT_EQ(kTestDataSize, stream.position());
109 EXPECT_TRUE(stream.IsEOF());
110 }
111
TEST(ChunkedUploadDataStreamTest,MultipleAppends)112 TEST(ChunkedUploadDataStreamTest, MultipleAppends) {
113 ChunkedUploadDataStream stream(0);
114
115 ASSERT_THAT(
116 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
117 IsOk());
118 EXPECT_FALSE(stream.IsInMemory());
119 EXPECT_EQ(0u, stream.size());
120 EXPECT_EQ(0u, stream.position());
121 EXPECT_FALSE(stream.IsEOF());
122
123 TestCompletionCallback callback;
124 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kTestBufferSize);
125 for (size_t i = 0; i < kTestDataSize; ++i) {
126 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
127 EXPECT_EQ(i, stream.position());
128 ASSERT_FALSE(stream.IsEOF());
129 int bytes_read = stream.Read(buf.get(),
130 kTestBufferSize,
131 callback.callback());
132 ASSERT_THAT(bytes_read, IsError(ERR_IO_PENDING));
133 stream.AppendData(&kTestData[i], 1, i == kTestDataSize - 1);
134 ASSERT_EQ(1, callback.WaitForResult());
135 EXPECT_EQ(kTestData[i], buf->data()[0]);
136 }
137
138 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
139 EXPECT_EQ(kTestDataSize, stream.position());
140 ASSERT_TRUE(stream.IsEOF());
141 }
142
TEST(ChunkedUploadDataStreamTest,MultipleAppendsBetweenReads)143 TEST(ChunkedUploadDataStreamTest, MultipleAppendsBetweenReads) {
144 ChunkedUploadDataStream stream(0);
145
146 ASSERT_THAT(
147 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
148 IsOk());
149 EXPECT_FALSE(stream.IsInMemory());
150 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
151 EXPECT_EQ(0u, stream.position());
152 EXPECT_FALSE(stream.IsEOF());
153
154 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kTestBufferSize);
155 for (size_t i = 0; i < kTestDataSize; ++i) {
156 EXPECT_EQ(i, stream.position());
157 ASSERT_FALSE(stream.IsEOF());
158 stream.AppendData(&kTestData[i], 1, i == kTestDataSize - 1);
159 int bytes_read = stream.Read(buf.get(),
160 kTestBufferSize,
161 TestCompletionCallback().callback());
162 ASSERT_EQ(1, bytes_read);
163 EXPECT_EQ(kTestData[i], buf->data()[0]);
164 }
165
166 EXPECT_EQ(kTestDataSize, stream.position());
167 ASSERT_TRUE(stream.IsEOF());
168 }
169
170 // Checks that multiple reads can be merged.
TEST(ChunkedUploadDataStreamTest,MultipleAppendsBeforeInit)171 TEST(ChunkedUploadDataStreamTest, MultipleAppendsBeforeInit) {
172 ChunkedUploadDataStream stream(0);
173 stream.AppendData(kTestData, 1, false);
174 stream.AppendData(kTestData + 1, 1, false);
175 stream.AppendData(kTestData + 2, kTestDataSize - 2, true);
176
177 ASSERT_THAT(
178 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
179 IsOk());
180 EXPECT_FALSE(stream.IsInMemory());
181 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
182 EXPECT_EQ(0u, stream.position());
183 EXPECT_FALSE(stream.IsEOF());
184
185 std::string data = ReadSync(&stream, kTestBufferSize);
186 EXPECT_EQ(kTestData, data);
187 EXPECT_EQ(kTestDataSize, stream.position());
188 ASSERT_TRUE(stream.IsEOF());
189 }
190
TEST(ChunkedUploadDataStreamTest,MultipleReads)191 TEST(ChunkedUploadDataStreamTest, MultipleReads) {
192 // Use a read size different from the write size to test bounds checking.
193 const size_t kReadSize = kTestDataSize + 3;
194
195 ChunkedUploadDataStream stream(0);
196 stream.AppendData(kTestData, kTestDataSize, false);
197 stream.AppendData(kTestData, kTestDataSize, false);
198 stream.AppendData(kTestData, kTestDataSize, false);
199 stream.AppendData(kTestData, kTestDataSize, true);
200
201 ASSERT_THAT(
202 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
203 IsOk());
204 EXPECT_FALSE(stream.IsInMemory());
205 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
206 EXPECT_EQ(0u, stream.position());
207 EXPECT_FALSE(stream.IsEOF());
208
209 std::string data = ReadSync(&stream, kReadSize);
210 EXPECT_EQ("0123456789012", data);
211 EXPECT_EQ(kReadSize, stream.position());
212 EXPECT_FALSE(stream.IsEOF());
213
214 data = ReadSync(&stream, kReadSize);
215 EXPECT_EQ("3456789012345", data);
216 EXPECT_EQ(2 * kReadSize, stream.position());
217 EXPECT_FALSE(stream.IsEOF());
218
219 data = ReadSync(&stream, kReadSize);
220 EXPECT_EQ("6789012345678", data);
221 EXPECT_EQ(3 * kReadSize, stream.position());
222 EXPECT_FALSE(stream.IsEOF());
223
224 data = ReadSync(&stream, kReadSize);
225 EXPECT_EQ("9", data);
226 EXPECT_EQ(4 * kTestDataSize, stream.position());
227 EXPECT_TRUE(stream.IsEOF());
228 }
229
TEST(ChunkedUploadDataStreamTest,EmptyUpload)230 TEST(ChunkedUploadDataStreamTest, EmptyUpload) {
231 ChunkedUploadDataStream stream(0);
232
233 ASSERT_THAT(
234 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
235 IsOk());
236 EXPECT_FALSE(stream.IsInMemory());
237 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
238 EXPECT_EQ(0u, stream.position());
239 EXPECT_FALSE(stream.IsEOF());
240
241 TestCompletionCallback callback;
242 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kTestBufferSize);
243 int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
244 ASSERT_THAT(result, IsError(ERR_IO_PENDING));
245
246 stream.AppendData(nullptr, 0, true);
247 int read = callback.WaitForResult();
248 EXPECT_EQ(0, read);
249 EXPECT_EQ(0u, stream.position());
250 EXPECT_TRUE(stream.IsEOF());
251 }
252
TEST(ChunkedUploadDataStreamTest,EmptyUploadEndedBeforeInit)253 TEST(ChunkedUploadDataStreamTest, EmptyUploadEndedBeforeInit) {
254 ChunkedUploadDataStream stream(0);
255 stream.AppendData(nullptr, 0, true);
256
257 ASSERT_THAT(
258 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
259 IsOk());
260 EXPECT_FALSE(stream.IsInMemory());
261 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
262 EXPECT_EQ(0u, stream.position());
263 EXPECT_FALSE(stream.IsEOF());
264
265 std::string data = ReadSync(&stream, kTestBufferSize);
266 ASSERT_EQ("", data);
267 EXPECT_EQ(0u, stream.position());
268 EXPECT_TRUE(stream.IsEOF());
269 }
270
TEST(ChunkedUploadDataStreamTest,RewindAfterComplete)271 TEST(ChunkedUploadDataStreamTest, RewindAfterComplete) {
272 ChunkedUploadDataStream stream(0);
273 stream.AppendData(kTestData, 1, false);
274 stream.AppendData(kTestData + 1, kTestDataSize - 1, true);
275
276 ASSERT_THAT(
277 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
278 IsOk());
279 EXPECT_FALSE(stream.IsInMemory());
280 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
281 EXPECT_EQ(0u, stream.position());
282 EXPECT_FALSE(stream.IsEOF());
283
284 std::string data = ReadSync(&stream, kTestBufferSize);
285 EXPECT_EQ(kTestData, data);
286 EXPECT_EQ(kTestDataSize, stream.position());
287 ASSERT_TRUE(stream.IsEOF());
288
289 // Rewind stream and repeat.
290 ASSERT_THAT(
291 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
292 IsOk());
293 EXPECT_FALSE(stream.IsInMemory());
294 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
295 EXPECT_EQ(0u, stream.position());
296 EXPECT_FALSE(stream.IsEOF());
297
298 data = ReadSync(&stream, kTestBufferSize);
299 EXPECT_EQ(kTestData, data);
300 EXPECT_EQ(kTestDataSize, stream.position());
301 ASSERT_TRUE(stream.IsEOF());
302 }
303
TEST(ChunkedUploadDataStreamTest,RewindWhileReading)304 TEST(ChunkedUploadDataStreamTest, RewindWhileReading) {
305 ChunkedUploadDataStream stream(0);
306
307 ASSERT_THAT(
308 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
309 IsOk());
310 EXPECT_FALSE(stream.IsInMemory());
311 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
312 EXPECT_EQ(0u, stream.position());
313 EXPECT_FALSE(stream.IsEOF());
314
315 TestCompletionCallback callback;
316 scoped_refptr<IOBuffer> buf = base::MakeRefCounted<IOBuffer>(kTestBufferSize);
317 int result = stream.Read(buf.get(), kTestBufferSize, callback.callback());
318 ASSERT_THAT(result, IsError(ERR_IO_PENDING));
319
320 ASSERT_THAT(
321 stream.Init(TestCompletionCallback().callback(), NetLogWithSource()),
322 IsOk());
323 EXPECT_FALSE(stream.IsInMemory());
324 EXPECT_EQ(0u, stream.size()); // Content-Length is 0 for chunked data.
325 EXPECT_EQ(0u, stream.position());
326 EXPECT_FALSE(stream.IsEOF());
327
328 // Adding data now should not result in calling the original read callback,
329 // since the stream was re-initialized for reuse, which cancels all pending
330 // reads.
331 stream.AppendData(kTestData, kTestDataSize, true);
332 EXPECT_FALSE(callback.have_result());
333
334 std::string data = ReadSync(&stream, kTestBufferSize);
335 EXPECT_EQ(kTestData, data);
336 EXPECT_EQ(kTestDataSize, stream.position());
337 ASSERT_TRUE(stream.IsEOF());
338 EXPECT_FALSE(callback.have_result());
339 }
340
341 // Check the behavior of ChunkedUploadDataStream::Writer.
TEST(ChunkedUploadDataStreamTest,ChunkedUploadDataStreamWriter)342 TEST(ChunkedUploadDataStreamTest, ChunkedUploadDataStreamWriter) {
343 std::unique_ptr<ChunkedUploadDataStream> stream(
344 new ChunkedUploadDataStream(0));
345 std::unique_ptr<ChunkedUploadDataStream::Writer> writer(
346 stream->CreateWriter());
347
348 // Write before Init.
349 ASSERT_TRUE(writer->AppendData(kTestData, 1, false));
350 ASSERT_THAT(
351 stream->Init(TestCompletionCallback().callback(), NetLogWithSource()),
352 IsOk());
353
354 // Write after Init.
355 ASSERT_TRUE(writer->AppendData(kTestData + 1, kTestDataSize - 1, false));
356
357 TestCompletionCallback callback;
358 std::string data = ReadSync(stream.get(), kTestBufferSize);
359 EXPECT_EQ(kTestData, data);
360
361 // Writing data should gracefully fail if the stream is deleted while still
362 // appending data to it.
363 stream.reset();
364 EXPECT_FALSE(writer->AppendData(kTestData, kTestDataSize, true));
365 }
366
367 } // namespace net
368