| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2012 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 "base/bind.h" | |
| 6 #include "base/file_util.h" | |
| 7 #include "base/files/file_path.h" | |
| 8 #include "base/files/scoped_temp_dir.h" | |
| 9 #include "base/memory/ref_counted.h" | |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "base/message_loop.h" | |
| 12 #include "base/time.h" | |
| 13 #include "net/base/io_buffer.h" | |
| 14 #include "net/http/http_request_headers.h" | |
| 15 #include "net/http/http_response_headers.h" | |
| 16 #include "net/url_request/url_request.h" | |
| 17 #include "net/url_request/url_request_context.h" | |
| 18 #include "net/url_request/url_request_job_factory_impl.h" | |
| 19 #include "testing/gtest/include/gtest/gtest.h" | |
| 20 #include "webkit/blob/blob_data.h" | |
| 21 #include "webkit/blob/blob_url_request_job.h" | |
| 22 #include "webkit/browser/fileapi/file_system_file_util.h" | |
| 23 #include "webkit/fileapi/file_system_context.h" | |
| 24 #include "webkit/fileapi/file_system_operation_context.h" | |
| 25 #include "webkit/fileapi/file_system_url.h" | |
| 26 #include "webkit/fileapi/mock_file_system_context.h" | |
| 27 | |
| 28 namespace webkit_blob { | |
| 29 | |
| 30 namespace { | |
| 31 | |
| 32 const int kBufferSize = 1024; | |
| 33 const char kTestData1[] = "Hello"; | |
| 34 const char kTestData2[] = "Here it is data."; | |
| 35 const char kTestFileData1[] = "0123456789"; | |
| 36 const char kTestFileData2[] = "This is sample file."; | |
| 37 const char kTestFileSystemFileData1[] = "abcdefghijklmnop"; | |
| 38 const char kTestFileSystemFileData2[] = "File system file test data."; | |
| 39 const char kTestContentType[] = "foo/bar"; | |
| 40 const char kTestContentDisposition[] = "attachment; filename=foo.txt"; | |
| 41 | |
| 42 const char kFileSystemURLOrigin[] = "http://remote"; | |
| 43 const fileapi::FileSystemType kFileSystemType = | |
| 44 fileapi::kFileSystemTypeTemporary; | |
| 45 | |
| 46 } // namespace | |
| 47 | |
| 48 class BlobURLRequestJobTest : public testing::Test { | |
| 49 public: | |
| 50 | |
| 51 // Test Harness ------------------------------------------------------------- | |
| 52 // TODO(jianli): share this test harness with AppCacheURLRequestJobTest | |
| 53 | |
| 54 class MockURLRequestDelegate : public net::URLRequest::Delegate { | |
| 55 public: | |
| 56 MockURLRequestDelegate() | |
| 57 : received_data_(new net::IOBuffer(kBufferSize)) {} | |
| 58 | |
| 59 virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE { | |
| 60 if (request->status().is_success()) { | |
| 61 EXPECT_TRUE(request->response_headers()); | |
| 62 ReadSome(request); | |
| 63 } else { | |
| 64 RequestComplete(); | |
| 65 } | |
| 66 } | |
| 67 | |
| 68 virtual void OnReadCompleted(net::URLRequest* request, | |
| 69 int bytes_read) OVERRIDE { | |
| 70 if (bytes_read > 0) | |
| 71 ReceiveData(request, bytes_read); | |
| 72 else | |
| 73 RequestComplete(); | |
| 74 } | |
| 75 | |
| 76 const std::string& response_data() const { return response_data_; } | |
| 77 | |
| 78 private: | |
| 79 void ReadSome(net::URLRequest* request) { | |
| 80 if (!request->is_pending()) { | |
| 81 RequestComplete(); | |
| 82 return; | |
| 83 } | |
| 84 | |
| 85 int bytes_read = 0; | |
| 86 if (!request->Read(received_data_.get(), kBufferSize, &bytes_read)) { | |
| 87 if (!request->status().is_io_pending()) { | |
| 88 RequestComplete(); | |
| 89 } | |
| 90 return; | |
| 91 } | |
| 92 | |
| 93 ReceiveData(request, bytes_read); | |
| 94 } | |
| 95 | |
| 96 void ReceiveData(net::URLRequest* request, int bytes_read) { | |
| 97 if (bytes_read) { | |
| 98 response_data_.append(received_data_->data(), | |
| 99 static_cast<size_t>(bytes_read)); | |
| 100 ReadSome(request); | |
| 101 } else { | |
| 102 RequestComplete(); | |
| 103 } | |
| 104 } | |
| 105 | |
| 106 void RequestComplete() { | |
| 107 base::MessageLoop::current()->Quit(); | |
| 108 } | |
| 109 | |
| 110 scoped_refptr<net::IOBuffer> received_data_; | |
| 111 std::string response_data_; | |
| 112 }; | |
| 113 | |
| 114 // A simple ProtocolHandler implementation to create BlobURLRequestJob. | |
| 115 class MockProtocolHandler : | |
| 116 public net::URLRequestJobFactory::ProtocolHandler { | |
| 117 public: | |
| 118 MockProtocolHandler(BlobURLRequestJobTest* test) : test_(test) {} | |
| 119 | |
| 120 // net::URLRequestJobFactory::ProtocolHandler override. | |
| 121 virtual net::URLRequestJob* MaybeCreateJob( | |
| 122 net::URLRequest* request, | |
| 123 net::NetworkDelegate* network_delegate) const OVERRIDE { | |
| 124 return new BlobURLRequestJob(request, | |
| 125 network_delegate, | |
| 126 test_->blob_data_, | |
| 127 test_->file_system_context_, | |
| 128 base::MessageLoopProxy::current()); | |
| 129 } | |
| 130 | |
| 131 private: | |
| 132 BlobURLRequestJobTest* test_; | |
| 133 }; | |
| 134 | |
| 135 BlobURLRequestJobTest() | |
| 136 : message_loop_(base::MessageLoop::TYPE_IO), | |
| 137 blob_data_(new BlobData()), | |
| 138 expected_status_code_(0) {} | |
| 139 | |
| 140 virtual void SetUp() { | |
| 141 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| 142 | |
| 143 temp_file1_ = temp_dir_.path().AppendASCII("BlobFile1.dat"); | |
| 144 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData1) - 1), | |
| 145 file_util::WriteFile(temp_file1_, kTestFileData1, | |
| 146 arraysize(kTestFileData1) - 1)); | |
| 147 base::PlatformFileInfo file_info1; | |
| 148 file_util::GetFileInfo(temp_file1_, &file_info1); | |
| 149 temp_file_modification_time1_ = file_info1.last_modified; | |
| 150 | |
| 151 temp_file2_ = temp_dir_.path().AppendASCII("BlobFile2.dat"); | |
| 152 ASSERT_EQ(static_cast<int>(arraysize(kTestFileData2) - 1), | |
| 153 file_util::WriteFile(temp_file2_, kTestFileData2, | |
| 154 arraysize(kTestFileData2) - 1)); | |
| 155 base::PlatformFileInfo file_info2; | |
| 156 file_util::GetFileInfo(temp_file2_, &file_info2); | |
| 157 temp_file_modification_time2_ = file_info2.last_modified; | |
| 158 | |
| 159 url_request_job_factory_.SetProtocolHandler("blob", | |
| 160 new MockProtocolHandler(this)); | |
| 161 url_request_context_.set_job_factory(&url_request_job_factory_); | |
| 162 } | |
| 163 | |
| 164 virtual void TearDown() { | |
| 165 } | |
| 166 | |
| 167 void SetUpFileSystem() { | |
| 168 // Prepare file system. | |
| 169 file_system_context_ = fileapi::CreateFileSystemContextForTesting( | |
| 170 NULL, temp_dir_.path()); | |
| 171 | |
| 172 file_system_context_->OpenFileSystem( | |
| 173 GURL(kFileSystemURLOrigin), | |
| 174 kFileSystemType, | |
| 175 true, // create | |
| 176 base::Bind(&BlobURLRequestJobTest::OnValidateFileSystem, | |
| 177 base::Unretained(this))); | |
| 178 base::MessageLoop::current()->RunUntilIdle(); | |
| 179 ASSERT_TRUE(file_system_root_url_.is_valid()); | |
| 180 | |
| 181 // Prepare files on file system. | |
| 182 const char kFilename1[] = "FileSystemFile1.dat"; | |
| 183 temp_file_system_file1_ = GetFileSystemURL(kFilename1); | |
| 184 WriteFileSystemFile(kFilename1, kTestFileSystemFileData1, | |
| 185 arraysize(kTestFileSystemFileData1) - 1, | |
| 186 &temp_file_system_file_modification_time1_); | |
| 187 const char kFilename2[] = "FileSystemFile2.dat"; | |
| 188 temp_file_system_file2_ = GetFileSystemURL(kFilename2); | |
| 189 WriteFileSystemFile(kFilename2, kTestFileSystemFileData2, | |
| 190 arraysize(kTestFileSystemFileData2) - 1, | |
| 191 &temp_file_system_file_modification_time2_); | |
| 192 } | |
| 193 | |
| 194 GURL GetFileSystemURL(const std::string& filename) { | |
| 195 return GURL(file_system_root_url_.spec() + filename); | |
| 196 } | |
| 197 | |
| 198 void WriteFileSystemFile(const std::string& filename, | |
| 199 const char* buf, int buf_size, | |
| 200 base::Time* modification_time) { | |
| 201 fileapi::FileSystemURL url = | |
| 202 file_system_context_->CreateCrackedFileSystemURL( | |
| 203 GURL(kFileSystemURLOrigin), | |
| 204 kFileSystemType, | |
| 205 base::FilePath().AppendASCII(filename)); | |
| 206 | |
| 207 fileapi::FileSystemFileUtil* file_util = | |
| 208 file_system_context_->GetFileUtil(kFileSystemType); | |
| 209 | |
| 210 fileapi::FileSystemOperationContext context(file_system_context_); | |
| 211 context.set_allowed_bytes_growth(1024); | |
| 212 | |
| 213 base::PlatformFile handle = base::kInvalidPlatformFileValue; | |
| 214 bool created = false; | |
| 215 ASSERT_EQ(base::PLATFORM_FILE_OK, file_util->CreateOrOpen( | |
| 216 &context, | |
| 217 url, | |
| 218 base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, | |
| 219 &handle, | |
| 220 &created)); | |
| 221 EXPECT_TRUE(created); | |
| 222 ASSERT_NE(base::kInvalidPlatformFileValue, handle); | |
| 223 ASSERT_EQ(buf_size, | |
| 224 base::WritePlatformFile(handle, 0 /* offset */, buf, buf_size)); | |
| 225 base::ClosePlatformFile(handle); | |
| 226 | |
| 227 base::PlatformFileInfo file_info; | |
| 228 base::FilePath platform_path; | |
| 229 ASSERT_EQ(base::PLATFORM_FILE_OK, | |
| 230 file_util->GetFileInfo(&context, url, &file_info, | |
| 231 &platform_path)); | |
| 232 if (modification_time) | |
| 233 *modification_time = file_info.last_modified; | |
| 234 } | |
| 235 | |
| 236 void OnValidateFileSystem(base::PlatformFileError result, | |
| 237 const std::string& name, | |
| 238 const GURL& root) { | |
| 239 ASSERT_EQ(base::PLATFORM_FILE_OK, result); | |
| 240 ASSERT_TRUE(root.is_valid()); | |
| 241 file_system_root_url_ = root; | |
| 242 } | |
| 243 | |
| 244 void TestSuccessRequest(const std::string& expected_response) { | |
| 245 expected_status_code_ = 200; | |
| 246 expected_response_ = expected_response; | |
| 247 TestRequest("GET", net::HttpRequestHeaders()); | |
| 248 } | |
| 249 | |
| 250 void TestErrorRequest(int expected_status_code) { | |
| 251 expected_status_code_ = expected_status_code; | |
| 252 expected_response_ = ""; | |
| 253 TestRequest("GET", net::HttpRequestHeaders()); | |
| 254 } | |
| 255 | |
| 256 void TestRequest(const std::string& method, | |
| 257 const net::HttpRequestHeaders& extra_headers) { | |
| 258 request_.reset(url_request_context_.CreateRequest( | |
| 259 GURL("blob:blah"), &url_request_delegate_)); | |
| 260 request_->set_method(method); | |
| 261 if (!extra_headers.IsEmpty()) | |
| 262 request_->SetExtraRequestHeaders(extra_headers); | |
| 263 request_->Start(); | |
| 264 | |
| 265 base::MessageLoop::current()->Run(); | |
| 266 | |
| 267 // Verify response. | |
| 268 EXPECT_TRUE(request_->status().is_success()); | |
| 269 EXPECT_EQ(expected_status_code_, | |
| 270 request_->response_headers()->response_code()); | |
| 271 EXPECT_EQ(expected_response_, url_request_delegate_.response_data()); | |
| 272 } | |
| 273 | |
| 274 void BuildComplicatedData(std::string* expected_result) { | |
| 275 blob_data_->AppendData(kTestData1 + 1, 2); | |
| 276 blob_data_->AppendFile(temp_file1_, 2, 3, temp_file_modification_time1_); | |
| 277 blob_data_->AppendFileSystemFile(temp_file_system_file1_, 3, 4, | |
| 278 temp_file_system_file_modification_time1_); | |
| 279 blob_data_->AppendData(kTestData2 + 4, 5); | |
| 280 blob_data_->AppendFile(temp_file2_, 5, 6, temp_file_modification_time2_); | |
| 281 blob_data_->AppendFileSystemFile(temp_file_system_file2_, 6, 7, | |
| 282 temp_file_system_file_modification_time2_); | |
| 283 *expected_result = std::string(kTestData1 + 1, 2); | |
| 284 *expected_result += std::string(kTestFileData1 + 2, 3); | |
| 285 *expected_result += std::string(kTestFileSystemFileData1 + 3, 4); | |
| 286 *expected_result += std::string(kTestData2 + 4, 5); | |
| 287 *expected_result += std::string(kTestFileData2 + 5, 6); | |
| 288 *expected_result += std::string(kTestFileSystemFileData2 + 6, 7); | |
| 289 } | |
| 290 | |
| 291 protected: | |
| 292 base::ScopedTempDir temp_dir_; | |
| 293 base::FilePath temp_file1_; | |
| 294 base::FilePath temp_file2_; | |
| 295 base::Time temp_file_modification_time1_; | |
| 296 base::Time temp_file_modification_time2_; | |
| 297 GURL file_system_root_url_; | |
| 298 GURL temp_file_system_file1_; | |
| 299 GURL temp_file_system_file2_; | |
| 300 base::Time temp_file_system_file_modification_time1_; | |
| 301 base::Time temp_file_system_file_modification_time2_; | |
| 302 | |
| 303 base::MessageLoop message_loop_; | |
| 304 scoped_refptr<fileapi::FileSystemContext> file_system_context_; | |
| 305 scoped_refptr<BlobData> blob_data_; | |
| 306 net::URLRequestJobFactoryImpl url_request_job_factory_; | |
| 307 net::URLRequestContext url_request_context_; | |
| 308 MockURLRequestDelegate url_request_delegate_; | |
| 309 scoped_ptr<net::URLRequest> request_; | |
| 310 | |
| 311 int expected_status_code_; | |
| 312 std::string expected_response_; | |
| 313 }; | |
| 314 | |
| 315 TEST_F(BlobURLRequestJobTest, TestGetSimpleDataRequest) { | |
| 316 blob_data_->AppendData(kTestData1); | |
| 317 TestSuccessRequest(kTestData1); | |
| 318 } | |
| 319 | |
| 320 TEST_F(BlobURLRequestJobTest, TestGetSimpleFileRequest) { | |
| 321 blob_data_->AppendFile(temp_file1_, 0, -1, base::Time()); | |
| 322 TestSuccessRequest(kTestFileData1); | |
| 323 } | |
| 324 | |
| 325 TEST_F(BlobURLRequestJobTest, TestGetLargeFileRequest) { | |
| 326 base::FilePath large_temp_file = temp_dir_.path().AppendASCII("LargeBlob.dat")
; | |
| 327 std::string large_data; | |
| 328 large_data.reserve(kBufferSize * 5); | |
| 329 for (int i = 0; i < kBufferSize * 5; ++i) | |
| 330 large_data.append(1, static_cast<char>(i % 256)); | |
| 331 ASSERT_EQ(static_cast<int>(large_data.size()), | |
| 332 file_util::WriteFile(large_temp_file, large_data.data(), | |
| 333 large_data.size())); | |
| 334 blob_data_->AppendFile(large_temp_file, 0, -1, base::Time()); | |
| 335 TestSuccessRequest(large_data); | |
| 336 } | |
| 337 | |
| 338 TEST_F(BlobURLRequestJobTest, TestGetNonExistentFileRequest) { | |
| 339 base::FilePath non_existent_file = | |
| 340 temp_file1_.InsertBeforeExtension(FILE_PATH_LITERAL("-na")); | |
| 341 blob_data_->AppendFile(non_existent_file, 0, -1, base::Time()); | |
| 342 TestErrorRequest(404); | |
| 343 } | |
| 344 | |
| 345 TEST_F(BlobURLRequestJobTest, TestGetChangedFileRequest) { | |
| 346 base::Time old_time = | |
| 347 temp_file_modification_time1_ - base::TimeDelta::FromSeconds(10); | |
| 348 blob_data_->AppendFile(temp_file1_, 0, 3, old_time); | |
| 349 TestErrorRequest(404); | |
| 350 } | |
| 351 | |
| 352 TEST_F(BlobURLRequestJobTest, TestGetSlicedFileRequest) { | |
| 353 blob_data_->AppendFile(temp_file1_, 2, 4, temp_file_modification_time1_); | |
| 354 std::string result(kTestFileData1 + 2, 4); | |
| 355 TestSuccessRequest(result); | |
| 356 } | |
| 357 | |
| 358 TEST_F(BlobURLRequestJobTest, TestGetSimpleFileSystemFileRequest) { | |
| 359 SetUpFileSystem(); | |
| 360 blob_data_->AppendFileSystemFile(temp_file_system_file1_, 0, -1, | |
| 361 base::Time()); | |
| 362 TestSuccessRequest(kTestFileSystemFileData1); | |
| 363 } | |
| 364 | |
| 365 TEST_F(BlobURLRequestJobTest, TestGetLargeFileSystemFileRequest) { | |
| 366 SetUpFileSystem(); | |
| 367 std::string large_data; | |
| 368 large_data.reserve(kBufferSize * 5); | |
| 369 for (int i = 0; i < kBufferSize * 5; ++i) | |
| 370 large_data.append(1, static_cast<char>(i % 256)); | |
| 371 | |
| 372 const char kFilename[] = "LargeBlob.dat"; | |
| 373 WriteFileSystemFile(kFilename, large_data.data(), large_data.size(), NULL); | |
| 374 | |
| 375 blob_data_->AppendFileSystemFile(GetFileSystemURL(kFilename), | |
| 376 0, -1, base::Time()); | |
| 377 TestSuccessRequest(large_data); | |
| 378 } | |
| 379 | |
| 380 TEST_F(BlobURLRequestJobTest, TestGetNonExistentFileSystemFileRequest) { | |
| 381 SetUpFileSystem(); | |
| 382 GURL non_existent_file = GetFileSystemURL("non-existent.dat"); | |
| 383 blob_data_->AppendFileSystemFile(non_existent_file, 0, -1, base::Time()); | |
| 384 TestErrorRequest(404); | |
| 385 } | |
| 386 | |
| 387 TEST_F(BlobURLRequestJobTest, TestGetChangedFileSystemFileRequest) { | |
| 388 SetUpFileSystem(); | |
| 389 base::Time old_time = | |
| 390 temp_file_system_file_modification_time1_ - | |
| 391 base::TimeDelta::FromSeconds(10); | |
| 392 blob_data_->AppendFileSystemFile(temp_file_system_file1_, 0, 3, old_time); | |
| 393 TestErrorRequest(404); | |
| 394 } | |
| 395 | |
| 396 TEST_F(BlobURLRequestJobTest, TestGetSlicedFileSystemFileRequest) { | |
| 397 SetUpFileSystem(); | |
| 398 blob_data_->AppendFileSystemFile(temp_file_system_file1_, 2, 4, | |
| 399 temp_file_system_file_modification_time1_); | |
| 400 std::string result(kTestFileSystemFileData1 + 2, 4); | |
| 401 TestSuccessRequest(result); | |
| 402 } | |
| 403 | |
| 404 TEST_F(BlobURLRequestJobTest, TestGetComplicatedDataAndFileRequest) { | |
| 405 SetUpFileSystem(); | |
| 406 std::string result; | |
| 407 BuildComplicatedData(&result); | |
| 408 TestSuccessRequest(result); | |
| 409 } | |
| 410 | |
| 411 TEST_F(BlobURLRequestJobTest, TestGetRangeRequest1) { | |
| 412 SetUpFileSystem(); | |
| 413 std::string result; | |
| 414 BuildComplicatedData(&result); | |
| 415 net::HttpRequestHeaders extra_headers; | |
| 416 extra_headers.SetHeader(net::HttpRequestHeaders::kRange, "bytes=5-10"); | |
| 417 expected_status_code_ = 206; | |
| 418 expected_response_ = result.substr(5, 10 - 5 + 1); | |
| 419 TestRequest("GET", extra_headers); | |
| 420 } | |
| 421 | |
| 422 TEST_F(BlobURLRequestJobTest, TestGetRangeRequest2) { | |
| 423 SetUpFileSystem(); | |
| 424 std::string result; | |
| 425 BuildComplicatedData(&result); | |
| 426 net::HttpRequestHeaders extra_headers; | |
| 427 extra_headers.SetHeader(net::HttpRequestHeaders::kRange, "bytes=-10"); | |
| 428 expected_status_code_ = 206; | |
| 429 expected_response_ = result.substr(result.length() - 10); | |
| 430 TestRequest("GET", extra_headers); | |
| 431 } | |
| 432 | |
| 433 TEST_F(BlobURLRequestJobTest, TestExtraHeaders) { | |
| 434 blob_data_->set_content_type(kTestContentType); | |
| 435 blob_data_->set_content_disposition(kTestContentDisposition); | |
| 436 blob_data_->AppendData(kTestData1); | |
| 437 expected_status_code_ = 200; | |
| 438 expected_response_ = kTestData1; | |
| 439 TestRequest("GET", net::HttpRequestHeaders()); | |
| 440 | |
| 441 std::string content_type; | |
| 442 EXPECT_TRUE(request_->response_headers()->GetMimeType(&content_type)); | |
| 443 EXPECT_EQ(kTestContentType, content_type); | |
| 444 void* iter = NULL; | |
| 445 std::string content_disposition; | |
| 446 EXPECT_TRUE(request_->response_headers()->EnumerateHeader( | |
| 447 &iter, "Content-Disposition", &content_disposition)); | |
| 448 EXPECT_EQ(kTestContentDisposition, content_disposition); | |
| 449 } | |
| 450 | |
| 451 } // namespace webkit_blob | |
| OLD | NEW |