| 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 "webkit/fileapi/file_system_dir_url_request_job.h" | |
| 6 | |
| 7 #include <string> | |
| 8 | |
| 9 #include "base/files/file_path.h" | |
| 10 #include "base/files/scoped_temp_dir.h" | |
| 11 #include "base/format_macros.h" | |
| 12 #include "base/memory/weak_ptr.h" | |
| 13 #include "base/message_loop.h" | |
| 14 #include "base/platform_file.h" | |
| 15 #include "base/strings/string_piece.h" | |
| 16 #include "base/utf_string_conversions.h" | |
| 17 #include "net/base/net_errors.h" | |
| 18 #include "net/base/net_util.h" | |
| 19 #include "net/http/http_request_headers.h" | |
| 20 #include "net/url_request/url_request.h" | |
| 21 #include "net/url_request/url_request_context.h" | |
| 22 #include "net/url_request/url_request_test_util.h" | |
| 23 #include "testing/gtest/include/gtest/gtest.h" | |
| 24 #include "third_party/icu/public/i18n/unicode/regex.h" | |
| 25 #include "webkit/fileapi/file_system_context.h" | |
| 26 #include "webkit/fileapi/file_system_file_util.h" | |
| 27 #include "webkit/fileapi/file_system_operation_context.h" | |
| 28 #include "webkit/fileapi/file_system_url.h" | |
| 29 #include "webkit/fileapi/mock_file_system_context.h" | |
| 30 #include "webkit/fileapi/sandbox_mount_point_provider.h" | |
| 31 #include "webkit/quota/mock_special_storage_policy.h" | |
| 32 | |
| 33 namespace fileapi { | |
| 34 namespace { | |
| 35 | |
| 36 // We always use the TEMPORARY FileSystem in this test. | |
| 37 static const char kFileSystemURLPrefix[] = | |
| 38 "filesystem:http://remote/temporary/"; | |
| 39 | |
| 40 } // namespace | |
| 41 | |
| 42 class FileSystemDirURLRequestJobTest : public testing::Test { | |
| 43 protected: | |
| 44 FileSystemDirURLRequestJobTest() | |
| 45 : message_loop_(base::MessageLoop::TYPE_IO), // simulate an IO thread | |
| 46 weak_factory_(this) { | |
| 47 } | |
| 48 | |
| 49 virtual void SetUp() OVERRIDE { | |
| 50 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
| 51 | |
| 52 special_storage_policy_ = new quota::MockSpecialStoragePolicy; | |
| 53 file_system_context_ = CreateFileSystemContextForTesting( | |
| 54 NULL, temp_dir_.path()); | |
| 55 | |
| 56 file_system_context_->sandbox_provider()->ValidateFileSystemRoot( | |
| 57 GURL("http://remote/"), kFileSystemTypeTemporary, true, // create | |
| 58 base::Bind(&FileSystemDirURLRequestJobTest::OnValidateFileSystem, | |
| 59 weak_factory_.GetWeakPtr())); | |
| 60 base::MessageLoop::current()->RunUntilIdle(); | |
| 61 | |
| 62 net::URLRequest::Deprecated::RegisterProtocolFactory( | |
| 63 "filesystem", &FileSystemDirURLRequestJobFactory); | |
| 64 } | |
| 65 | |
| 66 virtual void TearDown() OVERRIDE { | |
| 67 // NOTE: order matters, request must die before delegate | |
| 68 request_.reset(NULL); | |
| 69 delegate_.reset(NULL); | |
| 70 | |
| 71 net::URLRequest::Deprecated::RegisterProtocolFactory("filesystem", NULL); | |
| 72 ClearUnusedJob(); | |
| 73 } | |
| 74 | |
| 75 void OnValidateFileSystem(base::PlatformFileError result) { | |
| 76 ASSERT_EQ(base::PLATFORM_FILE_OK, result); | |
| 77 } | |
| 78 | |
| 79 void TestRequestHelper(const GURL& url, bool run_to_completion) { | |
| 80 delegate_.reset(new net::TestDelegate()); | |
| 81 delegate_->set_quit_on_redirect(true); | |
| 82 request_.reset(empty_context_.CreateRequest(url, delegate_.get())); | |
| 83 job_ = new FileSystemDirURLRequestJob( | |
| 84 request_.get(), NULL, file_system_context_.get()); | |
| 85 | |
| 86 request_->Start(); | |
| 87 ASSERT_TRUE(request_->is_pending()); // verify that we're starting async | |
| 88 if (run_to_completion) | |
| 89 base::MessageLoop::current()->Run(); | |
| 90 } | |
| 91 | |
| 92 void TestRequest(const GURL& url) { | |
| 93 TestRequestHelper(url, true); | |
| 94 } | |
| 95 | |
| 96 void TestRequestNoRun(const GURL& url) { | |
| 97 TestRequestHelper(url, false); | |
| 98 } | |
| 99 | |
| 100 FileSystemURL CreateURL(const base::FilePath& file_path) { | |
| 101 return file_system_context_->CreateCrackedFileSystemURL( | |
| 102 GURL("http://remote"), | |
| 103 fileapi::kFileSystemTypeTemporary, | |
| 104 file_path); | |
| 105 } | |
| 106 | |
| 107 FileSystemOperationContext* NewOperationContext() { | |
| 108 FileSystemOperationContext* context(new FileSystemOperationContext( | |
| 109 file_system_context_)); | |
| 110 context->set_allowed_bytes_growth(1024); | |
| 111 return context; | |
| 112 } | |
| 113 | |
| 114 void CreateDirectory(const base::StringPiece& dir_name) { | |
| 115 base::FilePath path = base::FilePath().AppendASCII(dir_name); | |
| 116 scoped_ptr<FileSystemOperationContext> context(NewOperationContext()); | |
| 117 ASSERT_EQ(base::PLATFORM_FILE_OK, file_util()->CreateDirectory( | |
| 118 context.get(), | |
| 119 CreateURL(path), | |
| 120 false /* exclusive */, | |
| 121 false /* recursive */)); | |
| 122 } | |
| 123 | |
| 124 void EnsureFileExists(const base::StringPiece file_name) { | |
| 125 base::FilePath path = base::FilePath().AppendASCII(file_name); | |
| 126 scoped_ptr<FileSystemOperationContext> context(NewOperationContext()); | |
| 127 ASSERT_EQ(base::PLATFORM_FILE_OK, file_util()->EnsureFileExists( | |
| 128 context.get(), CreateURL(path), NULL)); | |
| 129 } | |
| 130 | |
| 131 void TruncateFile(const base::StringPiece file_name, int64 length) { | |
| 132 base::FilePath path = base::FilePath().AppendASCII(file_name); | |
| 133 scoped_ptr<FileSystemOperationContext> context(NewOperationContext()); | |
| 134 ASSERT_EQ(base::PLATFORM_FILE_OK, file_util()->Truncate( | |
| 135 context.get(), CreateURL(path), length)); | |
| 136 } | |
| 137 | |
| 138 base::PlatformFileError GetFileInfo(const base::FilePath& path, | |
| 139 base::PlatformFileInfo* file_info, | |
| 140 base::FilePath* platform_file_path) { | |
| 141 scoped_ptr<FileSystemOperationContext> context(NewOperationContext()); | |
| 142 return file_util()->GetFileInfo(context.get(), | |
| 143 CreateURL(path), | |
| 144 file_info, platform_file_path); | |
| 145 } | |
| 146 | |
| 147 void VerifyListingEntry(const std::string& entry_line, | |
| 148 const std::string& name, | |
| 149 const std::string& url, | |
| 150 bool is_directory, | |
| 151 int64 size) { | |
| 152 #define STR "([^\"]*)" | |
| 153 icu::UnicodeString pattern("^<script>addRow\\(\"" STR "\",\"" STR | |
| 154 "\",(0|1),\"" STR "\",\"" STR "\"\\);</script>"); | |
| 155 #undef STR | |
| 156 icu::UnicodeString input(entry_line.c_str()); | |
| 157 | |
| 158 UErrorCode status = U_ZERO_ERROR; | |
| 159 icu::RegexMatcher match(pattern, input, 0, status); | |
| 160 | |
| 161 EXPECT_TRUE(match.find()); | |
| 162 EXPECT_EQ(5, match.groupCount()); | |
| 163 EXPECT_EQ(icu::UnicodeString(name.c_str()), match.group(1, status)); | |
| 164 EXPECT_EQ(icu::UnicodeString(url.c_str()), match.group(2, status)); | |
| 165 EXPECT_EQ(icu::UnicodeString(is_directory ? "1" : "0"), | |
| 166 match.group(3, status)); | |
| 167 icu::UnicodeString size_string(FormatBytesUnlocalized(size).c_str()); | |
| 168 EXPECT_EQ(size_string, match.group(4, status)); | |
| 169 | |
| 170 base::Time date; | |
| 171 icu::UnicodeString date_ustr(match.group(5, status)); | |
| 172 std::string date_str; | |
| 173 UTF16ToUTF8(date_ustr.getBuffer(), date_ustr.length(), &date_str); | |
| 174 EXPECT_TRUE(base::Time::FromString(date_str.c_str(), &date)); | |
| 175 EXPECT_FALSE(date.is_null()); | |
| 176 } | |
| 177 | |
| 178 GURL CreateFileSystemURL(const std::string path) { | |
| 179 return GURL(kFileSystemURLPrefix + path); | |
| 180 } | |
| 181 | |
| 182 static net::URLRequestJob* FileSystemDirURLRequestJobFactory( | |
| 183 net::URLRequest* request, | |
| 184 net::NetworkDelegate* network_delegate, | |
| 185 const std::string& scheme) { | |
| 186 DCHECK(job_); | |
| 187 net::URLRequestJob* temp = job_; | |
| 188 job_ = NULL; | |
| 189 return temp; | |
| 190 } | |
| 191 | |
| 192 static void ClearUnusedJob() { | |
| 193 if (job_) { | |
| 194 scoped_refptr<net::URLRequestJob> deleter = job_; | |
| 195 job_ = NULL; | |
| 196 } | |
| 197 } | |
| 198 | |
| 199 FileSystemFileUtil* file_util() { | |
| 200 return file_system_context_->sandbox_provider()->GetFileUtil( | |
| 201 kFileSystemTypeTemporary); | |
| 202 } | |
| 203 | |
| 204 // Put the message loop at the top, so that it's the last thing deleted. | |
| 205 // Delete all MessageLoopProxy objects before the MessageLoop, to help prevent | |
| 206 // leaks caused by tasks posted during shutdown. | |
| 207 base::MessageLoop message_loop_; | |
| 208 | |
| 209 base::ScopedTempDir temp_dir_; | |
| 210 net::URLRequestContext empty_context_; | |
| 211 scoped_ptr<net::TestDelegate> delegate_; | |
| 212 scoped_ptr<net::URLRequest> request_; | |
| 213 scoped_refptr<quota::MockSpecialStoragePolicy> special_storage_policy_; | |
| 214 scoped_refptr<FileSystemContext> file_system_context_; | |
| 215 base::WeakPtrFactory<FileSystemDirURLRequestJobTest> weak_factory_; | |
| 216 | |
| 217 static net::URLRequestJob* job_; | |
| 218 }; | |
| 219 | |
| 220 // static | |
| 221 net::URLRequestJob* FileSystemDirURLRequestJobTest::job_ = NULL; | |
| 222 | |
| 223 namespace { | |
| 224 | |
| 225 TEST_F(FileSystemDirURLRequestJobTest, DirectoryListing) { | |
| 226 CreateDirectory("foo"); | |
| 227 CreateDirectory("foo/bar"); | |
| 228 CreateDirectory("foo/bar/baz"); | |
| 229 | |
| 230 EnsureFileExists("foo/bar/hoge"); | |
| 231 TruncateFile("foo/bar/hoge", 10); | |
| 232 | |
| 233 TestRequest(CreateFileSystemURL("foo/bar/")); | |
| 234 | |
| 235 ASSERT_FALSE(request_->is_pending()); | |
| 236 EXPECT_EQ(1, delegate_->response_started_count()); | |
| 237 EXPECT_FALSE(delegate_->received_data_before_response()); | |
| 238 EXPECT_GT(delegate_->bytes_received(), 0); | |
| 239 | |
| 240 std::istringstream in(delegate_->data_received()); | |
| 241 std::string line; | |
| 242 EXPECT_TRUE(std::getline(in, line)); | |
| 243 | |
| 244 #if defined(OS_WIN) | |
| 245 EXPECT_EQ("<script>start(\"foo\\\\bar\");</script>", line); | |
| 246 #elif defined(OS_POSIX) | |
| 247 EXPECT_EQ("<script>start(\"/foo/bar\");</script>", line); | |
| 248 #endif | |
| 249 | |
| 250 EXPECT_TRUE(std::getline(in, line)); | |
| 251 VerifyListingEntry(line, "hoge", "hoge", false, 10); | |
| 252 | |
| 253 EXPECT_TRUE(std::getline(in, line)); | |
| 254 VerifyListingEntry(line, "baz", "baz", true, 0); | |
| 255 } | |
| 256 | |
| 257 TEST_F(FileSystemDirURLRequestJobTest, InvalidURL) { | |
| 258 TestRequest(GURL("filesystem:/foo/bar/baz")); | |
| 259 ASSERT_FALSE(request_->is_pending()); | |
| 260 EXPECT_TRUE(delegate_->request_failed()); | |
| 261 ASSERT_FALSE(request_->status().is_success()); | |
| 262 EXPECT_EQ(net::ERR_INVALID_URL, request_->status().error()); | |
| 263 } | |
| 264 | |
| 265 TEST_F(FileSystemDirURLRequestJobTest, NoSuchRoot) { | |
| 266 TestRequest(GURL("filesystem:http://remote/persistent/somedir/")); | |
| 267 ASSERT_FALSE(request_->is_pending()); | |
| 268 ASSERT_FALSE(request_->status().is_success()); | |
| 269 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error()); | |
| 270 } | |
| 271 | |
| 272 TEST_F(FileSystemDirURLRequestJobTest, NoSuchDirectory) { | |
| 273 TestRequest(CreateFileSystemURL("somedir/")); | |
| 274 ASSERT_FALSE(request_->is_pending()); | |
| 275 ASSERT_FALSE(request_->status().is_success()); | |
| 276 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error()); | |
| 277 } | |
| 278 | |
| 279 TEST_F(FileSystemDirURLRequestJobTest, Cancel) { | |
| 280 CreateDirectory("foo"); | |
| 281 TestRequestNoRun(CreateFileSystemURL("foo/")); | |
| 282 // Run StartAsync() and only StartAsync(). | |
| 283 base::MessageLoop::current()->DeleteSoon(FROM_HERE, request_.release()); | |
| 284 base::MessageLoop::current()->RunUntilIdle(); | |
| 285 // If we get here, success! we didn't crash! | |
| 286 } | |
| 287 | |
| 288 } // namespace (anonymous) | |
| 289 } // namespace fileapi | |
| OLD | NEW |