1 // Copyright 2014 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 "base/command_line.h" 6 #include "base/strings/string_util.h" 7 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/policy/cloud/policy_header_service_factory.h" 9 #include "chrome/browser/profiles/profile.h" 10 #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.h" 11 #include "chrome/browser/ui/browser.h" 12 #include "chrome/test/base/in_process_browser_test.h" 13 #include "chrome/test/base/ui_test_utils.h" 14 #include "components/policy/core/common/cloud/cloud_policy_constants.h" 15 #include "components/policy/core/common/cloud/policy_header_io_helper.h" 16 #include "components/policy/core/common/cloud/policy_header_service.h" 17 #include "components/policy/core/common/policy_switches.h" 18 #include "content/public/browser/resource_dispatcher_host.h" 19 #include "net/http/http_request_headers.h" 20 #include "net/test/embedded_test_server/embedded_test_server.h" 21 #include "net/test/embedded_test_server/http_request.h" 22 #include "net/test/embedded_test_server/http_response.h" 23 #include "net/url_request/url_request.h" 24 25 namespace { 26 static const char kTestPolicyHeader[] = "test_header"; 27 static const char kServerRedirectUrl[] = "/server-redirect"; 28 29 scoped_ptr<net::test_server::HttpResponse> HandleTestRequest( 30 const net::test_server::HttpRequest& request) { 31 if (StartsWithASCII(request.relative_url, kServerRedirectUrl, true)) { 32 // Extract the target URL and redirect there. 33 size_t query_string_pos = request.relative_url.find('?'); 34 std::string redirect_target = 35 request.relative_url.substr(query_string_pos + 1); 36 37 scoped_ptr<net::test_server::BasicHttpResponse> http_response( 38 new net::test_server::BasicHttpResponse); 39 http_response->set_code(net::HTTP_MOVED_PERMANENTLY); 40 http_response->AddCustomHeader("Location", redirect_target); 41 return http_response.PassAs<net::test_server::HttpResponse>(); 42 } else { 43 scoped_ptr<net::test_server::BasicHttpResponse> http_response( 44 new net::test_server::BasicHttpResponse); 45 http_response->set_code(net::HTTP_OK); 46 http_response->set_content("Success"); 47 return http_response.PassAs<net::test_server::HttpResponse>(); 48 } 49 } 50 51 class TestDispatcherHostDelegate : public ChromeResourceDispatcherHostDelegate { 52 public: 53 explicit TestDispatcherHostDelegate( 54 prerender::PrerenderTracker* prerender_tracker) 55 : ChromeResourceDispatcherHostDelegate(prerender_tracker) { 56 } 57 58 virtual ~TestDispatcherHostDelegate() {} 59 60 virtual void RequestBeginning( 61 net::URLRequest* request, 62 content::ResourceContext* resource_context, 63 appcache::AppCacheService* appcache_service, 64 ResourceType::Type resource_type, 65 int child_id, 66 int route_id, 67 ScopedVector<content::ResourceThrottle>* throttles) OVERRIDE { 68 ChromeResourceDispatcherHostDelegate::RequestBeginning( 69 request, 70 resource_context, 71 appcache_service, 72 resource_type, 73 child_id, 74 route_id, 75 throttles); 76 request_headers_.MergeFrom(request->extra_request_headers()); 77 } 78 79 virtual void OnRequestRedirected( 80 const GURL& redirect_url, 81 net::URLRequest* request, 82 content::ResourceContext* resource_context, 83 content::ResourceResponse* response) OVERRIDE { 84 ChromeResourceDispatcherHostDelegate::OnRequestRedirected( 85 redirect_url, 86 request, 87 resource_context, 88 response); 89 request_headers_.MergeFrom(request->extra_request_headers()); 90 } 91 92 net::HttpRequestHeaders request_headers_; 93 94 private: 95 DISALLOW_COPY_AND_ASSIGN(TestDispatcherHostDelegate); 96 }; 97 98 } // namespace 99 100 class ChromeResourceDispatcherHostDelegateBrowserTest : 101 public InProcessBrowserTest { 102 public: 103 ChromeResourceDispatcherHostDelegateBrowserTest() {} 104 105 virtual void SetUpOnMainThread() OVERRIDE { 106 InProcessBrowserTest::SetUpOnMainThread(); 107 // Hook navigations with our delegate. 108 dispatcher_host_delegate_.reset(new TestDispatcherHostDelegate( 109 g_browser_process->prerender_tracker())); 110 content::ResourceDispatcherHost::Get()->SetDelegate( 111 dispatcher_host_delegate_.get()); 112 113 embedded_test_server()->RegisterRequestHandler( 114 base::Bind(&HandleTestRequest)); 115 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); 116 // Tell chrome that this is our DM server. 117 dm_url_ = embedded_test_server()->GetURL("/DeviceManagement"); 118 119 // At this point, the Profile is already initialized and it's too 120 // late to set the DMServer URL via command line flags, so directly 121 // inject it to the PolicyHeaderIOHelper. 122 policy::PolicyHeaderService* policy_header_service = 123 policy::PolicyHeaderServiceFactory::GetForBrowserContext( 124 browser()->profile()); 125 std::vector<policy::PolicyHeaderIOHelper*> helpers = 126 policy_header_service->GetHelpersForTest(); 127 for (std::vector<policy::PolicyHeaderIOHelper*>::const_iterator it = 128 helpers.begin(); 129 it != helpers.end(); ++it) { 130 (*it)->SetServerURLForTest(dm_url_.spec()); 131 (*it)->UpdateHeader(kTestPolicyHeader); 132 } 133 } 134 135 virtual void CleanUpOnMainThread() OVERRIDE { 136 content::ResourceDispatcherHost::Get()->SetDelegate(NULL); 137 dispatcher_host_delegate_.reset(); 138 InProcessBrowserTest::CleanUpOnMainThread(); 139 } 140 141 protected: 142 // The fake URL for DMServer we are using. 143 GURL dm_url_; 144 scoped_ptr<TestDispatcherHostDelegate> dispatcher_host_delegate_; 145 146 private: 147 DISALLOW_COPY_AND_ASSIGN(ChromeResourceDispatcherHostDelegateBrowserTest); 148 }; 149 150 151 IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest, 152 NoPolicyHeader) { 153 // When fetching non-DMServer URLs, we should not add a policy header to the 154 // request. 155 DCHECK(!embedded_test_server()->base_url().spec().empty()); 156 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url()); 157 ASSERT_FALSE(dispatcher_host_delegate_->request_headers_.HasHeader( 158 policy::kChromePolicyHeader)); 159 } 160 161 IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest, 162 PolicyHeader) { 163 // When fetching a DMServer URL, we should add a policy header to the 164 // request. 165 ui_test_utils::NavigateToURL(browser(), dm_url_); 166 std::string value; 167 ASSERT_TRUE(dispatcher_host_delegate_->request_headers_.GetHeader( 168 policy::kChromePolicyHeader, &value)); 169 ASSERT_EQ(kTestPolicyHeader, value); 170 } 171 172 IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest, 173 PolicyHeaderForRedirect) { 174 175 // Build up a URL that results in a redirect to the DMServer URL to make 176 // sure the policy header is still added. 177 std::string redirect_url; 178 redirect_url += kServerRedirectUrl; 179 redirect_url += "?"; 180 redirect_url += dm_url_.spec(); 181 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL( 182 redirect_url)); 183 std::string value; 184 ASSERT_TRUE(dispatcher_host_delegate_->request_headers_.GetHeader( 185 policy::kChromePolicyHeader, &value)); 186 ASSERT_EQ(kTestPolicyHeader, value); 187 } 188