Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(483)

Side by Side Diff: chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc

Issue 2258483002: X-Chrome-Connected is stripped when it should not be in headers. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Addressed comments Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 <map>
9 #include <memory> 10 #include <memory>
10 #include <utility> 11 #include <utility>
12 #include <vector>
11 13
12 #include "base/command_line.h" 14 #include "base/command_line.h"
13 #include "base/macros.h" 15 #include "base/macros.h"
16 #include "base/path_service.h"
17 #include "base/stl_util.h"
14 #include "base/strings/string_util.h" 18 #include "base/strings/string_util.h"
19 #include "base/test/scoped_command_line.h"
15 #include "chrome/browser/browser_process.h" 20 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/policy/cloud/policy_header_service_factory.h" 21 #include "chrome/browser/policy/cloud/policy_header_service_factory.h"
17 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/browser/renderer_host/chrome_navigation_data.h" 23 #include "chrome/browser/renderer_host/chrome_navigation_data.h"
19 #include "chrome/browser/ui/browser.h" 24 #include "chrome/browser/ui/browser.h"
20 #include "chrome/browser/ui/tabs/tab_strip_model.h" 25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/common/chrome_paths.h"
21 #include "chrome/test/base/in_process_browser_test.h" 27 #include "chrome/test/base/in_process_browser_test.h"
22 #include "chrome/test/base/ui_test_utils.h" 28 #include "chrome/test/base/ui_test_utils.h"
23 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data .h" 29 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data .h"
24 #include "components/policy/core/common/cloud/cloud_policy_constants.h" 30 #include "components/policy/core/common/cloud/cloud_policy_constants.h"
25 #include "components/policy/core/common/cloud/policy_header_io_helper.h" 31 #include "components/policy/core/common/cloud/policy_header_io_helper.h"
26 #include "components/policy/core/common/cloud/policy_header_service.h" 32 #include "components/policy/core/common/cloud/policy_header_service.h"
27 #include "components/policy/core/common/policy_switches.h" 33 #include "components/policy/core/common/policy_switches.h"
34 #include "components/prefs/pref_service.h"
35 #include "components/signin/core/browser/signin_header_helper.h"
36 #include "components/signin/core/common/signin_pref_names.h"
37 #include "components/signin/core/common/signin_switches.h"
28 #include "content/public/browser/navigation_data.h" 38 #include "content/public/browser/navigation_data.h"
29 #include "content/public/browser/navigation_handle.h" 39 #include "content/public/browser/navigation_handle.h"
30 #include "content/public/browser/resource_dispatcher_host.h" 40 #include "content/public/browser/resource_dispatcher_host.h"
41 #include "content/public/browser/resource_dispatcher_host_delegate.h"
31 #include "content/public/browser/web_contents_observer.h" 42 #include "content/public/browser/web_contents_observer.h"
32 #include "content/public/test/browser_test_utils.h" 43 #include "content/public/test/browser_test_utils.h"
33 #include "net/http/http_request_headers.h" 44 #include "net/http/http_request_headers.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h" 45 #include "net/test/embedded_test_server/embedded_test_server.h"
35 #include "net/test/embedded_test_server/http_request.h" 46 #include "net/test/embedded_test_server/http_request.h"
36 #include "net/test/embedded_test_server/http_response.h" 47 #include "net/test/embedded_test_server/http_response.h"
48 #include "net/test/url_request/url_request_mock_http_job.h"
37 #include "net/url_request/url_request.h" 49 #include "net/url_request/url_request.h"
50 #include "net/url_request/url_request_filter.h"
51 #include "testing/gmock/include/gmock/gmock-matchers.h"
38 52
39 using content::ResourceType; 53 using content::ResourceType;
54 using testing::HasSubstr;
55 using testing::Not;
40 56
41 namespace { 57 namespace {
42 static const char kTestPolicyHeader[] = "test_header"; 58 static const char kTestPolicyHeader[] = "test_header";
43 static const char kServerRedirectUrl[] = "/server-redirect"; 59 static const char kServerRedirectUrl[] = "/server-redirect";
44 60
45 std::unique_ptr<net::test_server::HttpResponse> HandleTestRequest( 61 std::unique_ptr<net::test_server::HttpResponse> HandleTestRequest(
46 const net::test_server::HttpRequest& request) { 62 const net::test_server::HttpRequest& request) {
47 if (base::StartsWith(request.relative_url, kServerRedirectUrl, 63 if (base::StartsWith(request.relative_url, kServerRedirectUrl,
48 base::CompareCase::SENSITIVE)) { 64 base::CompareCase::SENSITIVE)) {
49 // Extract the target URL and redirect there. 65 // Extract the target URL and redirect there.
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 ui_test_utils::NavigateToURL( 260 ui_test_utils::NavigateToURL(
245 browser(), embedded_test_server()->GetURL("/google/google.html")); 261 browser(), embedded_test_server()->GetURL("/google/google.html"));
246 } 262 }
247 SetShouldAddDataReductionProxyData(true); 263 SetShouldAddDataReductionProxyData(true);
248 { 264 {
249 DidFinishNavigationObserver nav_observer( 265 DidFinishNavigationObserver nav_observer(
250 browser()->tab_strip_model()->GetActiveWebContents(), true); 266 browser()->tab_strip_model()->GetActiveWebContents(), true);
251 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url()); 267 ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url());
252 } 268 }
253 } 269 }
270
271 namespace {
272
273 // A URLRequestMockHTTPJob to that reports HTTP request headers of outgoing
274 // requests.
275 class MirrorMockURLRequestJob : public net::URLRequestMockHTTPJob {
276 public:
277 // Callback function on the UI thread to report a (URL, request headers)
278 // pair. Indicating that the |request headers| will be sent for the |URL|.
279 using ReportResponseHeadersOnUI =
280 base::Callback<void(const std::string&, const std::string&)>;
281
282 MirrorMockURLRequestJob(net::URLRequest* request,
283 net::NetworkDelegate* network_delegate,
284 const base::FilePath& file_path,
285 const scoped_refptr<base::TaskRunner>& task_runner,
286 ReportResponseHeadersOnUI report_on_ui)
287 : net::URLRequestMockHTTPJob(request,
288 network_delegate,
289 file_path,
290 task_runner),
291 report_on_ui_(report_on_ui) {}
292
293 void Start() override {
294 // Report the observed request headers on the UI thread.
295 content::BrowserThread::PostTask(
296 content::BrowserThread::UI, FROM_HERE,
297 base::Bind(report_on_ui_, request_->url().spec(),
298 request_->extra_request_headers().ToString()));
299
300 URLRequestMockHTTPJob::Start();
301 }
302
303 protected:
304 const ReportResponseHeadersOnUI report_on_ui_;
305
306 private:
307 DISALLOW_COPY_AND_ASSIGN(MirrorMockURLRequestJob);
308 };
309
310 // A URLRequestInterceptor to inject MirrorMockURLRequestJobs.
311 class MirrorMockJobInterceptor : public net::URLRequestInterceptor {
312 public:
313 using ReportResponseHeadersOnUI =
314 MirrorMockURLRequestJob::ReportResponseHeadersOnUI;
315
316 MirrorMockJobInterceptor(const base::FilePath& root_http,
317 ReportResponseHeadersOnUI report_on_ui)
318 : root_http_(root_http), report_on_ui_(report_on_ui) {}
319 ~MirrorMockJobInterceptor() override = default;
320
321 // URLRequestInterceptor implementation
322 net::URLRequestJob* MaybeInterceptRequest(
323 net::URLRequest* request,
324 net::NetworkDelegate* network_delegate) const override {
325 return new MirrorMockURLRequestJob(
326 request, network_delegate, root_http_,
327 content::BrowserThread::GetBlockingPool()
328 ->GetTaskRunnerWithShutdownBehavior(
329 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
330 report_on_ui_);
331 }
332
333 static void Register(const GURL& url,
334 const base::FilePath& root_http,
335 ReportResponseHeadersOnUI report_on_ui) {
336 EXPECT_TRUE(
337 content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
338 base::FilePath file_path(root_http);
339 file_path =
340 file_path.AppendASCII(url.scheme() + "." + url.host() + ".html");
341 net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
342 url.scheme(), url.host(), base::WrapUnique(new MirrorMockJobInterceptor(
343 file_path, report_on_ui)));
344 }
345
346 static void Unregister(const GURL& url) {
347 EXPECT_TRUE(
348 content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
349 net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(url.scheme(),
350 url.host());
351 }
352
353 private:
354 const base::FilePath root_http_;
355 ReportResponseHeadersOnUI report_on_ui_;
356
357 DISALLOW_COPY_AND_ASSIGN(MirrorMockJobInterceptor);
358 };
359
360 // Used in MirrorMockURLRequestJob to store HTTP request header for all received
361 // URLs in the given map.
362 void ReportRequestHeaders(std::map<std::string, std::string>* request_headers,
363 const std::string& url,
364 const std::string& headers) {
365 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
366 // Ensure that a previous value is not overwritten.
367 EXPECT_FALSE(base::ContainsKey(*request_headers, url));
368 (*request_headers)[url] = headers;
369 }
370
371 void EmptyClosure() {}
sky 2016/09/06 18:29:04 Use DoNothing (in bind_helpers).
Ramin Halavati 2016/09/07 07:51:20 Done.
372
373 } // namespace
374
375 // A delegate to insert a user generated X-Chrome-Connected header
376 // to a specifict URL.
377 class HeaderTestDispatcherHostDelegate
378 : public ChromeResourceDispatcherHostDelegate {
379 public:
380 explicit HeaderTestDispatcherHostDelegate(const GURL& watch_url)
381 : watch_url_(watch_url) {}
382 ~HeaderTestDispatcherHostDelegate() override {}
383
384 void RequestBeginning(
385 net::URLRequest* request,
386 content::ResourceContext* resource_context,
387 content::AppCacheService* appcache_service,
388 ResourceType resource_type,
389 ScopedVector<content::ResourceThrottle>* throttles) override {
390 ChromeResourceDispatcherHostDelegate::RequestBeginning(
391 request, resource_context, appcache_service, resource_type, throttles);
392 if (request->url() == watch_url_) {
393 request->SetExtraRequestHeaderByName(signin::kChromeConnectedHeader,
394 "User Data", false);
395 }
396 }
397
398 private:
399 const GURL watch_url_;
400
401 DISALLOW_COPY_AND_ASSIGN(HeaderTestDispatcherHostDelegate);
402 };
403
404 // Sets a new one on IO thread
405 void SetDelegateOnIO(content::ResourceDispatcherHostDelegate* new_delegate) {
406 content::ResourceDispatcherHost::Get()->SetDelegate(new_delegate);
407 }
408
409 // Verify the following items:
410 // 1- X-Chrome-Connected is appended on Google domains if account
411 // consistency is enabled and access is secure.
412 // 2- The header is stripped in case a request is redirected from a Gooogle
413 // domain to non-google domain.
414 // 3- The header is NOT stripped in case it is added directly by the page
415 // and not because it was on a secure Google domain.
416 // This is a regression test for crbug.com/588492.
417 IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
418 MirrorRequestHeader) {
419 // Enable account consistency so that mirror actually sets the
420 // X-Chrome-Connected header in requests to Google.
421 base::test::ScopedCommandLine command_line;
sky 2016/09/06 18:29:04 Do you really need this? Each browser_process runs
Ramin Halavati 2016/09/07 07:51:21 As other tests also use this fixture, I thought th
422 command_line.GetProcessCommandLine()->AppendSwitch(
423 switches::kEnableAccountConsistency);
424
425 browser()->profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
426 "user@gmail.com");
427 browser()->profile()->GetPrefs()->SetString(
428 prefs::kGoogleServicesUserAccountId, "account_id");
429
430 base::FilePath root_http;
431 PathService::Get(chrome::DIR_TEST_DATA, &root_http);
432 root_http = root_http.AppendASCII("mirror_request_header");
433
434 struct TestCase {
435 GURL original_url, redirected_to_url;
436 bool inject_header, original_url_expects_header,
437 redirected_to_url_expects_header;
438 } all_tests[] = {
439 // Neither should have the header.
440 {GURL("http://www.google.com"), GURL("http://www.redirected.com"), false,
441 false, false},
442 // First one should have the header, but not transfered to second one.
443 {GURL("https://www.google.com"), GURL("https://www.redirected.com"),
444 false, true, false},
445 // First one adds the header and transfers it to the second.
446 {GURL("http://www.header_adder.com"),
447 GURL("http://www.redirected_from_header_adder.com"), true, true, true}};
448
449 for (const auto& test_case : all_tests) {
450 SCOPED_TRACE(test_case.original_url);
451
452 // The HTTP Request headers (i.e. the ones that are managed on the
453 // URLRequest layer, not on the URLRequestJob layer) sent from the browser
454 // are collected in this map. The keys are URLs the values the request
455 // headers.
456 std::map<std::string, std::string> request_headers;
457 MirrorMockURLRequestJob::ReportResponseHeadersOnUI report_request_headers =
458 base::Bind(&ReportRequestHeaders, &request_headers);
459
460 // If test case requires adding header for the first url,
461 // change the delegate.
462 std::unique_ptr<HeaderTestDispatcherHostDelegate> dispatcher_host_delegate;
463 if (test_case.inject_header) {
464 dispatcher_host_delegate.reset(
465 new HeaderTestDispatcherHostDelegate(test_case.original_url));
sky 2016/09/06 18:29:04 MakeUnique is (apparently) the preferred way to ne
Ramin Halavati 2016/09/07 07:51:21 Done.
466 content::BrowserThread::PostTask(
467 content::BrowserThread::IO, FROM_HERE,
468 base::Bind(&SetDelegateOnIO, dispatcher_host_delegate.get()));
sky 2016/09/06 18:29:04 Do you need to block at all to ensure this is inst
Ramin Halavati 2016/09/07 07:51:21 I am not sure why you think we are blocking. I th
sky 2016/09/07 15:16:46 Sorry if I wasn't clear. My question is, do you ne
mmenke 2016/09/07 15:20:30 In the case where we're removing the delegate, we
469 }
470
471 // Set up mockup interceptors.
472 content::BrowserThread::PostTask(
473 content::BrowserThread::IO, FROM_HERE,
474 base::Bind(&MirrorMockJobInterceptor::Register, test_case.original_url,
475 root_http, report_request_headers));
476 content::BrowserThread::PostTask(
477 content::BrowserThread::IO, FROM_HERE,
478 base::Bind(&MirrorMockJobInterceptor::Register,
479 test_case.redirected_to_url, root_http,
480 report_request_headers));
481
482 // Navigate to first url.
483 ui_test_utils::NavigateToURL(browser(), test_case.original_url);
484
485 // Cleanup before verifying the observed headers.
486 content::BrowserThread::PostTask(
487 content::BrowserThread::IO, FROM_HERE,
488 base::Bind(&MirrorMockJobInterceptor::Unregister,
489 test_case.original_url));
490 content::BrowserThread::PostTask(
491 content::BrowserThread::IO, FROM_HERE,
492 base::Bind(&MirrorMockJobInterceptor::Unregister,
493 test_case.redirected_to_url));
494
495 // If delegate is changed, remove it.
496 if (test_case.inject_header) {
497 base::RunLoop run_loop;
498 content::BrowserThread::PostTaskAndReply(
499 content::BrowserThread::IO, FROM_HERE,
500 base::Bind(&SetDelegateOnIO, nullptr), run_loop.QuitClosure());
501 run_loop.Run();
502 }
503
504 // Ensure that the response headers have been reported to the UI thread
505 // and unregistration has been processed on the IO thread.
506 base::RunLoop run_loop;
507 content::BrowserThread::PostTaskAndReply(content::BrowserThread::IO,
508 FROM_HERE,
509 // Flush IO thread...
510 base::Bind(&EmptyClosure),
511 // ... and UI thread.
512 run_loop.QuitClosure());
513 run_loop.Run();
514
515 // Check if header exists and X-Chrome-Connected is correctly provided.
516 ASSERT_EQ(1u, request_headers.count(test_case.original_url.spec()));
517 if (test_case.original_url_expects_header) {
518 EXPECT_THAT(request_headers[test_case.original_url.spec()],
519 HasSubstr(signin::kChromeConnectedHeader));
520 } else {
521 EXPECT_THAT(request_headers[test_case.original_url.spec()],
522 Not(HasSubstr(signin::kChromeConnectedHeader)));
523 }
524
525 ASSERT_EQ(1u, request_headers.count(test_case.redirected_to_url.spec()));
526 if (test_case.redirected_to_url_expects_header) {
527 EXPECT_THAT(request_headers[test_case.redirected_to_url.spec()],
528 HasSubstr(signin::kChromeConnectedHeader));
529 } else {
530 EXPECT_THAT(request_headers[test_case.redirected_to_url.spec()],
531 Not(HasSubstr(signin::kChromeConnectedHeader)));
532 }
533 }
534 }
OLDNEW
« no previous file with comments | « chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate.cc ('k') | chrome/browser/signin/chrome_signin_helper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698