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

Unified 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: X-Chrome-Connected header is not removed if not originated from Google. Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc
diff --git a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc
index 57388aaed81d6c3ad32f7421455e84acb653a35b..c34027a0ad8aef2402fe7445e4f1838f65d80e5b 100644
--- a/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc
+++ b/chrome/browser/renderer_host/chrome_resource_dispatcher_host_delegate_browsertest.cc
@@ -8,16 +8,21 @@
#include <memory>
#include <utility>
+#include <vector>
#include "base/command_line.h"
#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/stl_util.h"
#include "base/strings/string_util.h"
+#include "base/test/scoped_command_line.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/policy/cloud/policy_header_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/renderer_host/chrome_navigation_data.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/chrome_paths.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/ui_test_utils.h"
#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
@@ -25,18 +30,28 @@
#include "components/policy/core/common/cloud/policy_header_io_helper.h"
#include "components/policy/core/common/cloud/policy_header_service.h"
#include "components/policy/core/common/policy_switches.h"
+#include "components/prefs/pref_service.h"
+#include "components/signin/core/browser/signin_header_helper.h"
+#include "components/signin/core/common/signin_pref_names.h"
+#include "components/signin/core/common/signin_switches.h"
#include "content/public/browser/navigation_data.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/resource_dispatcher_host.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/test/browser_test_utils.h"
#include "net/http/http_request_headers.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#include "net/test/embedded_test_server/http_request.h"
#include "net/test/embedded_test_server/http_response.h"
+#include "net/test/url_request/url_request_mock_http_job.h"
#include "net/url_request/url_request.h"
+#include "net/url_request/url_request_filter.h"
+#include "testing/gmock/include/gmock/gmock-matchers.h"
using content::ResourceType;
+using testing::HasSubstr;
+using testing::Not;
namespace {
static const char kTestPolicyHeader[] = "test_header";
@@ -251,3 +266,228 @@ IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url());
}
}
+
+namespace {
+
+// A URLRequestMockHTTPJob to that reports HTTP request headers of outgoing
+// requests.
+class MirrorMockURLRequestJob : public net::URLRequestMockHTTPJob {
+ public:
+ // Callback function on the UI thread to report a (URL, request headers)
+ // pair. Indicating that the |request headers| will be sent for the |URL|.
+ using ReportResponseHeadersOnUI =
+ base::Callback<void(const std::string&, const std::string&)>;
+
+ MirrorMockURLRequestJob(net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const base::FilePath& file_path,
+ const scoped_refptr<base::TaskRunner>& task_runner,
+ ReportResponseHeadersOnUI report_on_ui)
+ : net::URLRequestMockHTTPJob(request,
+ network_delegate,
+ file_path,
+ task_runner),
+ report_on_ui_(report_on_ui) {}
+
+ void Start() override {
+ // Report the observed request headers on the UI thread.
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI, FROM_HERE,
+ base::Bind(report_on_ui_, request_->url().spec(),
+ request_->extra_request_headers().ToString()));
+
+ URLRequestMockHTTPJob::Start();
+ }
+
+ protected:
+ const ReportResponseHeadersOnUI report_on_ui_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MirrorMockURLRequestJob);
+};
mmenke 2016/08/30 19:12:26 Do the google checks care about port? It doesn't
mmenke 2016/08/30 19:23:39 Actually, probably best to ignore this suggestion
Ramin Halavati 2016/09/01 10:41:44 Acknowledged.
Ramin Halavati 2016/09/01 10:41:44 Acknowledged.
+
+// A URLRequestInterceptor to inject MirrorMockURLRequestJobs.
+class MirrorMockJobInterceptor : public net::URLRequestInterceptor {
+ public:
+ using ReportResponseHeadersOnUI =
+ MirrorMockURLRequestJob::ReportResponseHeadersOnUI;
+
+ MirrorMockJobInterceptor(const base::FilePath& root_http,
+ ReportResponseHeadersOnUI report_on_ui)
+ : root_http_(root_http), report_on_ui_(report_on_ui) {}
+ ~MirrorMockJobInterceptor() override = default;
+
+ // URLRequestInterceptor implementation
+ net::URLRequestJob* MaybeInterceptRequest(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return new MirrorMockURLRequestJob(
+ request, network_delegate, root_http_,
+ content::BrowserThread::GetBlockingPool()
+ ->GetTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN),
+ report_on_ui_);
+ }
+
+ static void Register(const GURL& url,
+ const base::FilePath& root_http,
+ ReportResponseHeadersOnUI report_on_ui) {
+ EXPECT_TRUE(
+ content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ base::FilePath file_path(root_http);
+ file_path =
+ file_path.AppendASCII(url.scheme() + "." + url.host() + ".html");
+ net::URLRequestFilter::GetInstance()->AddHostnameInterceptor(
+ url.scheme(), url.host(), base::WrapUnique(new MirrorMockJobInterceptor(
+ file_path, report_on_ui)));
+ }
+
+ static void Unregister(const GURL& url) {
+ EXPECT_TRUE(
+ content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
+ net::URLRequestFilter::GetInstance()->RemoveHostnameHandler(url.scheme(),
+ url.host());
+ }
+
+ private:
+ const base::FilePath root_http_;
+ ReportResponseHeadersOnUI report_on_ui_;
+
+ DISALLOW_COPY_AND_ASSIGN(MirrorMockJobInterceptor);
+};
+
+void ReportRequestHeaders(std::map<std::string, std::string>* request_headers,
+ const std::string& url,
+ const std::string& headers) {
+ (*request_headers)[url] = headers;
+}
+
+void EmptyClosure() {}
+
+} // namespace
+
+class HeaderTestDispatcherHostDelegate
+ : public ChromeResourceDispatcherHostDelegate {
+ public:
+ explicit HeaderTestDispatcherHostDelegate(const GURL& watch_url)
+ : watch_url_(watch_url) {}
+ ~HeaderTestDispatcherHostDelegate() override {}
+
+ void RequestBeginning(
+ net::URLRequest* request,
+ content::ResourceContext* resource_context,
+ content::AppCacheService* appcache_service,
+ ResourceType resource_type,
+ ScopedVector<content::ResourceThrottle>* throttles) override {
+ ChromeResourceDispatcherHostDelegate::RequestBeginning(
+ request, resource_context, appcache_service, resource_type, throttles);
+ if (request->url() == watch_url_) {
+ request->SetExtraRequestHeaderByName(signin::kChromeConnectedHeader,
+ "User Data", false);
mmenke 2016/08/30 19:12:26 Why are we appending this? Shouldn't the RDH do t
Ramin Halavati 2016/09/01 10:41:44 We added a new test in the last CL in which a webs
+ }
+ }
+
+ private:
+ const GURL watch_url_;
+ DISALLOW_COPY_AND_ASSIGN(HeaderTestDispatcherHostDelegate);
+};
+
+// Verify the following items:
+// 1- X-Chrome-Connected is appended on Google domains if account
+// consistency is enabled and access is secure.
+// 2- The header is stripped in case a request is redirected from a Gooogle
+// domain to non-google domain.
+// 3- The header is NOT stripped in case it is added directly by the page
+// and not because it was on a secure Google domain.
+// This is a regression test for crbug.com/588492.
+IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
+ MirrorRequestHeader) {
+ // Enable account consistency so that mirror actually sets the
+ // X-Chrome-Connected header in requests to Google.
+ base::test::ScopedCommandLine command_line;
+ command_line.GetProcessCommandLine()->AppendSwitch(
+ switches::kEnableAccountConsistency);
+
+ browser()->profile()->GetPrefs()->SetString(prefs::kGoogleServicesUsername,
+ "user@gmail.com");
+ browser()->profile()->GetPrefs()->SetString(
+ prefs::kGoogleServicesUserAccountId, "account_id");
+
+ // Set URLS:
+ // The one that needs X-Chrome-Header injection:
+ GURL http_header_adder_com("http://www.header_adder.com");
+ // The ones that should have the X-Chrome-Header:
+ std::vector<GURL> urls_with_header = {
+ http_header_adder_com, GURL("https://www.google.com"),
+ GURL("http://www.redirected_from_header_adder.com")};
+ // All others:
+ std::vector<GURL> all_urls = {GURL("http://www.google.com"),
+ GURL("https://www.redirected.com"),
+ GURL("http://www.redirected.com")};
+ // Merge:
+ all_urls.insert(all_urls.end(), urls_with_header.begin(),
+ urls_with_header.end());
mmenke 2016/08/30 19:12:26 This seems like it would be much cleaner as single
Ramin Halavati 2016/09/01 10:41:44 Done.
+
+ // Change the delegate to the one that adds the header for
+ // http_header_adder_com.
+ HeaderTestDispatcherHostDelegate dispatcher_host_delegate(
+ http_header_adder_com);
+ content::ResourceDispatcherHost::Get()->SetDelegate(
+ &dispatcher_host_delegate);
+
+ // The HTTP Request headers (i.e. the ones that are managed on the URLRequest
+ // layer, not on the URLRequestJob layer) sent from the browser are collected
+ // in this map. The keys are URLs the values the request headers.
+ std::map<std::string, std::string> request_headers;
+ MirrorMockURLRequestJob::ReportResponseHeadersOnUI report_request_headers =
+ base::Bind(&ReportRequestHeaders, &request_headers);
+
+ base::FilePath root_http;
+ PathService::Get(chrome::DIR_TEST_DATA, &root_http);
+ root_http = root_http.AppendASCII("mirror_request_header");
+
+ for (const GURL& url : all_urls) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&MirrorMockJobInterceptor::Register, url, root_http,
+ report_request_headers));
+ }
+
+ // Perform a navigation to all none-redirected urls to observe
+ // the request headers.
+ for (const GURL& url : all_urls) {
+ if (url.host().find("redirect") == -1)
+ ui_test_utils::NavigateToURL(browser(), url);
+ }
mmenke 2016/08/30 19:12:26 I'm unable to figure out how we visit these URLs.
Ramin Halavati 2016/09/01 10:41:44 We have 3 starting URLs here and each one redirect
+
+ // Cleanup before verifying the observed headers.
+ for (const GURL& url : all_urls) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::IO, FROM_HERE,
+ base::Bind(&MirrorMockJobInterceptor::Unregister, url));
+ }
+
+ // Ensure that the response headers have been reported to the UI thread
+ // and unregistration has been processed on the IO thread.
+ base::RunLoop run_loop;
+ content::BrowserThread::PostTaskAndReply(content::BrowserThread::IO,
+ FROM_HERE,
+ // Flush IO thread...
+ base::Bind(&EmptyClosure),
+ // ... and UI thread.
+ run_loop.QuitClosure());
+ run_loop.Run();
+
+ content::ResourceDispatcherHost::Get()->SetDelegate(nullptr);
+
+ // Check if header exists and X-Chrome-Connected is correctly provided.
+ for (const GURL url : all_urls) {
+ ASSERT_EQ(1u, request_headers.count(url.spec()));
+ if (base::ContainsValue(urls_with_header, url))
+ EXPECT_THAT(request_headers[url.spec()],
+ HasSubstr(signin::kChromeConnectedHeader));
+ else
+ EXPECT_THAT(request_headers[url.spec()],
+ Not(HasSubstr(signin::kChromeConnectedHeader)));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698