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 |