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/file_util.h" 10 #include "base/files/file_path.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 "testing/gtest/include/gtest/gtest.h" 20 #include "url/gurl.h" 21 #include "webkit/browser/blob/blob_storage_context.h" 22 23 using webkit_blob::BlobData; 24 using webkit_blob::BlobDataHandle; 25 using webkit_blob::BlobStorageContext; 26 27 namespace content { 28 namespace { 29 30 bool 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 59 TEST(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 95 TEST(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); 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); 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