1 // Copyright 2013 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.
5 #include "content/browser/loader/upload_data_stream_builder.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/run_loop.h"
13 #include "base/thread_task_runner_handle.h"
14 #include "base/time/time.h"
15 #include "content/common/resource_request_body.h"
16 #include "net/base/io_buffer.h"
17 #include "net/base/net_errors.h"
18 #include "net/base/test_completion_callback.h"
19 #include "net/base/upload_bytes_element_reader.h"
20 #include "net/base/upload_data_stream.h"
21 #include "net/base/upload_file_element_reader.h"
22 #include "storage/browser/blob/blob_data_builder.h"
23 #include "storage/browser/blob/blob_storage_context.h"
24 #include "testing/gtest/include/gtest/gtest.h"
27 using storage::BlobDataBuilder
;
28 using storage::BlobDataHandle
;
29 using storage::BlobStorageContext
;
34 bool AreElementsEqual(const net::UploadElementReader
& reader
,
35 const ResourceRequestBody::Element
& element
) {
36 switch(element
.type()) {
37 case ResourceRequestBody::Element::TYPE_BYTES
: {
38 const net::UploadBytesElementReader
* bytes_reader
=
39 reader
.AsBytesReader();
40 return bytes_reader
&&
41 element
.length() == bytes_reader
->length() &&
42 std::equal(element
.bytes(), element
.bytes() + element
.length(),
43 bytes_reader
->bytes());
45 case ResourceRequestBody::Element::TYPE_FILE
: {
46 const net::UploadFileElementReader
* file_reader
= reader
.AsFileReader();
48 file_reader
->path() == element
.path() &&
49 file_reader
->range_offset() == element
.offset() &&
50 file_reader
->range_length() == element
.length() &&
51 file_reader
->expected_modification_time() ==
52 element
.expected_modification_time();
63 TEST(UploadDataStreamBuilderTest
, CreateUploadDataStreamWithoutBlob
) {
64 base::MessageLoop message_loop
;
65 scoped_refptr
<ResourceRequestBody
> request_body
= new ResourceRequestBody
;
67 const char kData
[] = "123";
68 const base::FilePath::StringType kFilePath
= FILE_PATH_LITERAL("abc");
69 const uint64 kFileOffset
= 10U;
70 const uint64 kFileLength
= 100U;
71 const base::Time kFileTime
= base::Time::FromDoubleT(999);
72 const int64 kIdentifier
= 12345;
74 request_body
->AppendBytes(kData
, arraysize(kData
) - 1);
75 request_body
->AppendFileRange(base::FilePath(kFilePath
),
76 kFileOffset
, kFileLength
, kFileTime
);
77 request_body
->set_identifier(kIdentifier
);
79 scoped_ptr
<net::UploadDataStream
> upload(UploadDataStreamBuilder::Build(
80 request_body
.get(), NULL
, NULL
,
81 base::ThreadTaskRunnerHandle::Get().get()));
83 EXPECT_EQ(kIdentifier
, upload
->identifier());
84 ASSERT_TRUE(upload
->GetElementReaders());
85 ASSERT_EQ(request_body
->elements()->size(),
86 upload
->GetElementReaders()->size());
88 const net::UploadBytesElementReader
* r1
=
89 (*upload
->GetElementReaders())[0]->AsBytesReader();
91 EXPECT_EQ(kData
, std::string(r1
->bytes(), r1
->length()));
93 const net::UploadFileElementReader
* r2
=
94 (*upload
->GetElementReaders())[1]->AsFileReader();
96 EXPECT_EQ(kFilePath
, r2
->path().value());
97 EXPECT_EQ(kFileOffset
, r2
->range_offset());
98 EXPECT_EQ(kFileLength
, r2
->range_length());
99 EXPECT_EQ(kFileTime
, r2
->expected_modification_time());
102 TEST(UploadDataStreamBuilderTest
, ResolveBlobAndCreateUploadDataStream
) {
103 base::MessageLoop message_loop
;
105 // Setup blob data for testing.
106 base::Time time1
, time2
;
107 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1
);
108 base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2
);
110 BlobStorageContext blob_storage_context
;
112 const std::string
blob_id0("id-0");
113 scoped_ptr
<BlobDataBuilder
> blob_data_builder(
114 new BlobDataBuilder(blob_id0
));
115 scoped_ptr
<BlobDataHandle
> handle1
=
116 blob_storage_context
.AddFinishedBlob(blob_data_builder
.get());
118 const std::string
blob_id1("id-1");
119 const std::string kBlobData
= "BlobData";
120 blob_data_builder
.reset(new BlobDataBuilder(blob_id1
));
121 blob_data_builder
->AppendData(kBlobData
);
122 blob_data_builder
->AppendFile(
123 base::FilePath(FILE_PATH_LITERAL("BlobFile.txt")), 0, 20, time1
);
124 scoped_ptr
<BlobDataHandle
> handle2
=
125 blob_storage_context
.AddFinishedBlob(blob_data_builder
.get());
127 // Setup upload data elements for comparison.
128 ResourceRequestBody::Element blob_element1
, blob_element2
;
129 blob_element1
.SetToBytes(kBlobData
.c_str(), kBlobData
.size());
130 blob_element2
.SetToFilePathRange(
131 base::FilePath(FILE_PATH_LITERAL("BlobFile.txt")), 0, 20, time1
);
133 ResourceRequestBody::Element upload_element1
, upload_element2
;
134 upload_element1
.SetToBytes("Hello", 5);
135 upload_element2
.SetToFilePathRange(
136 base::FilePath(FILE_PATH_LITERAL("foo1.txt")), 0, 20, time2
);
138 // Test no blob reference.
139 scoped_refptr
<ResourceRequestBody
> request_body(new ResourceRequestBody());
140 request_body
->AppendBytes(
141 upload_element1
.bytes(),
142 upload_element1
.length());
143 request_body
->AppendFileRange(
144 upload_element2
.path(),
145 upload_element2
.offset(),
146 upload_element2
.length(),
147 upload_element2
.expected_modification_time());
149 scoped_ptr
<net::UploadDataStream
> upload(UploadDataStreamBuilder::Build(
150 request_body
.get(), &blob_storage_context
, NULL
,
151 base::ThreadTaskRunnerHandle::Get().get()));
153 ASSERT_TRUE(upload
->GetElementReaders());
154 ASSERT_EQ(2U, upload
->GetElementReaders()->size());
155 EXPECT_TRUE(AreElementsEqual(
156 *(*upload
->GetElementReaders())[0], upload_element1
));
157 EXPECT_TRUE(AreElementsEqual(
158 *(*upload
->GetElementReaders())[1], upload_element2
));
160 // Test having only one blob reference that refers to empty blob data.
161 request_body
= new ResourceRequestBody();
162 request_body
->AppendBlob(blob_id0
);
164 upload
= UploadDataStreamBuilder::Build(
165 request_body
.get(), &blob_storage_context
, NULL
,
166 base::ThreadTaskRunnerHandle::Get().get());
167 ASSERT_TRUE(upload
->GetElementReaders());
168 ASSERT_EQ(0U, upload
->GetElementReaders()->size());
170 // Test having only one blob reference.
171 request_body
= new ResourceRequestBody();
172 request_body
->AppendBlob(blob_id1
);
174 upload
= UploadDataStreamBuilder::Build(
175 request_body
.get(), &blob_storage_context
, NULL
,
176 base::ThreadTaskRunnerHandle::Get().get());
177 ASSERT_TRUE(upload
->GetElementReaders());
178 ASSERT_EQ(2U, upload
->GetElementReaders()->size());
179 EXPECT_TRUE(AreElementsEqual(
180 *(*upload
->GetElementReaders())[0], blob_element1
));
181 EXPECT_TRUE(AreElementsEqual(
182 *(*upload
->GetElementReaders())[1], blob_element2
));
184 // Test having one blob reference at the beginning.
185 request_body
= new ResourceRequestBody();
186 request_body
->AppendBlob(blob_id1
);
187 request_body
->AppendBytes(
188 upload_element1
.bytes(),
189 upload_element1
.length());
190 request_body
->AppendFileRange(
191 upload_element2
.path(),
192 upload_element2
.offset(),
193 upload_element2
.length(),
194 upload_element2
.expected_modification_time());
196 upload
= UploadDataStreamBuilder::Build(
197 request_body
.get(), &blob_storage_context
, NULL
,
198 base::ThreadTaskRunnerHandle::Get().get());
199 ASSERT_TRUE(upload
->GetElementReaders());
200 ASSERT_EQ(4U, upload
->GetElementReaders()->size());
201 EXPECT_TRUE(AreElementsEqual(
202 *(*upload
->GetElementReaders())[0], blob_element1
));
203 EXPECT_TRUE(AreElementsEqual(
204 *(*upload
->GetElementReaders())[1], blob_element2
));
205 EXPECT_TRUE(AreElementsEqual(
206 *(*upload
->GetElementReaders())[2], upload_element1
));
207 EXPECT_TRUE(AreElementsEqual(
208 *(*upload
->GetElementReaders())[3], upload_element2
));
210 // Test having one blob reference at the end.
211 request_body
= new ResourceRequestBody();
212 request_body
->AppendBytes(
213 upload_element1
.bytes(),
214 upload_element1
.length());
215 request_body
->AppendFileRange(
216 upload_element2
.path(),
217 upload_element2
.offset(),
218 upload_element2
.length(),
219 upload_element2
.expected_modification_time());
220 request_body
->AppendBlob(blob_id1
);
222 upload
= UploadDataStreamBuilder::Build(
223 request_body
.get(), &blob_storage_context
, NULL
,
224 base::ThreadTaskRunnerHandle::Get().get());
225 ASSERT_TRUE(upload
->GetElementReaders());
226 ASSERT_EQ(4U, upload
->GetElementReaders()->size());
227 EXPECT_TRUE(AreElementsEqual(
228 *(*upload
->GetElementReaders())[0], upload_element1
));
229 EXPECT_TRUE(AreElementsEqual(
230 *(*upload
->GetElementReaders())[1], upload_element2
));
231 EXPECT_TRUE(AreElementsEqual(
232 *(*upload
->GetElementReaders())[2], blob_element1
));
233 EXPECT_TRUE(AreElementsEqual(
234 *(*upload
->GetElementReaders())[3], blob_element2
));
236 // Test having one blob reference in the middle.
237 request_body
= new ResourceRequestBody();
238 request_body
->AppendBytes(
239 upload_element1
.bytes(),
240 upload_element1
.length());
241 request_body
->AppendBlob(blob_id1
);
242 request_body
->AppendFileRange(
243 upload_element2
.path(),
244 upload_element2
.offset(),
245 upload_element2
.length(),
246 upload_element2
.expected_modification_time());
248 upload
= UploadDataStreamBuilder::Build(
249 request_body
.get(), &blob_storage_context
, NULL
,
250 base::ThreadTaskRunnerHandle::Get().get());
251 ASSERT_TRUE(upload
->GetElementReaders());
252 ASSERT_EQ(4U, upload
->GetElementReaders()->size());
253 EXPECT_TRUE(AreElementsEqual(
254 *(*upload
->GetElementReaders())[0], upload_element1
));
255 EXPECT_TRUE(AreElementsEqual(
256 *(*upload
->GetElementReaders())[1], blob_element1
));
257 EXPECT_TRUE(AreElementsEqual(
258 *(*upload
->GetElementReaders())[2], blob_element2
));
259 EXPECT_TRUE(AreElementsEqual(
260 *(*upload
->GetElementReaders())[3], upload_element2
));
262 // Test having multiple blob references.
263 request_body
= new ResourceRequestBody();
264 request_body
->AppendBlob(blob_id1
);
265 request_body
->AppendBytes(
266 upload_element1
.bytes(),
267 upload_element1
.length());
268 request_body
->AppendBlob(blob_id1
);
269 request_body
->AppendBlob(blob_id1
);
270 request_body
->AppendFileRange(
271 upload_element2
.path(),
272 upload_element2
.offset(),
273 upload_element2
.length(),
274 upload_element2
.expected_modification_time());
276 upload
= UploadDataStreamBuilder::Build(
277 request_body
.get(), &blob_storage_context
, NULL
,
278 base::ThreadTaskRunnerHandle::Get().get());
279 ASSERT_TRUE(upload
->GetElementReaders());
280 ASSERT_EQ(8U, upload
->GetElementReaders()->size());
281 EXPECT_TRUE(AreElementsEqual(
282 *(*upload
->GetElementReaders())[0], blob_element1
));
283 EXPECT_TRUE(AreElementsEqual(
284 *(*upload
->GetElementReaders())[1], blob_element2
));
285 EXPECT_TRUE(AreElementsEqual(
286 *(*upload
->GetElementReaders())[2], upload_element1
));
287 EXPECT_TRUE(AreElementsEqual(
288 *(*upload
->GetElementReaders())[3], blob_element1
));
289 EXPECT_TRUE(AreElementsEqual(
290 *(*upload
->GetElementReaders())[4], blob_element2
));
291 EXPECT_TRUE(AreElementsEqual(
292 *(*upload
->GetElementReaders())[5], blob_element1
));
293 EXPECT_TRUE(AreElementsEqual(
294 *(*upload
->GetElementReaders())[6], blob_element2
));
295 EXPECT_TRUE(AreElementsEqual(
296 *(*upload
->GetElementReaders())[7], upload_element2
));
298 // Clean up for ASAN.
299 base::RunLoop().RunUntilIdle();
302 TEST(UploadDataStreamBuilderTest
,
303 WriteUploadDataStreamWithEmptyFileBackedBlob
) {
304 base::MessageLoopForIO message_loop
;
306 base::FilePath test_blob_path
;
307 ASSERT_TRUE(base::CreateTemporaryFile(&test_blob_path
));
309 const uint64_t kZeroLength
= 0;
310 base::Time blob_time
;
311 base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &blob_time
);
312 ASSERT_TRUE(base::TouchFile(test_blob_path
, blob_time
, blob_time
));
314 BlobStorageContext blob_storage_context
;
316 // A blob created from an empty file added several times.
317 const std::string
blob_id("id-0");
318 scoped_ptr
<BlobDataBuilder
> blob_data_builder(new BlobDataBuilder(blob_id
));
319 blob_data_builder
->AppendFile(test_blob_path
, 0, kZeroLength
, blob_time
);
320 scoped_ptr
<BlobDataHandle
> handle
=
321 blob_storage_context
.AddFinishedBlob(blob_data_builder
.get());
323 ResourceRequestBody::Element blob_element
;
324 blob_element
.SetToFilePathRange(test_blob_path
, 0, kZeroLength
, blob_time
);
326 scoped_refptr
<ResourceRequestBody
> request_body(new ResourceRequestBody());
327 scoped_ptr
<net::UploadDataStream
> upload(UploadDataStreamBuilder::Build(
328 request_body
.get(), &blob_storage_context
, NULL
,
329 base::ThreadTaskRunnerHandle::Get().get()));
331 request_body
= new ResourceRequestBody();
332 request_body
->AppendBlob(blob_id
);
333 request_body
->AppendBlob(blob_id
);
334 request_body
->AppendBlob(blob_id
);
336 upload
= UploadDataStreamBuilder::Build(
337 request_body
.get(), &blob_storage_context
, NULL
,
338 base::ThreadTaskRunnerHandle::Get().get());
339 ASSERT_TRUE(upload
->GetElementReaders());
340 const auto& readers
= *upload
->GetElementReaders();
341 ASSERT_EQ(3U, readers
.size());
342 EXPECT_TRUE(AreElementsEqual(*readers
[0], blob_element
));
343 EXPECT_TRUE(AreElementsEqual(*readers
[1], blob_element
));
344 EXPECT_TRUE(AreElementsEqual(*readers
[2], blob_element
));
346 net::TestCompletionCallback init_callback
;
347 ASSERT_EQ(net::ERR_IO_PENDING
, upload
->Init(init_callback
.callback()));
348 EXPECT_EQ(net::OK
, init_callback
.WaitForResult());
350 EXPECT_EQ(kZeroLength
, upload
->size());
352 // Purposely (try to) read more than what is in the stream. If we try to
353 // read zero bytes then UploadDataStream::Read will fail a DCHECK.
354 int kBufferLength
= kZeroLength
+ 1;
355 scoped_ptr
<char[]> buffer(new char[kBufferLength
]);
356 scoped_refptr
<net::IOBuffer
> io_buffer
=
357 new net::WrappedIOBuffer(buffer
.get());
358 net::TestCompletionCallback read_callback
;
360 upload
->Read(io_buffer
.get(), kBufferLength
, read_callback
.callback());
361 EXPECT_EQ(static_cast<int>(kZeroLength
), read_callback
.GetResult(result
));
363 base::DeleteFile(test_blob_path
, false);
365 // Clean up for ASAN.
366 base::RunLoop().RunUntilIdle();
368 } // namespace content