skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 1 | // Copyright 2016 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 <memory> |
| 6 | |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 7 | #include "base/files/scoped_temp_dir.h" |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 8 | #include "base/strings/stringprintf.h" |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 9 | #include "base/threading/thread_restrictions.h" |
eseckler | d71fc50 | 2016-09-30 10:07:59 | [diff] [blame] | 10 | #include "content/public/browser/render_view_host.h" |
| 11 | #include "content/public/browser/web_contents.h" |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 12 | #include "content/public/test/browser_test.h" |
eseckler | d71fc50 | 2016-09-30 10:07:59 | [diff] [blame] | 13 | #include "headless/lib/browser/headless_web_contents_impl.h" |
skyostil | 6bac5f64 | 2017-05-04 11:40:30 | [diff] [blame] | 14 | #include "headless/public/devtools/domains/runtime.h" |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 15 | #include "headless/public/headless_browser.h" |
| 16 | #include "headless/public/headless_browser_context.h" |
| 17 | #include "headless/public/headless_devtools_client.h" |
| 18 | #include "headless/public/headless_devtools_target.h" |
| 19 | #include "headless/public/headless_web_contents.h" |
| 20 | #include "headless/test/headless_browser_test.h" |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 21 | #include "testing/gtest/include/gtest/gtest.h" |
| 22 | #include "ui/gfx/geometry/size.h" |
| 23 | |
| 24 | namespace headless { |
| 25 | namespace { |
| 26 | const char kMainPageCookie[] = "mood=quizzical"; |
| 27 | const char kIsolatedPageCookie[] = "mood=quixotic"; |
| 28 | } // namespace |
| 29 | |
| 30 | // This test creates two tabs pointing to the same security origin in two |
| 31 | // different browser contexts and checks that they are isolated by creating two |
| 32 | // cookies with the same name in both tabs. The steps are: |
| 33 | // |
| 34 | // 1. Wait for tab #1 to become ready for DevTools. |
| 35 | // 2. Create tab #2 and wait for it to become ready for DevTools. |
| 36 | // 3. Navigate tab #1 to the test page and wait for it to finish loading. |
| 37 | // 4. Navigate tab #2 to the test page and wait for it to finish loading. |
| 38 | // 5. Set a cookie in tab #1. |
| 39 | // 6. Set the same cookie in tab #2 to a different value. |
| 40 | // 7. Read the cookie in tab #1 and check that it has the first value. |
| 41 | // 8. Read the cookie in tab #2 and check that it has the second value. |
| 42 | // |
| 43 | // If the tabs aren't properly isolated, step 7 will fail. |
| 44 | class HeadlessBrowserContextIsolationTest |
| 45 | : public HeadlessAsyncDevTooledBrowserTest { |
| 46 | public: |
| 47 | HeadlessBrowserContextIsolationTest() |
Eric Seckler | 4948f93 | 2018-08-28 14:51:22 | [diff] [blame] | 48 | : browser_context_(nullptr), web_contents2_(nullptr) { |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 49 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 50 | } |
| 51 | |
| 52 | // HeadlessWebContentsObserver implementation: |
| 53 | void DevToolsTargetReady() override { |
| 54 | if (!web_contents2_) { |
| 55 | browser_context_ = browser()->CreateBrowserContextBuilder().Build(); |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 56 | web_contents2_ = browser_context_->CreateWebContentsBuilder().Build(); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 57 | web_contents2_->AddObserver(this); |
| 58 | return; |
| 59 | } |
| 60 | |
Eric Seckler | 4948f93 | 2018-08-28 14:51:22 | [diff] [blame] | 61 | devtools_client2_ = HeadlessDevToolsClient::Create(); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 62 | web_contents2_->GetDevToolsTarget()->AttachClient(devtools_client2_.get()); |
| 63 | HeadlessAsyncDevTooledBrowserTest::DevToolsTargetReady(); |
| 64 | } |
| 65 | |
| 66 | void RunDevTooledTest() override { |
| 67 | load_observer_.reset(new LoadObserver( |
| 68 | devtools_client_.get(), |
| 69 | base::Bind(&HeadlessBrowserContextIsolationTest::OnFirstLoadComplete, |
| 70 | base::Unretained(this)))); |
| 71 | devtools_client_->GetPage()->Navigate( |
| 72 | embedded_test_server()->GetURL("/hello.html").spec()); |
| 73 | } |
| 74 | |
| 75 | void OnFirstLoadComplete() { |
| 76 | EXPECT_TRUE(load_observer_->navigation_succeeded()); |
| 77 | load_observer_.reset(new LoadObserver( |
| 78 | devtools_client2_.get(), |
| 79 | base::Bind(&HeadlessBrowserContextIsolationTest::OnSecondLoadComplete, |
| 80 | base::Unretained(this)))); |
| 81 | devtools_client2_->GetPage()->Navigate( |
| 82 | embedded_test_server()->GetURL("/hello.html").spec()); |
| 83 | } |
| 84 | |
| 85 | void OnSecondLoadComplete() { |
| 86 | EXPECT_TRUE(load_observer_->navigation_succeeded()); |
| 87 | load_observer_.reset(); |
| 88 | |
| 89 | devtools_client_->GetRuntime()->Evaluate( |
| 90 | base::StringPrintf("document.cookie = '%s'", kMainPageCookie), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 91 | base::BindOnce( |
| 92 | &HeadlessBrowserContextIsolationTest::OnFirstSetCookieResult, |
| 93 | base::Unretained(this))); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 94 | } |
| 95 | |
| 96 | void OnFirstSetCookieResult(std::unique_ptr<runtime::EvaluateResult> result) { |
Alex Clarke | 1dbb609 | 2017-10-18 16:53:34 | [diff] [blame] | 97 | EXPECT_EQ(kMainPageCookie, result->GetResult()->GetValue()->GetString()); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 98 | |
| 99 | devtools_client2_->GetRuntime()->Evaluate( |
| 100 | base::StringPrintf("document.cookie = '%s'", kIsolatedPageCookie), |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 101 | base::BindOnce( |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 102 | &HeadlessBrowserContextIsolationTest::OnSecondSetCookieResult, |
| 103 | base::Unretained(this))); |
| 104 | } |
| 105 | |
| 106 | void OnSecondSetCookieResult( |
| 107 | std::unique_ptr<runtime::EvaluateResult> result) { |
Alex Clarke | 1dbb609 | 2017-10-18 16:53:34 | [diff] [blame] | 108 | EXPECT_EQ(kIsolatedPageCookie, |
| 109 | result->GetResult()->GetValue()->GetString()); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 110 | |
| 111 | devtools_client_->GetRuntime()->Evaluate( |
| 112 | "document.cookie", |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 113 | base::BindOnce( |
| 114 | &HeadlessBrowserContextIsolationTest::OnFirstGetCookieResult, |
| 115 | base::Unretained(this))); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 116 | } |
| 117 | |
| 118 | void OnFirstGetCookieResult(std::unique_ptr<runtime::EvaluateResult> result) { |
Alex Clarke | 1dbb609 | 2017-10-18 16:53:34 | [diff] [blame] | 119 | EXPECT_EQ(kMainPageCookie, result->GetResult()->GetValue()->GetString()); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 120 | |
| 121 | devtools_client2_->GetRuntime()->Evaluate( |
| 122 | "document.cookie", |
tzik | f7adad1a | 2018-03-10 20:31:01 | [diff] [blame] | 123 | base::BindOnce( |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 124 | &HeadlessBrowserContextIsolationTest::OnSecondGetCookieResult, |
| 125 | base::Unretained(this))); |
| 126 | } |
| 127 | |
| 128 | void OnSecondGetCookieResult( |
| 129 | std::unique_ptr<runtime::EvaluateResult> result) { |
Alex Clarke | 1dbb609 | 2017-10-18 16:53:34 | [diff] [blame] | 130 | EXPECT_EQ(kIsolatedPageCookie, |
| 131 | result->GetResult()->GetValue()->GetString()); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 132 | FinishTest(); |
| 133 | } |
| 134 | |
| 135 | void FinishTest() { |
| 136 | web_contents2_->RemoveObserver(this); |
| 137 | web_contents2_->Close(); |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 138 | browser_context_->Close(); |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 139 | FinishAsynchronousTest(); |
| 140 | } |
| 141 | |
| 142 | private: |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 143 | HeadlessBrowserContext* browser_context_; |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 144 | HeadlessWebContents* web_contents2_; |
| 145 | std::unique_ptr<HeadlessDevToolsClient> devtools_client2_; |
| 146 | std::unique_ptr<LoadObserver> load_observer_; |
| 147 | }; |
| 148 | |
| 149 | HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessBrowserContextIsolationTest); |
| 150 | |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 151 | IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, UserDataDir) { |
| 152 | // We do not want to bother with posting tasks to create a temp dir. |
| 153 | // Just allow IO from main thread for now. |
| 154 | base::ThreadRestrictions::SetIOAllowed(true); |
| 155 | |
| 156 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 157 | |
| 158 | base::ScopedTempDir user_data_dir; |
| 159 | ASSERT_TRUE(user_data_dir.CreateUniqueTempDir()); |
| 160 | |
| 161 | // Newly created temp directory should be empty. |
vabr | 16e5f60 | 2016-09-15 18:14:00 | [diff] [blame] | 162 | EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath())); |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 163 | |
altimin | bf875c9 | 2016-08-04 17:09:07 | [diff] [blame] | 164 | HeadlessBrowserContext* browser_context = |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 165 | browser() |
| 166 | ->CreateBrowserContextBuilder() |
vabr | 16e5f60 | 2016-09-15 18:14:00 | [diff] [blame] | 167 | .SetUserDataDir(user_data_dir.GetPath()) |
altimin | 1ab63101 | 2016-08-04 18:43:45 | [diff] [blame] | 168 | .SetIncognitoMode(false) |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 169 | .Build(); |
| 170 | |
| 171 | HeadlessWebContents* web_contents = |
| 172 | browser_context->CreateWebContentsBuilder() |
| 173 | .SetInitialURL(embedded_test_server()->GetURL("/hello.html")) |
| 174 | .Build(); |
| 175 | |
| 176 | EXPECT_TRUE(WaitForLoad(web_contents)); |
| 177 | |
| 178 | // Something should be written to this directory. |
| 179 | // If it is not the case, more complex page may be needed. |
| 180 | // ServiceWorkers may be a good option. |
vabr | 16e5f60 | 2016-09-15 18:14:00 | [diff] [blame] | 181 | EXPECT_FALSE(base::IsDirectoryEmpty(user_data_dir.GetPath())); |
altimin | 93a0240 | 2016-08-03 16:26:43 | [diff] [blame] | 182 | } |
| 183 | |
altimin | 1ab63101 | 2016-08-04 18:43:45 | [diff] [blame] | 184 | IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, IncognitoMode) { |
| 185 | // We do not want to bother with posting tasks to create a temp dir. |
| 186 | // Just allow IO from main thread for now. |
| 187 | base::ThreadRestrictions::SetIOAllowed(true); |
| 188 | |
| 189 | EXPECT_TRUE(embedded_test_server()->Start()); |
| 190 | |
| 191 | base::ScopedTempDir user_data_dir; |
| 192 | ASSERT_TRUE(user_data_dir.CreateUniqueTempDir()); |
| 193 | |
| 194 | // Newly created temp directory should be empty. |
vabr | 16e5f60 | 2016-09-15 18:14:00 | [diff] [blame] | 195 | EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath())); |
altimin | 1ab63101 | 2016-08-04 18:43:45 | [diff] [blame] | 196 | |
| 197 | HeadlessBrowserContext* browser_context = |
| 198 | browser() |
| 199 | ->CreateBrowserContextBuilder() |
vabr | 16e5f60 | 2016-09-15 18:14:00 | [diff] [blame] | 200 | .SetUserDataDir(user_data_dir.GetPath()) |
altimin | 1ab63101 | 2016-08-04 18:43:45 | [diff] [blame] | 201 | .SetIncognitoMode(true) |
| 202 | .Build(); |
| 203 | |
| 204 | HeadlessWebContents* web_contents = |
| 205 | browser_context->CreateWebContentsBuilder() |
| 206 | .SetInitialURL(embedded_test_server()->GetURL("/hello.html")) |
| 207 | .Build(); |
| 208 | |
| 209 | EXPECT_TRUE(WaitForLoad(web_contents)); |
| 210 | |
| 211 | // Similar to test above, but now we are in incognito mode, |
| 212 | // so nothing should be written to this directory. |
vabr | 16e5f60 | 2016-09-15 18:14:00 | [diff] [blame] | 213 | EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath())); |
altimin | 1ab63101 | 2016-08-04 18:43:45 | [diff] [blame] | 214 | } |
| 215 | |
eseckler | d71fc50 | 2016-09-30 10:07:59 | [diff] [blame] | 216 | IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ContextWebPreferences) { |
| 217 | // By default, hide_scrollbars should be false. |
| 218 | EXPECT_FALSE(WebPreferences().hide_scrollbars); |
| 219 | |
| 220 | // Set hide_scrollbars preference to true for a new BrowserContext. |
| 221 | HeadlessBrowserContext* browser_context = |
| 222 | browser() |
| 223 | ->CreateBrowserContextBuilder() |
| 224 | .SetOverrideWebPreferencesCallback( |
Eric Seckler | c27d203bae | 2017-09-27 11:44:57 | [diff] [blame] | 225 | base::Bind([](WebPreferences* preferences) { |
eseckler | d71fc50 | 2016-09-30 10:07:59 | [diff] [blame] | 226 | preferences->hide_scrollbars = true; |
| 227 | })) |
| 228 | .Build(); |
| 229 | HeadlessWebContents* web_contents = |
| 230 | browser_context->CreateWebContentsBuilder() |
| 231 | .SetInitialURL(GURL("about:blank")) |
| 232 | .Build(); |
| 233 | |
| 234 | // Verify that the preference takes effect. |
| 235 | HeadlessWebContentsImpl* contents_impl = |
| 236 | HeadlessWebContentsImpl::From(web_contents); |
| 237 | EXPECT_TRUE(contents_impl->web_contents() |
| 238 | ->GetRenderViewHost() |
| 239 | ->GetWebkitPreferences().hide_scrollbars); |
| 240 | } |
| 241 | |
skyostil | d34af14 | 2016-06-23 17:19:45 | [diff] [blame] | 242 | } // namespace headless |