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.
4
5#include "content/browser/loader/upload_data_stream_builder.h"
6
7#include <algorithm>
8
9#include "base/files/file_path.h"
10#include "base/files/file_util.h"
11#include "base/message_loop/message_loop.h"
12#include "base/message_loop/message_loop_proxy.h"
13#include "base/run_loop.h"
14#include "base/time/time.h"
15#include "content/common/resource_request_body.h"
16#include "net/base/upload_bytes_element_reader.h"
17#include "net/base/upload_data_stream.h"
18#include "net/base/upload_file_element_reader.h"
19#include "storage/browser/blob/blob_storage_context.h"
20#include "testing/gtest/include/gtest/gtest.h"
21#include "url/gurl.h"
22
23using storage::BlobData;
24using storage::BlobDataHandle;
25using storage::BlobStorageContext;
26
27namespace content {
28namespace {
29
30bool AreElementsEqual(const net::UploadElementReader& reader,
31                      const ResourceRequestBody::Element& element) {
32  switch(element.type()) {
33    case ResourceRequestBody::Element::TYPE_BYTES: {
34      const net::UploadBytesElementReader* bytes_reader =
35          reader.AsBytesReader();
36      return bytes_reader &&
37          element.length() == bytes_reader->length() &&
38          std::equal(element.bytes(), element.bytes() + element.length(),
39                     bytes_reader->bytes());
40    }
41    case ResourceRequestBody::Element::TYPE_FILE: {
42      const net::UploadFileElementReader* file_reader = reader.AsFileReader();
43      return file_reader &&
44          file_reader->path() == element.path() &&
45          file_reader->range_offset() == element.offset() &&
46          file_reader->range_length() == element.length() &&
47          file_reader->expected_modification_time() ==
48          element.expected_modification_time();
49      break;
50    }
51    default:
52      NOTREACHED();
53  }
54  return false;
55}
56
57}  // namespace
58
59TEST(UploadDataStreamBuilderTest, CreateUploadDataStreamWithoutBlob) {
60  base::MessageLoop message_loop;
61  scoped_refptr<ResourceRequestBody> request_body = new ResourceRequestBody;
62
63  const char kData[] = "123";
64  const base::FilePath::StringType kFilePath = FILE_PATH_LITERAL("abc");
65  const uint64 kFileOffset = 10U;
66  const uint64 kFileLength = 100U;
67  const base::Time kFileTime = base::Time::FromDoubleT(999);
68  const int64 kIdentifier = 12345;
69
70  request_body->AppendBytes(kData, arraysize(kData) - 1);
71  request_body->AppendFileRange(base::FilePath(kFilePath),
72                                kFileOffset, kFileLength, kFileTime);
73  request_body->set_identifier(kIdentifier);
74
75  scoped_ptr<net::UploadDataStream> upload(UploadDataStreamBuilder::Build(
76      request_body.get(), NULL, NULL, base::MessageLoopProxy::current().get()));
77
78  EXPECT_EQ(kIdentifier, upload->identifier());
79  ASSERT_EQ(request_body->elements()->size(), upload->element_readers().size());
80
81  const net::UploadBytesElementReader* r1 =
82      upload->element_readers()[0]->AsBytesReader();
83  ASSERT_TRUE(r1);
84  EXPECT_EQ(kData, std::string(r1->bytes(), r1->length()));
85
86  const net::UploadFileElementReader* r2 =
87      upload->element_readers()[1]->AsFileReader();
88  ASSERT_TRUE(r2);
89  EXPECT_EQ(kFilePath, r2->path().value());
90  EXPECT_EQ(kFileOffset, r2->range_offset());
91  EXPECT_EQ(kFileLength, r2->range_length());
92  EXPECT_EQ(kFileTime, r2->expected_modification_time());
93}
94
95TEST(UploadDataStreamBuilderTest, ResolveBlobAndCreateUploadDataStream) {
96  base::MessageLoop message_loop;
97  {
98    // Setup blob data for testing.
99    base::Time time1, time2;
100    base::Time::FromString("Tue, 15 Nov 1994, 12:45:26 GMT", &time1);
101    base::Time::FromString("Mon, 14 Nov 1994, 11:30:49 GMT", &time2);
102
103    BlobStorageContext blob_storage_context;
104
105    const std::string blob_id0("id-0");
106    scoped_refptr<BlobData> blob_data(new BlobData(blob_id0));
107    scoped_ptr<BlobDataHandle> handle1 =
108        blob_storage_context.AddFinishedBlob(blob_data.get());
109
110    const std::string blob_id1("id-1");
111    blob_data = new BlobData(blob_id1);
112    blob_data->AppendData("BlobData");
113    blob_data->AppendFile(
114        base::FilePath(FILE_PATH_LITERAL("BlobFile.txt")), 0, 20, time1);
115    scoped_ptr<BlobDataHandle> handle2 =
116        blob_storage_context.AddFinishedBlob(blob_data.get());
117
118    // Setup upload data elements for comparison.
119    ResourceRequestBody::Element blob_element1, blob_element2;
120    blob_element1.SetToBytes(
121        blob_data->items().at(0).bytes() +
122        static_cast<int>(blob_data->items().at(0).offset()),
123        static_cast<int>(blob_data->items().at(0).length()));
124    blob_element2.SetToFilePathRange(
125        blob_data->items().at(1).path(),
126        blob_data->items().at(1).offset(),
127        blob_data->items().at(1).length(),
128        blob_data->items().at(1).expected_modification_time());
129
130    ResourceRequestBody::Element upload_element1, upload_element2;
131    upload_element1.SetToBytes("Hello", 5);
132    upload_element2.SetToFilePathRange(
133        base::FilePath(FILE_PATH_LITERAL("foo1.txt")), 0, 20, time2);
134
135    // Test no blob reference.
136    scoped_refptr<ResourceRequestBody> request_body(new ResourceRequestBody());
137    request_body->AppendBytes(
138        upload_element1.bytes(),
139        upload_element1.length());
140    request_body->AppendFileRange(
141        upload_element2.path(),
142        upload_element2.offset(),
143        upload_element2.length(),
144        upload_element2.expected_modification_time());
145
146    scoped_ptr<net::UploadDataStream> upload(
147        UploadDataStreamBuilder::Build(
148            request_body.get(),
149            &blob_storage_context,
150            NULL,
151            base::MessageLoopProxy::current().get()));
152
153    ASSERT_EQ(2U, upload->element_readers().size());
154    EXPECT_TRUE(AreElementsEqual(
155        *upload->element_readers()[0], upload_element1));
156    EXPECT_TRUE(AreElementsEqual(
157        *upload->element_readers()[1], upload_element2));
158
159    // Test having only one blob reference that refers to empty blob data.
160    request_body = new ResourceRequestBody();
161    request_body->AppendBlob(blob_id0);
162
163    upload = UploadDataStreamBuilder::Build(
164        request_body.get(),
165        &blob_storage_context,
166        NULL,
167        base::MessageLoopProxy::current().get());
168    ASSERT_EQ(0U, upload->element_readers().size());
169
170    // Test having only one blob reference.
171    request_body = new ResourceRequestBody();
172    request_body->AppendBlob(blob_id1);
173
174    upload = UploadDataStreamBuilder::Build(
175        request_body.get(),
176        &blob_storage_context,
177        NULL,
178        base::MessageLoopProxy::current().get());
179    ASSERT_EQ(2U, upload->element_readers().size());
180    EXPECT_TRUE(AreElementsEqual(
181        *upload->element_readers()[0], blob_element1));
182    EXPECT_TRUE(AreElementsEqual(
183        *upload->element_readers()[1], blob_element2));
184
185    // Test having one blob reference at the beginning.
186    request_body = new ResourceRequestBody();
187    request_body->AppendBlob(blob_id1);
188    request_body->AppendBytes(
189        upload_element1.bytes(),
190        upload_element1.length());
191    request_body->AppendFileRange(
192        upload_element2.path(),
193        upload_element2.offset(),
194        upload_element2.length(),
195        upload_element2.expected_modification_time());
196
197    upload = UploadDataStreamBuilder::Build(
198        request_body.get(),
199        &blob_storage_context,
200        NULL,
201        base::MessageLoopProxy::current().get());
202    ASSERT_EQ(4U, upload->element_readers().size());
203    EXPECT_TRUE(AreElementsEqual(
204        *upload->element_readers()[0], blob_element1));
205    EXPECT_TRUE(AreElementsEqual(
206        *upload->element_readers()[1], blob_element2));
207    EXPECT_TRUE(AreElementsEqual(
208        *upload->element_readers()[2], upload_element1));
209    EXPECT_TRUE(AreElementsEqual(
210        *upload->element_readers()[3], upload_element2));
211
212    // Test having one blob reference at the end.
213    request_body = new ResourceRequestBody();
214    request_body->AppendBytes(
215        upload_element1.bytes(),
216        upload_element1.length());
217    request_body->AppendFileRange(
218        upload_element2.path(),
219        upload_element2.offset(),
220        upload_element2.length(),
221        upload_element2.expected_modification_time());
222    request_body->AppendBlob(blob_id1);
223
224    upload =
225        UploadDataStreamBuilder::Build(request_body.get(),
226                                       &blob_storage_context,
227                                       NULL,
228                                       base::MessageLoopProxy::current().get());
229    ASSERT_EQ(4U, upload->element_readers().size());
230    EXPECT_TRUE(AreElementsEqual(
231        *upload->element_readers()[0], upload_element1));
232    EXPECT_TRUE(AreElementsEqual(
233        *upload->element_readers()[1], upload_element2));
234    EXPECT_TRUE(AreElementsEqual(
235        *upload->element_readers()[2], blob_element1));
236    EXPECT_TRUE(AreElementsEqual(
237          *upload->element_readers()[3], blob_element2));
238
239    // Test having one blob reference in the middle.
240    request_body = new ResourceRequestBody();
241    request_body->AppendBytes(
242        upload_element1.bytes(),
243        upload_element1.length());
244    request_body->AppendBlob(blob_id1);
245    request_body->AppendFileRange(
246        upload_element2.path(),
247        upload_element2.offset(),
248        upload_element2.length(),
249        upload_element2.expected_modification_time());
250
251    upload = UploadDataStreamBuilder::Build(
252        request_body.get(),
253        &blob_storage_context,
254        NULL,
255        base::MessageLoopProxy::current().get());
256    ASSERT_EQ(4U, upload->element_readers().size());
257    EXPECT_TRUE(AreElementsEqual(
258        *upload->element_readers()[0], upload_element1));
259    EXPECT_TRUE(AreElementsEqual(
260        *upload->element_readers()[1], blob_element1));
261    EXPECT_TRUE(AreElementsEqual(
262        *upload->element_readers()[2], blob_element2));
263    EXPECT_TRUE(AreElementsEqual(
264        *upload->element_readers()[3], upload_element2));
265
266    // Test having multiple blob references.
267    request_body = new ResourceRequestBody();
268    request_body->AppendBlob(blob_id1);
269    request_body->AppendBytes(
270        upload_element1.bytes(),
271        upload_element1.length());
272    request_body->AppendBlob(blob_id1);
273    request_body->AppendBlob(blob_id1);
274    request_body->AppendFileRange(
275        upload_element2.path(),
276        upload_element2.offset(),
277        upload_element2.length(),
278        upload_element2.expected_modification_time());
279
280    upload = UploadDataStreamBuilder::Build(
281        request_body.get(),
282        &blob_storage_context,
283        NULL,
284        base::MessageLoopProxy::current().get());
285    ASSERT_EQ(8U, upload->element_readers().size());
286    EXPECT_TRUE(AreElementsEqual(
287        *upload->element_readers()[0], blob_element1));
288    EXPECT_TRUE(AreElementsEqual(
289        *upload->element_readers()[1], blob_element2));
290    EXPECT_TRUE(AreElementsEqual(
291        *upload->element_readers()[2], upload_element1));
292    EXPECT_TRUE(AreElementsEqual(
293        *upload->element_readers()[3], blob_element1));
294    EXPECT_TRUE(AreElementsEqual(
295        *upload->element_readers()[4], blob_element2));
296    EXPECT_TRUE(AreElementsEqual(
297        *upload->element_readers()[5], blob_element1));
298    EXPECT_TRUE(AreElementsEqual(
299        *upload->element_readers()[6], blob_element2));
300    EXPECT_TRUE(AreElementsEqual(
301        *upload->element_readers()[7], upload_element2));
302  }
303  // Clean up for ASAN.
304  base::RunLoop().RunUntilIdle();
305}
306
307}  // namespace content
308