OLD | NEW |
| (Empty) |
1 // Copyright (c) 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. | |
4 | |
5 #include "webkit/browser/fileapi/file_system_url_request_job.h" | |
6 | |
7 #include <string> | |
8 | |
9 #include "base/bind.h" | |
10 #include "base/file_util.h" | |
11 #include "base/files/file_path.h" | |
12 #include "base/files/scoped_temp_dir.h" | |
13 #include "base/format_macros.h" | |
14 #include "base/memory/weak_ptr.h" | |
15 #include "base/message_loop/message_loop.h" | |
16 #include "base/message_loop/message_loop_proxy.h" | |
17 #include "base/platform_file.h" | |
18 #include "base/rand_util.h" | |
19 #include "base/run_loop.h" | |
20 #include "base/strings/string_piece.h" | |
21 #include "base/strings/stringprintf.h" | |
22 #include "base/strings/utf_string_conversions.h" | |
23 #include "net/base/load_flags.h" | |
24 #include "net/base/mime_util.h" | |
25 #include "net/base/net_errors.h" | |
26 #include "net/base/net_util.h" | |
27 #include "net/http/http_request_headers.h" | |
28 #include "net/url_request/url_request.h" | |
29 #include "net/url_request/url_request_context.h" | |
30 #include "net/url_request/url_request_test_util.h" | |
31 #include "testing/gtest/include/gtest/gtest.h" | |
32 #include "webkit/browser/fileapi/async_file_test_helper.h" | |
33 #include "webkit/browser/fileapi/external_mount_points.h" | |
34 #include "webkit/browser/fileapi/file_system_context.h" | |
35 #include "webkit/browser/fileapi/file_system_file_util.h" | |
36 #include "webkit/browser/fileapi/mock_file_system_context.h" | |
37 | |
38 namespace fileapi { | |
39 namespace { | |
40 | |
41 // We always use the TEMPORARY FileSystem in this test. | |
42 const char kFileSystemURLPrefix[] = "filesystem:http://remote/temporary/"; | |
43 const char kTestFileData[] = "0123456789"; | |
44 | |
45 void FillBuffer(char* buffer, size_t len) { | |
46 base::RandBytes(buffer, len); | |
47 } | |
48 | |
49 } // namespace | |
50 | |
51 class FileSystemURLRequestJobTest : public testing::Test { | |
52 protected: | |
53 FileSystemURLRequestJobTest() : weak_factory_(this) { | |
54 } | |
55 | |
56 virtual void SetUp() OVERRIDE { | |
57 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); | |
58 | |
59 // We use the main thread so that we can get the root path synchronously. | |
60 // TODO(adamk): Run this on the FILE thread we've created as well. | |
61 file_system_context_ = | |
62 CreateFileSystemContextForTesting(NULL, temp_dir_.path()); | |
63 | |
64 file_system_context_->OpenFileSystem( | |
65 GURL("http://remote/"), kFileSystemTypeTemporary, | |
66 OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT, | |
67 base::Bind(&FileSystemURLRequestJobTest::OnOpenFileSystem, | |
68 weak_factory_.GetWeakPtr())); | |
69 base::RunLoop().RunUntilIdle(); | |
70 | |
71 net::URLRequest::Deprecated::RegisterProtocolFactory( | |
72 "filesystem", &FileSystemURLRequestJobFactory); | |
73 } | |
74 | |
75 virtual void TearDown() OVERRIDE { | |
76 net::URLRequest::Deprecated::RegisterProtocolFactory("filesystem", NULL); | |
77 ClearUnusedJob(); | |
78 if (pending_job_.get()) { | |
79 pending_job_->Kill(); | |
80 pending_job_ = NULL; | |
81 } | |
82 // FileReader posts a task to close the file in destructor. | |
83 base::RunLoop().RunUntilIdle(); | |
84 } | |
85 | |
86 void OnOpenFileSystem(base::PlatformFileError result, | |
87 const std::string& name, | |
88 const GURL& root_url) { | |
89 ASSERT_EQ(base::PLATFORM_FILE_OK, result); | |
90 } | |
91 | |
92 void TestRequestHelper(const GURL& url, | |
93 const net::HttpRequestHeaders* headers, | |
94 bool run_to_completion, | |
95 FileSystemContext* file_system_context) { | |
96 delegate_.reset(new net::TestDelegate()); | |
97 // Make delegate_ exit the MessageLoop when the request is done. | |
98 delegate_->set_quit_on_complete(true); | |
99 delegate_->set_quit_on_redirect(true); | |
100 request_.reset(empty_context_.CreateRequest(url, delegate_.get())); | |
101 if (headers) | |
102 request_->SetExtraRequestHeaders(*headers); | |
103 ASSERT_TRUE(!job_); | |
104 job_ = new FileSystemURLRequestJob( | |
105 request_.get(), NULL, file_system_context); | |
106 pending_job_ = job_; | |
107 | |
108 request_->Start(); | |
109 ASSERT_TRUE(request_->is_pending()); // verify that we're starting async | |
110 if (run_to_completion) | |
111 base::MessageLoop::current()->Run(); | |
112 } | |
113 | |
114 void TestRequest(const GURL& url) { | |
115 TestRequestHelper(url, NULL, true, file_system_context_.get()); | |
116 } | |
117 | |
118 void TestRequestWithContext(const GURL& url, | |
119 FileSystemContext* file_system_context) { | |
120 TestRequestHelper(url, NULL, true, file_system_context); | |
121 } | |
122 | |
123 void TestRequestWithHeaders(const GURL& url, | |
124 const net::HttpRequestHeaders* headers) { | |
125 TestRequestHelper(url, headers, true, file_system_context_.get()); | |
126 } | |
127 | |
128 void TestRequestNoRun(const GURL& url) { | |
129 TestRequestHelper(url, NULL, false, file_system_context_.get()); | |
130 } | |
131 | |
132 void CreateDirectory(const base::StringPiece& dir_name) { | |
133 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( | |
134 GURL("http://remote"), | |
135 kFileSystemTypeTemporary, | |
136 base::FilePath().AppendASCII(dir_name)); | |
137 ASSERT_EQ(base::PLATFORM_FILE_OK, AsyncFileTestHelper::CreateDirectory( | |
138 file_system_context_, url)); | |
139 } | |
140 | |
141 void WriteFile(const base::StringPiece& file_name, | |
142 const char* buf, int buf_size) { | |
143 FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL( | |
144 GURL("http://remote"), | |
145 kFileSystemTypeTemporary, | |
146 base::FilePath().AppendASCII(file_name)); | |
147 ASSERT_EQ(base::PLATFORM_FILE_OK, | |
148 AsyncFileTestHelper::CreateFileWithData( | |
149 file_system_context_, url, buf, buf_size)); | |
150 } | |
151 | |
152 GURL CreateFileSystemURL(const std::string& path) { | |
153 return GURL(kFileSystemURLPrefix + path); | |
154 } | |
155 | |
156 static net::URLRequestJob* FileSystemURLRequestJobFactory( | |
157 net::URLRequest* request, | |
158 net::NetworkDelegate* network_delegate, | |
159 const std::string& scheme) { | |
160 DCHECK(job_); | |
161 net::URLRequestJob* temp = job_; | |
162 job_ = NULL; | |
163 return temp; | |
164 } | |
165 | |
166 static void ClearUnusedJob() { | |
167 if (job_) { | |
168 scoped_refptr<net::URLRequestJob> deleter = job_; | |
169 job_ = NULL; | |
170 } | |
171 } | |
172 | |
173 // Put the message loop at the top, so that it's the last thing deleted. | |
174 base::MessageLoopForIO message_loop_; | |
175 | |
176 base::ScopedTempDir temp_dir_; | |
177 scoped_refptr<FileSystemContext> file_system_context_; | |
178 base::WeakPtrFactory<FileSystemURLRequestJobTest> weak_factory_; | |
179 | |
180 net::URLRequestContext empty_context_; | |
181 | |
182 // NOTE: order matters, request must die before delegate | |
183 scoped_ptr<net::TestDelegate> delegate_; | |
184 scoped_ptr<net::URLRequest> request_; | |
185 | |
186 scoped_refptr<net::URLRequestJob> pending_job_; | |
187 static net::URLRequestJob* job_; | |
188 }; | |
189 | |
190 // static | |
191 net::URLRequestJob* FileSystemURLRequestJobTest::job_ = NULL; | |
192 | |
193 namespace { | |
194 | |
195 TEST_F(FileSystemURLRequestJobTest, FileTest) { | |
196 WriteFile("file1.dat", kTestFileData, arraysize(kTestFileData) - 1); | |
197 TestRequest(CreateFileSystemURL("file1.dat")); | |
198 | |
199 ASSERT_FALSE(request_->is_pending()); | |
200 EXPECT_EQ(1, delegate_->response_started_count()); | |
201 EXPECT_FALSE(delegate_->received_data_before_response()); | |
202 EXPECT_EQ(kTestFileData, delegate_->data_received()); | |
203 EXPECT_EQ(200, request_->GetResponseCode()); | |
204 std::string cache_control; | |
205 request_->GetResponseHeaderByName("cache-control", &cache_control); | |
206 EXPECT_EQ("no-cache", cache_control); | |
207 } | |
208 | |
209 TEST_F(FileSystemURLRequestJobTest, FileTestFullSpecifiedRange) { | |
210 const size_t buffer_size = 4000; | |
211 scoped_ptr<char[]> buffer(new char[buffer_size]); | |
212 FillBuffer(buffer.get(), buffer_size); | |
213 WriteFile("bigfile", buffer.get(), buffer_size); | |
214 | |
215 const size_t first_byte_position = 500; | |
216 const size_t last_byte_position = buffer_size - first_byte_position; | |
217 std::string partial_buffer_string(buffer.get() + first_byte_position, | |
218 buffer.get() + last_byte_position + 1); | |
219 | |
220 net::HttpRequestHeaders headers; | |
221 headers.SetHeader(net::HttpRequestHeaders::kRange, | |
222 base::StringPrintf( | |
223 "bytes=%" PRIuS "-%" PRIuS, | |
224 first_byte_position, last_byte_position)); | |
225 TestRequestWithHeaders(CreateFileSystemURL("bigfile"), &headers); | |
226 | |
227 ASSERT_FALSE(request_->is_pending()); | |
228 EXPECT_EQ(1, delegate_->response_started_count()); | |
229 EXPECT_FALSE(delegate_->received_data_before_response()); | |
230 EXPECT_TRUE(partial_buffer_string == delegate_->data_received()); | |
231 } | |
232 | |
233 TEST_F(FileSystemURLRequestJobTest, FileTestHalfSpecifiedRange) { | |
234 const size_t buffer_size = 4000; | |
235 scoped_ptr<char[]> buffer(new char[buffer_size]); | |
236 FillBuffer(buffer.get(), buffer_size); | |
237 WriteFile("bigfile", buffer.get(), buffer_size); | |
238 | |
239 const size_t first_byte_position = 500; | |
240 std::string partial_buffer_string(buffer.get() + first_byte_position, | |
241 buffer.get() + buffer_size); | |
242 | |
243 net::HttpRequestHeaders headers; | |
244 headers.SetHeader(net::HttpRequestHeaders::kRange, | |
245 base::StringPrintf("bytes=%" PRIuS "-", | |
246 first_byte_position)); | |
247 TestRequestWithHeaders(CreateFileSystemURL("bigfile"), &headers); | |
248 ASSERT_FALSE(request_->is_pending()); | |
249 EXPECT_EQ(1, delegate_->response_started_count()); | |
250 EXPECT_FALSE(delegate_->received_data_before_response()); | |
251 // Don't use EXPECT_EQ, it will print out a lot of garbage if check failed. | |
252 EXPECT_TRUE(partial_buffer_string == delegate_->data_received()); | |
253 } | |
254 | |
255 | |
256 TEST_F(FileSystemURLRequestJobTest, FileTestMultipleRangesNotSupported) { | |
257 WriteFile("file1.dat", kTestFileData, arraysize(kTestFileData) - 1); | |
258 net::HttpRequestHeaders headers; | |
259 headers.SetHeader(net::HttpRequestHeaders::kRange, | |
260 "bytes=0-5,10-200,200-300"); | |
261 TestRequestWithHeaders(CreateFileSystemURL("file1.dat"), &headers); | |
262 EXPECT_TRUE(delegate_->request_failed()); | |
263 EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, | |
264 request_->status().error()); | |
265 } | |
266 | |
267 TEST_F(FileSystemURLRequestJobTest, RangeOutOfBounds) { | |
268 WriteFile("file1.dat", kTestFileData, arraysize(kTestFileData) - 1); | |
269 net::HttpRequestHeaders headers; | |
270 headers.SetHeader(net::HttpRequestHeaders::kRange, "bytes=500-1000"); | |
271 TestRequestWithHeaders(CreateFileSystemURL("file1.dat"), &headers); | |
272 | |
273 ASSERT_FALSE(request_->is_pending()); | |
274 EXPECT_TRUE(delegate_->request_failed()); | |
275 EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, | |
276 request_->status().error()); | |
277 } | |
278 | |
279 TEST_F(FileSystemURLRequestJobTest, FileDirRedirect) { | |
280 CreateDirectory("dir"); | |
281 TestRequest(CreateFileSystemURL("dir")); | |
282 | |
283 EXPECT_EQ(1, delegate_->received_redirect_count()); | |
284 EXPECT_TRUE(request_->status().is_success()); | |
285 EXPECT_FALSE(delegate_->request_failed()); | |
286 | |
287 // We've deferred the redirect; now cancel the request to avoid following it. | |
288 request_->Cancel(); | |
289 base::MessageLoop::current()->Run(); | |
290 } | |
291 | |
292 TEST_F(FileSystemURLRequestJobTest, InvalidURL) { | |
293 TestRequest(GURL("filesystem:/foo/bar/baz")); | |
294 ASSERT_FALSE(request_->is_pending()); | |
295 EXPECT_TRUE(delegate_->request_failed()); | |
296 EXPECT_EQ(net::ERR_INVALID_URL, request_->status().error()); | |
297 } | |
298 | |
299 TEST_F(FileSystemURLRequestJobTest, NoSuchRoot) { | |
300 TestRequest(GURL("filesystem:http://remote/persistent/somefile")); | |
301 ASSERT_FALSE(request_->is_pending()); | |
302 EXPECT_TRUE(delegate_->request_failed()); | |
303 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error()); | |
304 } | |
305 | |
306 TEST_F(FileSystemURLRequestJobTest, NoSuchFile) { | |
307 TestRequest(CreateFileSystemURL("somefile")); | |
308 ASSERT_FALSE(request_->is_pending()); | |
309 EXPECT_TRUE(delegate_->request_failed()); | |
310 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error()); | |
311 } | |
312 | |
313 TEST_F(FileSystemURLRequestJobTest, Cancel) { | |
314 WriteFile("file1.dat", kTestFileData, arraysize(kTestFileData) - 1); | |
315 TestRequestNoRun(CreateFileSystemURL("file1.dat")); | |
316 | |
317 // Run StartAsync() and only StartAsync(). | |
318 base::MessageLoop::current()->DeleteSoon(FROM_HERE, request_.release()); | |
319 base::RunLoop().RunUntilIdle(); | |
320 // If we get here, success! we didn't crash! | |
321 } | |
322 | |
323 TEST_F(FileSystemURLRequestJobTest, GetMimeType) { | |
324 const char kFilename[] = "hoge.html"; | |
325 | |
326 std::string mime_type_direct; | |
327 base::FilePath::StringType extension = | |
328 base::FilePath().AppendASCII(kFilename).Extension(); | |
329 if (!extension.empty()) | |
330 extension = extension.substr(1); | |
331 EXPECT_TRUE(net::GetWellKnownMimeTypeFromExtension( | |
332 extension, &mime_type_direct)); | |
333 | |
334 TestRequest(CreateFileSystemURL(kFilename)); | |
335 | |
336 std::string mime_type_from_job; | |
337 request_->GetMimeType(&mime_type_from_job); | |
338 EXPECT_EQ(mime_type_direct, mime_type_from_job); | |
339 } | |
340 | |
341 TEST_F(FileSystemURLRequestJobTest, Incognito) { | |
342 WriteFile("file", kTestFileData, arraysize(kTestFileData) - 1); | |
343 | |
344 // Creates a new filesystem context for incognito mode. | |
345 scoped_refptr<FileSystemContext> file_system_context = | |
346 CreateIncognitoFileSystemContextForTesting(NULL, temp_dir_.path()); | |
347 | |
348 // The request should return NOT_FOUND error if it's in incognito mode. | |
349 TestRequestWithContext(CreateFileSystemURL("file"), | |
350 file_system_context.get()); | |
351 ASSERT_FALSE(request_->is_pending()); | |
352 EXPECT_TRUE(delegate_->request_failed()); | |
353 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request_->status().error()); | |
354 | |
355 // Make sure it returns success with regular (non-incognito) context. | |
356 TestRequest(CreateFileSystemURL("file")); | |
357 ASSERT_FALSE(request_->is_pending()); | |
358 EXPECT_EQ(kTestFileData, delegate_->data_received()); | |
359 EXPECT_EQ(200, request_->GetResponseCode()); | |
360 } | |
361 | |
362 } // namespace | |
363 } // namespace fileapi | |
OLD | NEW |