// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include #include #include "base/at_exit.h" #include "base/message_loop.h" #include "chrome/browser/chrome_plugin_service_filter.h" #include "chrome/browser/chromeos/gview_request_interceptor.h" #include "chrome/browser/plugins/plugin_prefs.h" #include "chrome/browser/plugins/plugin_prefs_factory.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/testing_pref_service.h" #include "chrome/test/base/testing_profile.h" #include "content/public/browser/plugin_service.h" #include "content/public/browser/resource_request_info.h" #include "content/public/test/mock_resource_context.h" #include "content/public/test/test_browser_thread.h" #include "net/base/load_flags.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_job.h" #include "net/url_request/url_request_job_factory.h" #include "net/url_request/url_request_job_factory_impl.h" #include "net/url_request/url_request_test_job.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" #include "webkit/plugins/npapi/mock_plugin_list.h" using content::BrowserThread; using content::PluginService; namespace chromeos { namespace { const char kPdfUrl[] = "http://foo.com/file.pdf"; const char kPptUrl[] = "http://foo.com/file.ppt"; const char kHtmlUrl[] = "http://foo.com/index.html"; const char kPdfBlob[] = "blob:blobinternal:///d17c4eef-28e7-42bd-bafa-78d5cb8"; const char kPdfUrlIntercepted[] = "http://docs.google.com/gview?url=http%3A//foo.com/file.pdf"; const char kPptUrlIntercepted[] = "http://docs.google.com/gview?url=http%3A//foo.com/file.ppt"; void AssertPluginEnabled(bool did_enable) { ASSERT_TRUE(did_enable); MessageLoop::current()->QuitWhenIdle(); } class GViewURLRequestTestJob : public net::URLRequestTestJob { public: GViewURLRequestTestJob(net::URLRequest* request, net::NetworkDelegate* network_delegate) : net::URLRequestTestJob(request, network_delegate, true) { } virtual bool GetMimeType(std::string* mime_type) const { // During the course of a single test, two URLRequestJobs are // created -- the first is for the viewable document URL, and the // second is for the rediected URL. In order to test the // interceptor, the mime type of the first request must be one of // the supported viewable mime types. So when the net::URLRequestJob // is a request for one of the test URLs that point to viewable // content, return an appropraite mime type. Otherwise, return // "text/html". const GURL& request_url = request_->url(); if (request_url == GURL(kPdfUrl) || request_url == GURL(kPdfBlob)) { *mime_type = "application/pdf"; } else if (request_url == GURL(kPptUrl)) { *mime_type = "application/vnd.ms-powerpoint"; } else { *mime_type = "text/html"; } return true; } private: ~GViewURLRequestTestJob() {} }; class GViewRequestProtocolFactory : public net::URLRequestJobFactory::ProtocolHandler { public: GViewRequestProtocolFactory() {} virtual ~GViewRequestProtocolFactory() {} virtual net::URLRequestJob* MaybeCreateJob( net::URLRequest* request, net::NetworkDelegate* network_delegate) const { return new GViewURLRequestTestJob(request, network_delegate); } }; class GViewRequestInterceptorTest : public testing::Test { public: GViewRequestInterceptorTest() : ui_thread_(BrowserThread::UI, &message_loop_), file_thread_(BrowserThread::FILE, &message_loop_), io_thread_(BrowserThread::IO, &message_loop_) {} virtual void SetUp() { net::URLRequestContext* request_context = resource_context_.GetRequestContext(); old_factory_ = request_context->job_factory(); job_factory_.SetProtocolHandler("http", new GViewRequestProtocolFactory); job_factory_.AddInterceptor(new GViewRequestInterceptor); request_context->set_job_factory(&job_factory_); plugin_prefs_ = PluginPrefs::GetForTestingProfile(&profile_); PluginPrefsFactory::GetInstance()->RegisterUserPrefsOnProfile(&profile_); ChromePluginServiceFilter* filter = ChromePluginServiceFilter::GetInstance(); filter->RegisterResourceContext(plugin_prefs_, &resource_context_); PluginService::GetInstance()->SetFilter(filter); ASSERT_TRUE(PathService::Get(chrome::FILE_PDF_PLUGIN, &pdf_path_)); PluginService::GetInstance()->SetPluginListForTesting(&plugin_list_); PluginService::GetInstance()->Init(); } virtual void TearDown() { plugin_prefs_->ShutdownOnUIThread(); net::URLRequestContext* request_context = resource_context_.GetRequestContext(); request_context->set_job_factory(old_factory_); ChromePluginServiceFilter* filter = ChromePluginServiceFilter::GetInstance(); filter->UnregisterResourceContext(&resource_context_); PluginService::GetInstance()->SetFilter(NULL); } void RegisterPDFPlugin() { webkit::WebPluginInfo info; info.path = pdf_path_; plugin_list_.AddPluginToLoad(info); plugin_list_.RefreshPlugins(); } void UnregisterPDFPlugin() { plugin_list_.ClearPluginsToLoad(); plugin_list_.RefreshPlugins(); } void SetPDFPluginLoadedState(bool want_loaded) { webkit::WebPluginInfo info; bool is_loaded = PluginService::GetInstance()->GetPluginInfoByPath( pdf_path_, &info); if (is_loaded == want_loaded) return; if (want_loaded) { // This "loads" the plug-in even if it's not present on the // system - which is OK since we don't actually use it, just // need it to be "enabled" for the test. RegisterPDFPlugin(); } else { UnregisterPDFPlugin(); } is_loaded = PluginService::GetInstance()->GetPluginInfoByPath( pdf_path_, &info); ASSERT_EQ(want_loaded, is_loaded); } void SetupRequest(net::URLRequest* request) { content::ResourceRequestInfo::AllocateForTesting(request, ResourceType::MAIN_FRAME, &resource_context_, -1, -1); } protected: base::ShadowingAtExitManager at_exit_manager_; // Deletes PluginService. MessageLoopForIO message_loop_; content::TestBrowserThread ui_thread_; content::TestBrowserThread file_thread_; content::TestBrowserThread io_thread_; webkit::npapi::MockPluginList plugin_list_; TestingProfile profile_; scoped_refptr plugin_prefs_; net::URLRequestJobFactoryImpl job_factory_; const net::URLRequestJobFactory* old_factory_; TestDelegate test_delegate_; FilePath pdf_path_; content::MockResourceContext resource_context_; }; TEST_F(GViewRequestInterceptorTest, DoNotInterceptHtml) { net::URLRequest request( GURL(kHtmlUrl), &test_delegate_, resource_context_.GetRequestContext()); SetupRequest(&request); request.Start(); MessageLoop::current()->Run(); EXPECT_EQ(0, test_delegate_.received_redirect_count()); EXPECT_EQ(GURL(kHtmlUrl), request.url()); } TEST_F(GViewRequestInterceptorTest, DoNotInterceptDownload) { net::URLRequest request( GURL(kPdfUrl), &test_delegate_, resource_context_.GetRequestContext()); SetupRequest(&request); request.set_load_flags(net::LOAD_IS_DOWNLOAD); request.Start(); MessageLoop::current()->Run(); EXPECT_EQ(0, test_delegate_.received_redirect_count()); EXPECT_EQ(GURL(kPdfUrl), request.url()); } TEST_F(GViewRequestInterceptorTest, DoNotInterceptPdfWhenEnabled) { ASSERT_NO_FATAL_FAILURE(SetPDFPluginLoadedState(true)); plugin_prefs_->EnablePlugin(true, pdf_path_, base::Bind(&AssertPluginEnabled)); MessageLoop::current()->Run(); net::URLRequest request( GURL(kPdfUrl), &test_delegate_, resource_context_.GetRequestContext()); SetupRequest(&request); request.Start(); MessageLoop::current()->Run(); EXPECT_EQ(0, test_delegate_.received_redirect_count()); EXPECT_EQ(GURL(kPdfUrl), request.url()); } TEST_F(GViewRequestInterceptorTest, InterceptPdfWhenDisabled) { ASSERT_NO_FATAL_FAILURE(SetPDFPluginLoadedState(true)); plugin_prefs_->EnablePlugin(false, pdf_path_, base::Bind(&AssertPluginEnabled)); MessageLoop::current()->Run(); net::URLRequest request( GURL(kPdfUrl), &test_delegate_, resource_context_.GetRequestContext()); SetupRequest(&request); request.Start(); MessageLoop::current()->Run(); EXPECT_EQ(1, test_delegate_.received_redirect_count()); EXPECT_EQ(GURL(kPdfUrlIntercepted), request.url()); } #if !defined(GOOGLE_CHROME_BUILD) // Official builds have pdf plugin by default, and we cannot unload it, so the // test fails. Since pdf plugin is always present, we don't need to run this // test. TEST_F(GViewRequestInterceptorTest, InterceptPdfWithNoPlugin) { ASSERT_NO_FATAL_FAILURE(SetPDFPluginLoadedState(false)); net::URLRequest request( GURL(kPdfUrl), &test_delegate_, resource_context_.GetRequestContext()); SetupRequest(&request); request.Start(); MessageLoop::current()->Run(); EXPECT_EQ(1, test_delegate_.received_redirect_count()); EXPECT_EQ(GURL(kPdfUrlIntercepted), request.url()); } #endif TEST_F(GViewRequestInterceptorTest, InterceptPowerpoint) { net::URLRequest request( GURL(kPptUrl), &test_delegate_, resource_context_.GetRequestContext()); SetupRequest(&request); request.Start(); MessageLoop::current()->Run(); EXPECT_EQ(1, test_delegate_.received_redirect_count()); EXPECT_EQ(GURL(kPptUrlIntercepted), request.url()); } TEST_F(GViewRequestInterceptorTest, DoNotInterceptPost) { ASSERT_NO_FATAL_FAILURE(SetPDFPluginLoadedState(false)); net::URLRequest request( GURL(kPdfUrl), &test_delegate_, resource_context_.GetRequestContext()); SetupRequest(&request); request.set_method("POST"); request.Start(); MessageLoop::current()->Run(); EXPECT_EQ(0, test_delegate_.received_redirect_count()); EXPECT_EQ(GURL(kPdfUrl), request.url()); } TEST_F(GViewRequestInterceptorTest, DoNotInterceptBlob) { ASSERT_NO_FATAL_FAILURE(SetPDFPluginLoadedState(false)); net::URLRequest request( GURL(kPdfBlob), &test_delegate_, resource_context_.GetRequestContext()); SetupRequest(&request); request.Start(); MessageLoop::current()->Run(); EXPECT_EQ(0, test_delegate_.received_redirect_count()); EXPECT_EQ(GURL(kPdfBlob), request.url()); } } // namespace } // namespace chromeos