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