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 "chrome/browser/chromeos/drive/drive_url_request_job.h" 6 7 #include "base/bind.h" 8 #include "base/memory/ref_counted.h" 9 #include "base/memory/scoped_ptr.h" 10 #include "base/run_loop.h" 11 #include "base/sequenced_task_runner.h" 12 #include "base/threading/sequenced_worker_pool.h" 13 #include "base/threading/thread.h" 14 #include "chrome/browser/chromeos/drive/drive_file_stream_reader.h" 15 #include "chrome/browser/chromeos/drive/fake_file_system.h" 16 #include "chrome/browser/chromeos/drive/file_system_util.h" 17 #include "chrome/browser/chromeos/drive/test_util.h" 18 #include "chrome/browser/drive/fake_drive_service.h" 19 #include "chrome/browser/drive/test_util.h" 20 #include "chrome/common/url_constants.h" 21 #include "content/public/browser/browser_thread.h" 22 #include "content/public/test/test_browser_thread_bundle.h" 23 #include "google_apis/drive/test_util.h" 24 #include "net/base/request_priority.h" 25 #include "net/base/test_completion_callback.h" 26 #include "net/http/http_byte_range.h" 27 #include "net/url_request/url_request_test_util.h" 28 #include "testing/gtest/include/gtest/gtest.h" 29 #include "url/gurl.h" 30 31 namespace drive { 32 namespace { 33 34 // A simple URLRequestJobFactory implementation to create DriveURLRequestJob. 35 class TestURLRequestJobFactory : public net::URLRequestJobFactory { 36 public: 37 TestURLRequestJobFactory( 38 const DriveURLRequestJob::FileSystemGetter& file_system_getter, 39 base::SequencedTaskRunner* sequenced_task_runner) 40 : file_system_getter_(file_system_getter), 41 sequenced_task_runner_(sequenced_task_runner) { 42 } 43 44 virtual ~TestURLRequestJobFactory() {} 45 46 // net::URLRequestJobFactory override: 47 virtual net::URLRequestJob* MaybeCreateJobWithProtocolHandler( 48 const std::string& scheme, 49 net::URLRequest* request, 50 net::NetworkDelegate* network_delegate) const OVERRIDE { 51 return new DriveURLRequestJob(file_system_getter_, 52 sequenced_task_runner_.get(), 53 request, 54 network_delegate); 55 } 56 57 virtual bool IsHandledProtocol(const std::string& scheme) const OVERRIDE { 58 return scheme == chrome::kDriveScheme; 59 } 60 61 virtual bool IsHandledURL(const GURL& url) const OVERRIDE { 62 return url.is_valid() && IsHandledProtocol(url.scheme()); 63 } 64 65 virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE { 66 return true; 67 } 68 69 private: 70 const DriveURLRequestJob::FileSystemGetter file_system_getter_; 71 scoped_refptr<base::SequencedTaskRunner> sequenced_task_runner_; 72 73 DISALLOW_COPY_AND_ASSIGN(TestURLRequestJobFactory); 74 }; 75 76 class TestDelegate : public net::TestDelegate { 77 public: 78 TestDelegate() {} 79 80 const GURL& redirect_url() const { return redirect_url_; } 81 82 // net::TestDelegate override. 83 virtual void OnReceivedRedirect(net::URLRequest* request, 84 const GURL& new_url, 85 bool* defer_redirect) OVERRIDE{ 86 redirect_url_ = new_url; 87 net::TestDelegate::OnReceivedRedirect(request, new_url, defer_redirect); 88 } 89 90 private: 91 GURL redirect_url_; 92 93 DISALLOW_COPY_AND_ASSIGN(TestDelegate); 94 }; 95 96 } // namespace 97 98 class DriveURLRequestJobTest : public testing::Test { 99 protected: 100 DriveURLRequestJobTest() 101 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP) { 102 } 103 104 virtual ~DriveURLRequestJobTest() { 105 } 106 107 virtual void SetUp() OVERRIDE { 108 // Initialize FakeDriveService. 109 fake_drive_service_.reset(new FakeDriveService); 110 ASSERT_TRUE(test_util::SetUpTestEntries(fake_drive_service_.get())); 111 112 // Initialize FakeFileSystem. 113 fake_file_system_.reset( 114 new test_util::FakeFileSystem(fake_drive_service_.get())); 115 116 scoped_refptr<base::SequencedWorkerPool> blocking_pool = 117 content::BrowserThread::GetBlockingPool(); 118 test_network_delegate_.reset(new net::TestNetworkDelegate); 119 test_url_request_job_factory_.reset(new TestURLRequestJobFactory( 120 base::Bind(&DriveURLRequestJobTest::GetFileSystem, 121 base::Unretained(this)), 122 blocking_pool->GetSequencedTaskRunner( 123 blocking_pool->GetSequenceToken()).get())); 124 url_request_context_.reset(new net::URLRequestContext()); 125 url_request_context_->set_job_factory(test_url_request_job_factory_.get()); 126 url_request_context_->set_network_delegate(test_network_delegate_.get()); 127 test_delegate_.reset(new TestDelegate); 128 } 129 130 FileSystemInterface* GetFileSystem() { 131 return fake_file_system_.get(); 132 } 133 134 bool ReadDriveFileSync( 135 const base::FilePath& file_path, std::string* out_content) { 136 scoped_ptr<base::Thread> worker_thread( 137 new base::Thread("ReadDriveFileSync")); 138 if (!worker_thread->Start()) 139 return false; 140 141 scoped_ptr<DriveFileStreamReader> reader(new DriveFileStreamReader( 142 base::Bind(&DriveURLRequestJobTest::GetFileSystem, 143 base::Unretained(this)), 144 worker_thread->message_loop_proxy().get())); 145 int error = net::ERR_FAILED; 146 scoped_ptr<ResourceEntry> entry; 147 { 148 base::RunLoop run_loop; 149 reader->Initialize( 150 file_path, 151 net::HttpByteRange(), 152 google_apis::test_util::CreateQuitCallback( 153 &run_loop, 154 google_apis::test_util::CreateCopyResultCallback( 155 &error, &entry))); 156 run_loop.Run(); 157 } 158 if (error != net::OK || !entry) 159 return false; 160 161 // Read data from the reader. 162 std::string content; 163 if (test_util::ReadAllData(reader.get(), &content) != net::OK) 164 return false; 165 166 if (static_cast<size_t>(entry->file_info().size()) != content.size()) 167 return false; 168 169 *out_content = content; 170 return true; 171 } 172 173 content::TestBrowserThreadBundle thread_bundle_; 174 175 scoped_ptr<FakeDriveService> fake_drive_service_; 176 scoped_ptr<test_util::FakeFileSystem> fake_file_system_; 177 178 scoped_ptr<net::TestNetworkDelegate> test_network_delegate_; 179 scoped_ptr<TestURLRequestJobFactory> test_url_request_job_factory_; 180 scoped_ptr<net::URLRequestContext> url_request_context_; 181 scoped_ptr<TestDelegate> test_delegate_; 182 }; 183 184 TEST_F(DriveURLRequestJobTest, NonGetMethod) { 185 net::URLRequest request(GURL("drive:drive/root/File 1.txt"), 186 net::DEFAULT_PRIORITY, 187 test_delegate_.get(), 188 url_request_context_.get()); 189 request.set_method("POST"); // Set non "GET" method. 190 request.Start(); 191 192 base::RunLoop().Run(); 193 194 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); 195 EXPECT_EQ(net::ERR_METHOD_NOT_SUPPORTED, request.status().error()); 196 } 197 198 TEST_F(DriveURLRequestJobTest, RegularFile) { 199 const GURL kTestUrl("drive:drive/root/File 1.txt"); 200 const base::FilePath kTestFilePath("drive/root/File 1.txt"); 201 202 // For the first time, the file should be fetched from the server. 203 { 204 net::URLRequest request(kTestUrl, 205 net::DEFAULT_PRIORITY, 206 test_delegate_.get(), 207 url_request_context_.get()); 208 request.Start(); 209 210 base::RunLoop().Run(); 211 212 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status()); 213 // It looks weird, but the mime type for the "File 1.txt" is "audio/mpeg" 214 // on the server. 215 std::string mime_type; 216 request.GetMimeType(&mime_type); 217 EXPECT_EQ("audio/mpeg", mime_type); 218 219 // Reading file must be done after |request| runs, otherwise 220 // it'll create a local cache file, and we cannot test correctly. 221 std::string expected_data; 222 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data)); 223 EXPECT_EQ(expected_data, test_delegate_->data_received()); 224 } 225 226 // For the second time, the locally cached file should be used. 227 // The caching emulation is done by FakeFileSystem. 228 { 229 test_delegate_.reset(new TestDelegate); 230 net::URLRequest request(GURL("drive:drive/root/File 1.txt"), 231 net::DEFAULT_PRIORITY, 232 test_delegate_.get(), 233 url_request_context_.get()); 234 request.Start(); 235 236 base::RunLoop().Run(); 237 238 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status()); 239 std::string mime_type; 240 request.GetMimeType(&mime_type); 241 EXPECT_EQ("audio/mpeg", mime_type); 242 243 std::string expected_data; 244 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data)); 245 EXPECT_EQ(expected_data, test_delegate_->data_received()); 246 } 247 } 248 249 TEST_F(DriveURLRequestJobTest, HostedDocument) { 250 // Open a gdoc file. 251 test_delegate_->set_quit_on_redirect(true); 252 net::URLRequest request( 253 GURL("drive:drive/root/Document 1 excludeDir-test.gdoc"), 254 net::DEFAULT_PRIORITY, 255 test_delegate_.get(), 256 url_request_context_.get()); 257 request.Start(); 258 259 base::RunLoop().Run(); 260 261 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status()); 262 // Make sure that a hosted document triggers redirection. 263 EXPECT_TRUE(request.is_redirecting()); 264 EXPECT_TRUE(test_delegate_->redirect_url().is_valid()); 265 } 266 267 TEST_F(DriveURLRequestJobTest, RootDirectory) { 268 net::URLRequest request(GURL("drive:drive/root"), 269 net::DEFAULT_PRIORITY, 270 test_delegate_.get(), 271 url_request_context_.get()); 272 request.Start(); 273 274 base::RunLoop().Run(); 275 276 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); 277 EXPECT_EQ(net::ERR_FAILED, request.status().error()); 278 } 279 280 TEST_F(DriveURLRequestJobTest, Directory) { 281 net::URLRequest request(GURL("drive:drive/root/Directory 1"), 282 net::DEFAULT_PRIORITY, 283 test_delegate_.get(), 284 url_request_context_.get()); 285 request.Start(); 286 287 base::RunLoop().Run(); 288 289 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); 290 EXPECT_EQ(net::ERR_FAILED, request.status().error()); 291 } 292 293 TEST_F(DriveURLRequestJobTest, NonExistingFile) { 294 net::URLRequest request(GURL("drive:drive/root/non-existing-file.txt"), 295 net::DEFAULT_PRIORITY, 296 test_delegate_.get(), 297 url_request_context_.get()); 298 request.Start(); 299 300 base::RunLoop().Run(); 301 302 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); 303 EXPECT_EQ(net::ERR_FILE_NOT_FOUND, request.status().error()); 304 } 305 306 TEST_F(DriveURLRequestJobTest, WrongFormat) { 307 net::URLRequest request(GURL("drive:"), 308 net::DEFAULT_PRIORITY, 309 test_delegate_.get(), 310 url_request_context_.get()); 311 request.Start(); 312 313 base::RunLoop().Run(); 314 315 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); 316 EXPECT_EQ(net::ERR_INVALID_URL, request.status().error()); 317 } 318 319 TEST_F(DriveURLRequestJobTest, Cancel) { 320 net::URLRequest request(GURL("drive:drive/root/File 1.txt"), 321 net::DEFAULT_PRIORITY, 322 test_delegate_.get(), 323 url_request_context_.get()); 324 325 // Start the request, and cancel it immediately after it. 326 request.Start(); 327 request.Cancel(); 328 329 base::RunLoop().Run(); 330 331 EXPECT_EQ(net::URLRequestStatus::CANCELED, request.status().status()); 332 } 333 334 TEST_F(DriveURLRequestJobTest, RangeHeader) { 335 const GURL kTestUrl("drive:drive/root/File 1.txt"); 336 const base::FilePath kTestFilePath("drive/root/File 1.txt"); 337 338 net::URLRequest request(kTestUrl, 339 net::DEFAULT_PRIORITY, 340 test_delegate_.get(), 341 url_request_context_.get()); 342 343 // Set range header. 344 request.SetExtraRequestHeaderByName( 345 "Range", "bytes=3-5", false /* overwrite */); 346 request.Start(); 347 348 base::RunLoop().Run(); 349 350 EXPECT_EQ(net::URLRequestStatus::SUCCESS, request.status().status()); 351 352 // Reading file must be done after |request| runs, otherwise 353 // it'll create a local cache file, and we cannot test correctly. 354 std::string expected_data; 355 ASSERT_TRUE(ReadDriveFileSync(kTestFilePath, &expected_data)); 356 EXPECT_EQ(expected_data.substr(3, 3), test_delegate_->data_received()); 357 } 358 359 TEST_F(DriveURLRequestJobTest, WrongRangeHeader) { 360 const GURL kTestUrl("drive:drive/root/File 1.txt"); 361 362 net::URLRequest request(kTestUrl, 363 net::DEFAULT_PRIORITY, 364 test_delegate_.get(), 365 url_request_context_.get()); 366 367 // Set range header. 368 request.SetExtraRequestHeaderByName( 369 "Range", "Wrong Range Header Value", false /* overwrite */); 370 request.Start(); 371 372 base::RunLoop().Run(); 373 374 EXPECT_EQ(net::URLRequestStatus::FAILED, request.status().status()); 375 EXPECT_EQ(net::ERR_REQUEST_RANGE_NOT_SATISFIABLE, request.status().error()); 376 } 377 378 } // namespace drive 379