Ignore title parameter for navigator.registerProtocolHandler
[chromium-blink-merge.git] / content / browser / fileapi / file_system_dir_url_request_job_unittest.cc
blob29eb70466804224d6ef79ce65a1e0405626003d2
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.
5 #include "webkit/browser/fileapi/file_system_dir_url_request_job.h"
7 #include <string>
9 #include "base/file_util.h"
10 #include "base/files/file_path.h"
11 #include "base/files/scoped_temp_dir.h"
12 #include "base/format_macros.h"
13 #include "base/memory/scoped_vector.h"
14 #include "base/memory/weak_ptr.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/platform_file.h"
17 #include "base/run_loop.h"
18 #include "base/strings/string_piece.h"
19 #include "base/strings/utf_string_conversions.h"
20 #include "content/public/test/mock_special_storage_policy.h"
21 #include "content/public/test/test_file_system_backend.h"
22 #include "content/public/test/test_file_system_context.h"
23 #include "net/base/net_errors.h"
24 #include "net/base/net_util.h"
25 #include "net/base/request_priority.h"
26 #include "net/http/http_request_headers.h"
27 #include "net/url_request/url_request.h"
28 #include "net/url_request/url_request_context.h"
29 #include "net/url_request/url_request_test_util.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31 #include "third_party/icu/source/i18n/unicode/regex.h"
32 #include "webkit/browser/fileapi/external_mount_points.h"
33 #include "webkit/browser/fileapi/file_system_context.h"
34 #include "webkit/browser/fileapi/file_system_file_util.h"
35 #include "webkit/browser/fileapi/file_system_operation_context.h"
36 #include "webkit/browser/fileapi/file_system_url.h"
38 using fileapi::FileSystemContext;
39 using fileapi::FileSystemOperationContext;
40 using fileapi::FileSystemURL;
42 namespace content {
43 namespace {
45 // We always use the TEMPORARY FileSystem in this test.
46 const char kFileSystemURLPrefix[] = "filesystem:http://remote/temporary/";
48 const char kValidExternalMountPoint[] = "mnt_name";
50 // An auto mounter that will try to mount anything for |storage_domain| =
51 // "automount", but will only succeed for the mount point "mnt_name".
52 bool TestAutoMountForURLRequest(
53 const net::URLRequest* /*url_request*/,
54 const fileapi::FileSystemURL& filesystem_url,
55 const std::string& storage_domain,
56 const base::Callback<void(base::File::Error result)>& callback) {
57 if (storage_domain != "automount")
58 return false;
60 std::vector<base::FilePath::StringType> components;
61 filesystem_url.path().GetComponents(&components);
62 std::string mount_point = base::FilePath(components[0]).AsUTF8Unsafe();
64 if (mount_point == kValidExternalMountPoint) {
65 fileapi::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
66 kValidExternalMountPoint, fileapi::kFileSystemTypeTest,
67 fileapi::FileSystemMountOption(), base::FilePath());
68 callback.Run(base::File::FILE_OK);
69 } else {
70 callback.Run(base::File::FILE_ERROR_NOT_FOUND);
72 return true;
75 } // namespace
77 class FileSystemDirURLRequestJobTest : public testing::Test {
78 protected:
79 FileSystemDirURLRequestJobTest()
80 : weak_factory_(this) {
83 virtual void SetUp() OVERRIDE {
84 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
86 special_storage_policy_ = new MockSpecialStoragePolicy;
87 file_system_context_ = CreateFileSystemContextForTesting(
88 NULL, temp_dir_.path());
90 file_system_context_->OpenFileSystem(
91 GURL("http://remote/"), fileapi::kFileSystemTypeTemporary,
92 fileapi::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
93 base::Bind(&FileSystemDirURLRequestJobTest::OnOpenFileSystem,
94 weak_factory_.GetWeakPtr()));
95 base::RunLoop().RunUntilIdle();
97 net::URLRequest::Deprecated::RegisterProtocolFactory(
98 "filesystem", &FileSystemDirURLRequestJobFactory);
101 virtual void TearDown() OVERRIDE {
102 // NOTE: order matters, request must die before delegate
103 request_.reset(NULL);
104 delegate_.reset(NULL);
106 net::URLRequest::Deprecated::RegisterProtocolFactory("filesystem", NULL);
107 ClearUnusedJob();
110 void SetUpAutoMountContext(base::FilePath* mnt_point) {
111 *mnt_point = temp_dir_.path().AppendASCII("auto_mount_dir");
112 ASSERT_TRUE(base::CreateDirectory(*mnt_point));
114 ScopedVector<fileapi::FileSystemBackend> additional_providers;
115 additional_providers.push_back(new TestFileSystemBackend(
116 base::MessageLoopProxy::current().get(), *mnt_point));
118 std::vector<fileapi::URLRequestAutoMountHandler> handlers;
119 handlers.push_back(base::Bind(&TestAutoMountForURLRequest));
121 file_system_context_ = CreateFileSystemContextWithAutoMountersForTesting(
122 NULL, additional_providers.Pass(), handlers, temp_dir_.path());
125 void OnOpenFileSystem(const GURL& root_url,
126 const std::string& name,
127 base::File::Error result) {
128 ASSERT_EQ(base::File::FILE_OK, result);
131 void TestRequestHelper(const GURL& url, bool run_to_completion,
132 FileSystemContext* file_system_context) {
133 delegate_.reset(new net::TestDelegate());
134 delegate_->set_quit_on_redirect(true);
135 request_ = empty_context_.CreateRequest(
136 url, net::DEFAULT_PRIORITY, delegate_.get(), NULL);
137 job_ = new fileapi::FileSystemDirURLRequestJob(
138 request_.get(), NULL, url.GetOrigin().host(), file_system_context);
140 request_->Start();
141 ASSERT_TRUE(request_->is_pending()); // verify that we're starting async
142 if (run_to_completion)
143 base::MessageLoop::current()->Run();
146 void TestRequest(const GURL& url) {
147 TestRequestHelper(url, true, file_system_context_.get());
150 void TestRequestWithContext(const GURL& url,
151 FileSystemContext* file_system_context) {
152 TestRequestHelper(url, true, file_system_context);
155 void TestRequestNoRun(const GURL& url) {
156 TestRequestHelper(url, false, file_system_context_.get());
159 FileSystemURL CreateURL(const base::FilePath& file_path) {
160 return file_system_context_->CreateCrackedFileSystemURL(
161 GURL("http://remote"),
162 fileapi::kFileSystemTypeTemporary,
163 file_path);
166 FileSystemOperationContext* NewOperationContext() {
167 FileSystemOperationContext* context(
168 new FileSystemOperationContext(file_system_context_.get()));
169 context->set_allowed_bytes_growth(1024);
170 return context;
173 void CreateDirectory(const base::StringPiece& dir_name) {
174 base::FilePath path = base::FilePath().AppendASCII(dir_name);
175 scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
176 ASSERT_EQ(base::File::FILE_OK, file_util()->CreateDirectory(
177 context.get(),
178 CreateURL(path),
179 false /* exclusive */,
180 false /* recursive */));
183 void EnsureFileExists(const base::StringPiece file_name) {
184 base::FilePath path = base::FilePath().AppendASCII(file_name);
185 scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
186 ASSERT_EQ(base::File::FILE_OK, file_util()->EnsureFileExists(
187 context.get(), CreateURL(path), NULL));
190 void TruncateFile(const base::StringPiece file_name, int64 length) {
191 base::FilePath path = base::FilePath().AppendASCII(file_name);
192 scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
193 ASSERT_EQ(base::File::FILE_OK, file_util()->Truncate(
194 context.get(), CreateURL(path), length));
197 base::File::Error GetFileInfo(const base::FilePath& path,
198 base::File::Info* file_info,
199 base::FilePath* platform_file_path) {
200 scoped_ptr<FileSystemOperationContext> context(NewOperationContext());
201 return file_util()->GetFileInfo(context.get(),
202 CreateURL(path),
203 file_info, platform_file_path);
206 // If |size| is negative, the reported size is ignored.
207 void VerifyListingEntry(const std::string& entry_line,
208 const std::string& name,
209 const std::string& url,
210 bool is_directory,
211 int64 size) {
212 #define STR "([^\"]*)"
213 icu::UnicodeString pattern("^<script>addRow\\(\"" STR "\",\"" STR
214 "\",(0|1),\"" STR "\",\"" STR "\"\\);</script>");
215 #undef STR
216 icu::UnicodeString input(entry_line.c_str());
218 UErrorCode status = U_ZERO_ERROR;
219 icu::RegexMatcher match(pattern, input, 0, status);
221 EXPECT_TRUE(match.find());
222 EXPECT_EQ(5, match.groupCount());
223 EXPECT_EQ(icu::UnicodeString(name.c_str()), match.group(1, status));
224 EXPECT_EQ(icu::UnicodeString(url.c_str()), match.group(2, status));
225 EXPECT_EQ(icu::UnicodeString(is_directory ? "1" : "0"),
226 match.group(3, status));
227 if (size >= 0) {
228 icu::UnicodeString size_string(FormatBytesUnlocalized(size).c_str());
229 EXPECT_EQ(size_string, match.group(4, status));
232 base::Time date;
233 icu::UnicodeString date_ustr(match.group(5, status));
234 std::string date_str;
235 base::UTF16ToUTF8(date_ustr.getBuffer(), date_ustr.length(), &date_str);
236 EXPECT_TRUE(base::Time::FromString(date_str.c_str(), &date));
237 EXPECT_FALSE(date.is_null());
240 GURL CreateFileSystemURL(const std::string path) {
241 return GURL(kFileSystemURLPrefix + path);
244 static net::URLRequestJob* FileSystemDirURLRequestJobFactory(
245 net::URLRequest* request,
246 net::NetworkDelegate* network_delegate,
247 const std::string& scheme) {
248 DCHECK(job_);
249 net::URLRequestJob* temp = job_;
250 job_ = NULL;
251 return temp;
254 static void ClearUnusedJob() {
255 if (job_) {
256 scoped_refptr<net::URLRequestJob> deleter = job_;
257 job_ = NULL;
261 fileapi::FileSystemFileUtil* file_util() {
262 return file_system_context_->sandbox_delegate()->sync_file_util();
265 // Put the message loop at the top, so that it's the last thing deleted.
266 // Delete all MessageLoopProxy objects before the MessageLoop, to help prevent
267 // leaks caused by tasks posted during shutdown.
268 base::MessageLoopForIO message_loop_;
270 base::ScopedTempDir temp_dir_;
271 net::URLRequestContext empty_context_;
272 scoped_ptr<net::TestDelegate> delegate_;
273 scoped_ptr<net::URLRequest> request_;
274 scoped_refptr<MockSpecialStoragePolicy> special_storage_policy_;
275 scoped_refptr<FileSystemContext> file_system_context_;
276 base::WeakPtrFactory<FileSystemDirURLRequestJobTest> weak_factory_;
278 static net::URLRequestJob* job_;
281 // static
282 net::URLRequestJob* FileSystemDirURLRequestJobTest::job_ = NULL;
284 namespace {
286 TEST_F(FileSystemDirURLRequestJobTest, DirectoryListing) {
287 CreateDirectory("foo");
288 CreateDirectory("foo/bar");
289 CreateDirectory("foo/bar/baz");
291 EnsureFileExists("foo/bar/hoge");
292 TruncateFile("foo/bar/hoge", 10);
294 TestRequest(CreateFileSystemURL("foo/bar/"));
296 ASSERT_FALSE(request_->is_pending());
297 EXPECT_EQ(1, delegate_->response_started_count());
298 EXPECT_FALSE(delegate_->received_data_before_response());
299 EXPECT_GT(delegate_->bytes_received(), 0);
301 std::istringstream in(delegate_->data_received());
302 std::string line;
303 EXPECT_TRUE(!!std::getline(in, line));
305 #if defined(OS_WIN)
306 EXPECT_EQ("<script>start(\"foo\\\\bar\");</script>", line);
307 #elif defined(OS_POSIX)
308 EXPECT_EQ("<script>start(\"/foo/bar\");</script>", line);
309 #endif
311 EXPECT_TRUE(!!std::getline(in, line));
312 VerifyListingEntry(line, "hoge", "hoge", false, 10);
314 EXPECT_TRUE(!!std::getline(in, line));
315 VerifyListingEntry(line, "baz", "baz", true, 0);
316 EXPECT_FALSE(!!std::getline(in, line));
319 TEST_F(FileSystemDirURLRequestJobTest, InvalidURL) {
320 TestRequest(GURL("filesystem:/foo/bar/baz"));
321 ASSERT_FALSE(request_->is_pending());
322 EXPECT_TRUE(delegate_->request_failed());
323 ASSERT_FALSE(request_->status().is_success());
324 EXPECT_EQ(net::ERR_INVALID_URL, request_->status().error());
327 TEST_F(FileSystemDirURLRequestJobTest, NoSuchRoot) {
328 TestRequest(GURL("filesystem:http://remote/persistent/somedir/"));
329 ASSERT_FALSE(request_->is_pending());
330 ASSERT_FALSE(request_->status().is_success());
331 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
334 TEST_F(FileSystemDirURLRequestJobTest, NoSuchDirectory) {
335 TestRequest(CreateFileSystemURL("somedir/"));
336 ASSERT_FALSE(request_->is_pending());
337 ASSERT_FALSE(request_->status().is_success());
338 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
341 TEST_F(FileSystemDirURLRequestJobTest, Cancel) {
342 CreateDirectory("foo");
343 TestRequestNoRun(CreateFileSystemURL("foo/"));
344 // Run StartAsync() and only StartAsync().
345 base::MessageLoop::current()->DeleteSoon(FROM_HERE, request_.release());
346 base::RunLoop().RunUntilIdle();
347 // If we get here, success! we didn't crash!
350 TEST_F(FileSystemDirURLRequestJobTest, Incognito) {
351 CreateDirectory("foo");
353 scoped_refptr<FileSystemContext> file_system_context =
354 CreateIncognitoFileSystemContextForTesting(NULL, temp_dir_.path());
356 TestRequestWithContext(CreateFileSystemURL("/"),
357 file_system_context.get());
358 ASSERT_FALSE(request_->is_pending());
359 ASSERT_TRUE(request_->status().is_success());
361 std::istringstream in(delegate_->data_received());
362 std::string line;
363 EXPECT_TRUE(!!std::getline(in, line));
364 EXPECT_FALSE(!!std::getline(in, line));
366 TestRequestWithContext(CreateFileSystemURL("foo"),
367 file_system_context.get());
368 ASSERT_FALSE(request_->is_pending());
369 ASSERT_FALSE(request_->status().is_success());
370 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
373 TEST_F(FileSystemDirURLRequestJobTest, AutoMountDirectoryListing) {
374 base::FilePath mnt_point;
375 SetUpAutoMountContext(&mnt_point);
376 ASSERT_TRUE(base::CreateDirectory(mnt_point));
377 ASSERT_TRUE(base::CreateDirectory(mnt_point.AppendASCII("foo")));
378 ASSERT_EQ(10,
379 base::WriteFile(mnt_point.AppendASCII("bar"), "1234567890", 10));
381 TestRequest(GURL("filesystem:http://automount/external/mnt_name"));
383 ASSERT_FALSE(request_->is_pending());
384 EXPECT_EQ(1, delegate_->response_started_count());
385 EXPECT_FALSE(delegate_->received_data_before_response());
386 EXPECT_GT(delegate_->bytes_received(), 0);
388 std::istringstream in(delegate_->data_received());
389 std::string line;
390 EXPECT_TRUE(!!std::getline(in, line)); // |line| contains the temp dir path.
392 // Result order is not guaranteed, so sort the results.
393 std::vector<std::string> listing_entries;
394 while (!!std::getline(in, line))
395 listing_entries.push_back(line);
397 ASSERT_EQ(2U, listing_entries.size());
398 std::sort(listing_entries.begin(), listing_entries.end());
399 VerifyListingEntry(listing_entries[0], "bar", "bar", false, 10);
400 VerifyListingEntry(listing_entries[1], "foo", "foo", true, -1);
402 ASSERT_TRUE(
403 fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
404 kValidExternalMountPoint));
407 TEST_F(FileSystemDirURLRequestJobTest, AutoMountInvalidRoot) {
408 base::FilePath mnt_point;
409 SetUpAutoMountContext(&mnt_point);
410 TestRequest(GURL("filesystem:http://automount/external/invalid"));
412 ASSERT_FALSE(request_->is_pending());
413 ASSERT_FALSE(request_->status().is_success());
414 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
416 ASSERT_FALSE(
417 fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
418 "invalid"));
421 TEST_F(FileSystemDirURLRequestJobTest, AutoMountNoHandler) {
422 base::FilePath mnt_point;
423 SetUpAutoMountContext(&mnt_point);
424 TestRequest(GURL("filesystem:http://noauto/external/mnt_name"));
426 ASSERT_FALSE(request_->is_pending());
427 ASSERT_FALSE(request_->status().is_success());
428 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error());
430 ASSERT_FALSE(
431 fileapi::ExternalMountPoints::GetSystemInstance()->RevokeFileSystem(
432 kValidExternalMountPoint));
435 } // namespace (anonymous)
436 } // namespace content