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