OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate. h" | 5 #include "chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate. h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <utility> | 10 #include <utility> |
11 #include <vector> | |
11 | 12 |
12 #include "base/command_line.h" | 13 #include "base/command_line.h" |
13 #include "base/macros.h" | 14 #include "base/macros.h" |
15 #include "base/path_service.h" | |
16 #include "base/stl_util.h" | |
14 #include "base/strings/string_util.h" | 17 #include "base/strings/string_util.h" |
18 #include "base/test/scoped_command_line.h" | |
15 #include "chrome/browser/browser_process.h" | 19 #include "chrome/browser/browser_process.h" |
16 #include "chrome/browser/policy/cloud/policy_header_service_factory.h" | 20 #include "chrome/browser/policy/cloud/policy_header_service_factory.h" |
17 #include "chrome/browser/profiles/profile.h" | 21 #include "chrome/browser/profiles/profile.h" |
18 #include "chrome/browser/renderer_host/chrome_navigation_data.h" | 22 #include "chrome/browser/renderer_host/chrome_navigation_data.h" |
19 #include "chrome/browser/ui/browser.h" | 23 #include "chrome/browser/ui/browser.h" |
20 #include "chrome/browser/ui/tabs/tab_strip_model.h" | 24 #include "chrome/browser/ui/tabs/tab_strip_model.h" |
25 #include "chrome/common/chrome_paths.h" | |
21 #include "chrome/test/base/in_process_browser_test.h" | 26 #include "chrome/test/base/in_process_browser_test.h" |
22 #include "chrome/test/base/ui_test_utils.h" | 27 #include "chrome/test/base/ui_test_utils.h" |
23 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data .h" | 28 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data .h" |
24 #include "components/policy/core/common/cloud/cloud_policy_constants.h" | 29 #include "components/policy/core/common/cloud/cloud_policy_constants.h" |
25 #include "components/policy/core/common/cloud/policy_header_io_helper.h" | 30 #include "components/policy/core/common/cloud/policy_header_io_helper.h" |
26 #include "components/policy/core/common/cloud/policy_header_service.h" | 31 #include "components/policy/core/common/cloud/policy_header_service.h" |
27 #include "components/policy/core/common/policy_switches.h" | 32 #include "components/policy/core/common/policy_switches.h" |
33 #include "components/prefs/pref_service.h" | |
34 #include "components/signin/core/browser/signin_header_helper.h" | |
35 #include "components/signin/core/common/signin_pref_names.h" | |
36 #include "components/signin/core/common/signin_switches.h" | |
28 #include "content/public/browser/navigation_data.h" | 37 #include "content/public/browser/navigation_data.h" |
29 #include "content/public/browser/navigation_handle.h" | 38 #include "content/public/browser/navigation_handle.h" |
30 #include "content/public/browser/resource_dispatcher_host.h" | 39 #include "content/public/browser/resource_dispatcher_host.h" |
40 #include "content/public/browser/resource_dispatcher_host_delegate.h" | |
31 #include "content/public/browser/web_contents_observer.h" | 41 #include "content/public/browser/web_contents_observer.h" |
32 #include "content/public/test/browser_test_utils.h" | 42 #include "content/public/test/browser_test_utils.h" |
33 #include "net/http/http_request_headers.h" | 43 #include "net/http/http_request_headers.h" |
34 #include "net/test/embedded_test_server/embedded_test_server.h" | 44 #include "net/test/embedded_test_server/embedded_test_server.h" |
35 #include "net/test/embedded_test_server/http_request.h" | 45 #include "net/test/embedded_test_server/http_request.h" |
36 #include "net/test/embedded_test_server/http_response.h" | 46 #include "net/test/embedded_test_server/http_response.h" |
47 #include "net/test/url_request/url_request_mock_http_job.h" | |
37 #include "net/url_request/url_request.h" | 48 #include "net/url_request/url_request.h" |
49 #include "net/url_request/url_request_filter.h" | |
50 #include "testing/gmock/include/gmock/gmock-matchers.h" | |
38 | 51 |
39 using content::ResourceType; | 52 using content::ResourceType; |
53 using testing::HasSubstr; | |
54 using testing::Not; | |
40 | 55 |
41 namespace { | 56 namespace { |
42 static const char kTestPolicyHeader[] = "test_header"; | 57 static const char kTestPolicyHeader[] = "test_header"; |
43 static const char kServerRedirectUrl[] = "/server-redirect"; | 58 static const char kServerRedirectUrl[] = "/server-redirect"; |
44 | 59 |
45 std::unique_ptr<net::test_server::HttpResponse> HandleTestRequest( | 60 std::unique_ptr<net::test_server::HttpResponse> HandleTestRequest( |
46 const net::test_server::HttpRequest& request) { | 61 const net::test_server::HttpRequest& request) { |
47 if (base::StartsWith(request.relative_url, kServerRedirectUrl, | 62 if (base::StartsWith(request.relative_url, kServerRedirectUrl, |
48 base::CompareCase::SENSITIVE)) { | 63 base::CompareCase::SENSITIVE)) { |
49 // Extract the target URL and redirect there. | 64 // Extract the target URL and redirect there. |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
244 ui_test_utils::NavigateToURL( | 259 ui_test_utils::NavigateToURL( |
245 browser(), embedded_test_server()->GetURL("/google/google.html")); | 260 browser(), embedded_test_server()->GetURL("/google/google.html")); |
246 } | 261 } |
247 SetShouldAddDataReductionProxyData(true); | 262 SetShouldAddDataReductionProxyData(true); |
248 { | 263 { |
249 DidFinishNavigationObserver nav_observer( | 264 DidFinishNavigationObserver nav_observer( |
250 browser()->tab_strip_model()->GetActiveWebContents(), true); | 265 browser()->tab_strip_model()->GetActiveWebContents(), true); |
251 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url()); | 266 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url()); |
252 } | 267 } |
253 } | 268 } |
269 | |
270 namespace { | |
271 | |
272 // A URLRequestMockHTTPJob to that reports HTTP request headers of outgoing | |
273 // requests. | |
274 class MirrorMockURLRequestJob : public net::URLRequestMockHTTPJob { | |
275 public: | |
276 // Callback function on the UI thread to report a (URL, request headers) | |
277 // pair. Indicating that the |request headers| will be sent for the |URL|. | |
278 using ReportResponseHeadersOnUI = | |
279 base::Callback<void(const std::string&, const std::string&)>; | |
280 | |
281 MirrorMockURLRequestJob(net::URLRequest* request, | |
282 net::NetworkDelegate* network_delegate, | |
283 const base::FilePath& file_path, | |
284 const scoped_refptr<base::TaskRunner>& task_runner, | |
285 ReportResponseHeadersOnUI report_on_ui) | |
286 : net::URLRequestMockHTTPJob(request, | |
287 network_delegate, | |
288 file_path, | |
289 task_runner), | |
290 report_on_ui_(report_on_ui) {} | |
291 | |
292 void Start() override { | |
293 // Report the observed request headers on the UI thread. | |
294 content::BrowserThread::PostTask( | |
295 content::BrowserThread::UI, FROM_HERE, | |
296 base::Bind(report_on_ui_, request_->url().spec(), | |
297 request_->extra_request_headers().ToString())); | |
298 | |
299 URLRequestMockHTTPJob::Start(); | |
300 } | |
301 | |
302 protected: | |
303 const ReportResponseHeadersOnUI report_on_ui_; | |
304 | |
305 private: | |
306 DISALLOW_COPY_AND_ASSIGN(MirrorMockURLRequestJob); | |
307 }; | |
308 | |
309 // A URLRequestInterceptor to inject MirrorMockURLRequestJobs. | |
310 class MirrorMockJobInterceptor : public net::URLRequestInterceptor { | |
311 public: | |
312 using ReportResponseHeadersOnUI = | |
313 MirrorMockURLRequestJob::ReportResponseHeadersOnUI; | |
314 | |
315 MirrorMockJobInterceptor(const base::FilePath& root_http, | |
316 ReportResponseHeadersOnUI report_on_ui) | |
317 : root_http_(root_http), report_on_ui_(report_on_ui) {} | |
318 ~MirrorMockJobInterceptor() override = default; | |
319 | |
320 // URLRequestInterceptor implementation | |
321 net::URLRequestJob* MaybeInterceptRequest( | |
322 net::URLRequest* request, | |
323 net::NetworkDelegate* network_delegate) const override { | |
324 return new MirrorMockURLRequestJob( | |
325 request, network_delegate, root_http_, | |
326 content::BrowserThread::GetBlockingPool() | |
327 ->GetTaskRunnerWithShutdownBehavior( | |
328 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN), | |
329 report_on_ui_); | |
330 } | |
331 | |
332 static void Register(const GURL& url, | |
333 const base::FilePath& root_http, | |
334 ReportResponseHeadersOnUI report_on_ui) { | |
335 EXPECT_TRUE( | |
336 content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
337 base::FilePath file_path(root_http); | |
338 file_path = | |
339 file_path.AppendASCII(url.scheme() + "." + url.host() + ".html"); | |
340 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor( | |
341 url.scheme(), url.host(), base::WrapUnique(new MirrorMockJobInterceptor( | |
342 file_path, report_on_ui))); | |
343 } | |
344 | |
345 static void Unregister(const GURL& url) { | |
346 EXPECT_TRUE( | |
347 content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); | |
348 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(url.scheme(), | |
349 url.host()); | |
350 } | |
351 | |
352 private: | |
353 const base::FilePath root_http_; | |
354 ReportResponseHeadersOnUI report_on_ui_; | |
355 | |
356 DISALLOW_COPY_AND_ASSIGN(MirrorMockJobInterceptor); | |
357 }; | |
358 | |
359 void ReportRequestHeaders(std::map<std::string, std::string>* request_headers, | |
mmenke
2016/09/01 18:31:48
include map
mmenke
2016/09/01 18:31:48
Should document this.
Ramin Halavati
2016/09/02 13:41:43
Done.
Ramin Halavati
2016/09/02 13:41:43
Done.
| |
360 const std::string& url, | |
361 const std::string& headers) { | |
mmenke
2016/09/01 18:31:48
EXPECT_TRUE(request_header.find(url) == std::map::
mmenke
2016/09/01 18:31:48
DCHECK_CURRENTLY_ON(BrowserThread::UI); (Or whatev
Ramin Halavati
2016/09/02 13:41:43
Done.
Ramin Halavati
2016/09/02 13:41:43
Done.
| |
362 (*request_headers)[url] = headers; | |
363 } | |
364 | |
365 void EmptyClosure() {} | |
366 | |
367 } // namespace | |
368 | |
369 class HeaderTestDispatcherHostDelegate | |
mmenke
2016/09/01 18:31:48
Should document this.
Ramin Halavati
2016/09/02 13:41:43
Done.
| |
370 : public ChromeResourceDispatcherHostDelegate { | |
371 public: | |
372 explicit HeaderTestDispatcherHostDelegate(const GURL& watch_url) | |
373 : watch_url_(watch_url) {} | |
374 ~HeaderTestDispatcherHostDelegate() override {} | |
375 | |
376 void RequestBeginning( | |
377 net::URLRequest* request, | |
378 content::ResourceContext* resource_context, | |
379 content::AppCacheService* appcache_service, | |
380 ResourceType resource_type, | |
381 ScopedVector<content::ResourceThrottle>* throttles) override { | |
382 ChromeResourceDispatcherHostDelegate::RequestBeginning( | |
383 request, resource_context, appcache_service, resource_type, throttles); | |
384 if (request->url() == watch_url_) { | |
385 request->SetExtraRequestHeaderByName(signin::kChromeConnectedHeader, | |
386 "User Data", false); | |
387 } | |
388 } | |
389 | |
390 private: | |
391 const GURL watch_url_; | |
392 DISALLOW_COPY_AND_ASSIGN(HeaderTestDispatcherHostDelegate); | |
mmenke
2016/09/01 18:31:48
nit: Blank line before DISALLOW_COPY_AND_ASSIGN
Ramin Halavati
2016/09/02 13:41:43
Done.
| |
393 }; | |
394 | |
395 // Verify the following items: | |
396 // 1- X-Chrome-Connected is appended on Google domains if account | |
397 // consistency is enabled and access is secure. | |
398 // 2- The header is stripped in case a request is redirected from a Gooogle | |
399 // domain to non-google domain. | |
400 // 3- The header is NOT stripped in case it is added directly by the page | |
401 // and not because it was on a secure Google domain. | |
402 // This is a regression test for crbug.com/588492. | |
403 IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest, | |
404 MirrorRequestHeader) { | |
405 // Enable account consistency so that mirror actually sets the | |
406 // X-Chrome-Connected header in requests to Google. | |
407 base::test::ScopedCommandLine command_line; | |
408 command_line.GetProcessCommandLine()->AppendSwitch( | |
409 switches::kEnableAccountConsistency); | |
410 | |
411 browser()->profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername, | |
412 "user@gmail.com"); | |
413 browser()->profile()->GetPrefs()->SetString( | |
414 prefs::kGoogleServicesUserAccountId, "account_id"); | |
415 | |
416 // The HTTP Request headers (i.e. the ones that are managed on the URLRequest | |
417 // layer, not on the URLRequestJob layer) sent from the browser are collected | |
418 // in this map. The keys are URLs the values the request headers. | |
419 std::map<std::string, std::string> request_headers; | |
420 MirrorMockURLRequestJob::ReportResponseHeadersOnUI report_request_headers = | |
421 base::Bind(&ReportRequestHeaders, &request_headers); | |
mmenke
2016/09/01 18:31:48
Move this stuff into the loop, so it's cleared bet
Ramin Halavati
2016/09/02 13:41:44
Done.
| |
422 | |
423 base::FilePath root_http; | |
424 PathService::Get(chrome::DIR_TEST_DATA, &root_http); | |
425 root_http = root_http.AppendASCII("mirror_request_header"); | |
426 | |
427 struct TestCase { | |
428 GURL urls[2]; | |
mmenke
2016/09/01 18:31:48
Think you should name these two URLs - you have to
Ramin Halavati
2016/09/02 13:41:43
Done.
| |
429 bool inject_header; | |
430 bool expect_header[2]; | |
431 } all_tests[] = { | |
432 // Neither should have the header. | |
433 {{GURL("http://www.google.com"), GURL("http://www.redirected.com")}, | |
434 false, | |
435 {false, false}}, | |
436 // First one should have the header, but not transfered to second one. | |
437 {{GURL("https://www.google.com"), GURL("https://www.redirected.com")}, | |
438 false, | |
439 {true, false}}, | |
440 // First one adds the header and transfers it to the second. | |
441 {{GURL("http://www.header_adder.com"), | |
442 GURL("http://www.redirected_from_header_adder.com")}, | |
443 true, | |
444 {true, true}}}; | |
445 | |
446 for (const auto& test_case : all_tests) { | |
447 SCOPED_TRACE(test_case.urls[0]); | |
448 // If test case requires adding header for the first url, | |
449 // change the delegate. | |
450 std::unique_ptr<HeaderTestDispatcherHostDelegate> dispatcher_host_delegate; | |
451 if (test_case.inject_header) { | |
452 dispatcher_host_delegate.reset( | |
453 new HeaderTestDispatcherHostDelegate(test_case.urls[0])); | |
454 content::ResourceDispatcherHost::Get()->SetDelegate( | |
455 dispatcher_host_delegate.get()); | |
mmenke
2016/09/01 18:31:48
Here and below, should set this on the IO thread (
Ramin Halavati
2016/09/02 13:41:43
Done.
| |
456 } | |
457 | |
458 // Setup mockup interceptors. | |
459 for (const GURL& url : test_case.urls) { | |
460 content::BrowserThread::PostTask( | |
461 content::BrowserThread::IO, FROM_HERE, | |
462 base::Bind(&MirrorMockJobInterceptor::Register, url, root_http, | |
463 report_request_headers)); | |
464 } | |
465 | |
466 // Navigate to first url. | |
467 ui_test_utils::NavigateToURL(browser(), test_case.urls[0]); | |
468 | |
469 // Cleanup before verifying the observed headers. | |
470 for (const GURL& url : test_case.urls) { | |
471 content::BrowserThread::PostTask( | |
472 content::BrowserThread::IO, FROM_HERE, | |
473 base::Bind(&MirrorMockJobInterceptor::Unregister, url)); | |
474 } | |
475 | |
476 // Ensure that the response headers have been reported to the UI thread | |
477 // and unregistration has been processed on the IO thread. | |
478 base::RunLoop run_loop; | |
479 content::BrowserThread::PostTaskAndReply(content::BrowserThread::IO, | |
480 FROM_HERE, | |
481 // Flush IO thread... | |
482 base::Bind(&EmptyClosure), | |
483 // ... and UI thread. | |
484 run_loop.QuitClosure()); | |
485 run_loop.Run(); | |
486 | |
487 if (test_case.inject_header) | |
488 content::ResourceDispatcherHost::Get()->SetDelegate(nullptr); | |
mmenke
2016/09/01 18:31:48
We should restore the original RDHDelegate instead
Ramin Halavati
2016/09/02 13:41:43
I couldn't find anyway in public interface to get
mmenke
2016/09/02 16:29:43
You're right. Looks like the RDH mostly allows a
| |
489 | |
490 // Check if header exists and X-Chrome-Connected is correctly provided. | |
491 for (int i = 0; i < 2; i++) { | |
492 SCOPED_TRACE(test_case.urls[i]); | |
493 ASSERT_EQ(1u, request_headers.count(test_case.urls[i].spec())); | |
494 if (test_case.expect_header[i]) | |
495 EXPECT_THAT(request_headers[test_case.urls[i].spec()], | |
496 HasSubstr(signin::kChromeConnectedHeader)); | |
497 else | |
498 EXPECT_THAT(request_headers[test_case.urls[i].spec()], | |
499 Not(HasSubstr(signin::kChromeConnectedHeader))); | |
500 } | |
501 } | |
502 } | |
OLD | NEW |