blob: 49ab195c09404837850f8c4a70dfd52a2eb2fb1e [file] [log] [blame]
skyostild34af142016-06-23 17:19:451// 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
altimin93a02402016-08-03 16:26:437#include "base/files/scoped_temp_dir.h"
skyostild34af142016-06-23 17:19:458#include "base/memory/ptr_util.h"
9#include "base/strings/stringprintf.h"
altimin93a02402016-08-03 16:26:4310#include "base/threading/thread_restrictions.h"
esecklerd71fc502016-09-30 10:07:5911#include "content/public/browser/render_view_host.h"
12#include "content/public/browser/web_contents.h"
skyostild34af142016-06-23 17:19:4513#include "content/public/test/browser_test.h"
esecklerd71fc502016-09-30 10:07:5914#include "headless/lib/browser/headless_web_contents_impl.h"
skyostild34af142016-06-23 17:19:4515#include "headless/public/domains/runtime.h"
16#include "headless/public/headless_browser.h"
17#include "headless/public/headless_browser_context.h"
18#include "headless/public/headless_devtools_client.h"
19#include "headless/public/headless_devtools_target.h"
20#include "headless/public/headless_web_contents.h"
21#include "headless/test/headless_browser_test.h"
22#include "headless/test/test_protocol_handler.h"
23#include "net/base/io_buffer.h"
24#include "net/http/http_response_headers.h"
25#include "net/test/spawned_test_server/spawned_test_server.h"
26#include "net/url_request/url_request_job.h"
27#include "testing/gtest/include/gtest/gtest.h"
28#include "ui/gfx/geometry/size.h"
29
30namespace headless {
31namespace {
32const char kMainPageCookie[] = "mood=quizzical";
33const char kIsolatedPageCookie[] = "mood=quixotic";
34} // namespace
35
36// This test creates two tabs pointing to the same security origin in two
37// different browser contexts and checks that they are isolated by creating two
38// cookies with the same name in both tabs. The steps are:
39//
40// 1. Wait for tab #1 to become ready for DevTools.
41// 2. Create tab #2 and wait for it to become ready for DevTools.
42// 3. Navigate tab #1 to the test page and wait for it to finish loading.
43// 4. Navigate tab #2 to the test page and wait for it to finish loading.
44// 5. Set a cookie in tab #1.
45// 6. Set the same cookie in tab #2 to a different value.
46// 7. Read the cookie in tab #1 and check that it has the first value.
47// 8. Read the cookie in tab #2 and check that it has the second value.
48//
49// If the tabs aren't properly isolated, step 7 will fail.
50class HeadlessBrowserContextIsolationTest
51 : public HeadlessAsyncDevTooledBrowserTest {
52 public:
53 HeadlessBrowserContextIsolationTest()
altiminbf875c92016-08-04 17:09:0754 : browser_context_(nullptr),
55 web_contents2_(nullptr),
skyostild34af142016-06-23 17:19:4556 devtools_client2_(HeadlessDevToolsClient::Create()) {
57 EXPECT_TRUE(embedded_test_server()->Start());
58 }
59
60 // HeadlessWebContentsObserver implementation:
61 void DevToolsTargetReady() override {
62 if (!web_contents2_) {
63 browser_context_ = browser()->CreateBrowserContextBuilder().Build();
altimin93a02402016-08-03 16:26:4364 web_contents2_ = browser_context_->CreateWebContentsBuilder().Build();
skyostild34af142016-06-23 17:19:4565 web_contents2_->AddObserver(this);
66 return;
67 }
68
69 web_contents2_->GetDevToolsTarget()->AttachClient(devtools_client2_.get());
70 HeadlessAsyncDevTooledBrowserTest::DevToolsTargetReady();
71 }
72
73 void RunDevTooledTest() override {
74 load_observer_.reset(new LoadObserver(
75 devtools_client_.get(),
76 base::Bind(&HeadlessBrowserContextIsolationTest::OnFirstLoadComplete,
77 base::Unretained(this))));
78 devtools_client_->GetPage()->Navigate(
79 embedded_test_server()->GetURL("/hello.html").spec());
80 }
81
82 void OnFirstLoadComplete() {
83 EXPECT_TRUE(load_observer_->navigation_succeeded());
84 load_observer_.reset(new LoadObserver(
85 devtools_client2_.get(),
86 base::Bind(&HeadlessBrowserContextIsolationTest::OnSecondLoadComplete,
87 base::Unretained(this))));
88 devtools_client2_->GetPage()->Navigate(
89 embedded_test_server()->GetURL("/hello.html").spec());
90 }
91
92 void OnSecondLoadComplete() {
93 EXPECT_TRUE(load_observer_->navigation_succeeded());
94 load_observer_.reset();
95
96 devtools_client_->GetRuntime()->Evaluate(
97 base::StringPrintf("document.cookie = '%s'", kMainPageCookie),
98 base::Bind(&HeadlessBrowserContextIsolationTest::OnFirstSetCookieResult,
99 base::Unretained(this)));
100 }
101
102 void OnFirstSetCookieResult(std::unique_ptr<runtime::EvaluateResult> result) {
103 std::string cookie;
104 EXPECT_TRUE(result->GetResult()->GetValue()->GetAsString(&cookie));
105 EXPECT_EQ(kMainPageCookie, cookie);
106
107 devtools_client2_->GetRuntime()->Evaluate(
108 base::StringPrintf("document.cookie = '%s'", kIsolatedPageCookie),
109 base::Bind(
110 &HeadlessBrowserContextIsolationTest::OnSecondSetCookieResult,
111 base::Unretained(this)));
112 }
113
114 void OnSecondSetCookieResult(
115 std::unique_ptr<runtime::EvaluateResult> result) {
116 std::string cookie;
117 EXPECT_TRUE(result->GetResult()->GetValue()->GetAsString(&cookie));
118 EXPECT_EQ(kIsolatedPageCookie, cookie);
119
120 devtools_client_->GetRuntime()->Evaluate(
121 "document.cookie",
122 base::Bind(&HeadlessBrowserContextIsolationTest::OnFirstGetCookieResult,
123 base::Unretained(this)));
124 }
125
126 void OnFirstGetCookieResult(std::unique_ptr<runtime::EvaluateResult> result) {
127 std::string cookie;
128 EXPECT_TRUE(result->GetResult()->GetValue()->GetAsString(&cookie));
129 EXPECT_EQ(kMainPageCookie, cookie);
130
131 devtools_client2_->GetRuntime()->Evaluate(
132 "document.cookie",
133 base::Bind(
134 &HeadlessBrowserContextIsolationTest::OnSecondGetCookieResult,
135 base::Unretained(this)));
136 }
137
138 void OnSecondGetCookieResult(
139 std::unique_ptr<runtime::EvaluateResult> result) {
140 std::string cookie;
141 EXPECT_TRUE(result->GetResult()->GetValue()->GetAsString(&cookie));
142 EXPECT_EQ(kIsolatedPageCookie, cookie);
143 FinishTest();
144 }
145
146 void FinishTest() {
147 web_contents2_->RemoveObserver(this);
148 web_contents2_->Close();
altiminbf875c92016-08-04 17:09:07149 browser_context_->Close();
skyostild34af142016-06-23 17:19:45150 FinishAsynchronousTest();
151 }
152
153 private:
altiminbf875c92016-08-04 17:09:07154 HeadlessBrowserContext* browser_context_;
skyostild34af142016-06-23 17:19:45155 HeadlessWebContents* web_contents2_;
156 std::unique_ptr<HeadlessDevToolsClient> devtools_client2_;
157 std::unique_ptr<LoadObserver> load_observer_;
158};
159
160HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessBrowserContextIsolationTest);
161
162IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ContextProtocolHandler) {
163 const std::string kResponseBody = "<p>HTTP response body</p>";
164 ProtocolHandlerMap protocol_handlers;
165 protocol_handlers[url::kHttpScheme] =
riceac4bfd812016-08-19 12:06:54166 base::MakeUnique<TestProtocolHandler>(kResponseBody);
skyostild34af142016-06-23 17:19:45167
168 // Load a page which doesn't actually exist, but which is fetched by our
169 // custom protocol handler.
altiminbf875c92016-08-04 17:09:07170 HeadlessBrowserContext* browser_context =
skyostild34af142016-06-23 17:19:45171 browser()
172 ->CreateBrowserContextBuilder()
173 .SetProtocolHandlers(std::move(protocol_handlers))
174 .Build();
175 HeadlessWebContents* web_contents =
altimin93a02402016-08-03 16:26:43176 browser_context->CreateWebContentsBuilder()
skyostild34af142016-06-23 17:19:45177 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html"))
skyostild34af142016-06-23 17:19:45178 .Build();
179 EXPECT_TRUE(WaitForLoad(web_contents));
180
181 std::string inner_html;
182 EXPECT_TRUE(EvaluateScript(web_contents, "document.body.innerHTML")
183 ->GetResult()
184 ->GetValue()
185 ->GetAsString(&inner_html));
186 EXPECT_EQ(kResponseBody, inner_html);
187 web_contents->Close();
188
altiminbf875c92016-08-04 17:09:07189 HeadlessBrowserContext* another_browser_context =
altimin93a02402016-08-03 16:26:43190 browser()->CreateBrowserContextBuilder().Build();
191
192 // Loading the same non-existent page using a tab with a different context
skyostild34af142016-06-23 17:19:45193 // should not work since the protocol handler only exists on the custom
194 // context.
195 web_contents =
altimin93a02402016-08-03 16:26:43196 another_browser_context->CreateWebContentsBuilder()
skyostild34af142016-06-23 17:19:45197 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html"))
198 .Build();
199 EXPECT_TRUE(WaitForLoad(web_contents));
200 EXPECT_TRUE(EvaluateScript(web_contents, "document.body.innerHTML")
201 ->GetResult()
202 ->GetValue()
203 ->GetAsString(&inner_html));
204 EXPECT_EQ("", inner_html);
205 web_contents->Close();
206}
207
altimin93a02402016-08-03 16:26:43208IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, UserDataDir) {
209 // We do not want to bother with posting tasks to create a temp dir.
210 // Just allow IO from main thread for now.
211 base::ThreadRestrictions::SetIOAllowed(true);
212
213 EXPECT_TRUE(embedded_test_server()->Start());
214
215 base::ScopedTempDir user_data_dir;
216 ASSERT_TRUE(user_data_dir.CreateUniqueTempDir());
217
218 // Newly created temp directory should be empty.
vabr16e5f602016-09-15 18:14:00219 EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath()));
altimin93a02402016-08-03 16:26:43220
altiminbf875c92016-08-04 17:09:07221 HeadlessBrowserContext* browser_context =
altimin93a02402016-08-03 16:26:43222 browser()
223 ->CreateBrowserContextBuilder()
vabr16e5f602016-09-15 18:14:00224 .SetUserDataDir(user_data_dir.GetPath())
altimin1ab631012016-08-04 18:43:45225 .SetIncognitoMode(false)
altimin93a02402016-08-03 16:26:43226 .Build();
227
228 HeadlessWebContents* web_contents =
229 browser_context->CreateWebContentsBuilder()
230 .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
231 .Build();
232
233 EXPECT_TRUE(WaitForLoad(web_contents));
234
235 // Something should be written to this directory.
236 // If it is not the case, more complex page may be needed.
237 // ServiceWorkers may be a good option.
vabr16e5f602016-09-15 18:14:00238 EXPECT_FALSE(base::IsDirectoryEmpty(user_data_dir.GetPath()));
altimin93a02402016-08-03 16:26:43239}
240
altimin1ab631012016-08-04 18:43:45241IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, IncognitoMode) {
242 // We do not want to bother with posting tasks to create a temp dir.
243 // Just allow IO from main thread for now.
244 base::ThreadRestrictions::SetIOAllowed(true);
245
246 EXPECT_TRUE(embedded_test_server()->Start());
247
248 base::ScopedTempDir user_data_dir;
249 ASSERT_TRUE(user_data_dir.CreateUniqueTempDir());
250
251 // Newly created temp directory should be empty.
vabr16e5f602016-09-15 18:14:00252 EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath()));
altimin1ab631012016-08-04 18:43:45253
254 HeadlessBrowserContext* browser_context =
255 browser()
256 ->CreateBrowserContextBuilder()
vabr16e5f602016-09-15 18:14:00257 .SetUserDataDir(user_data_dir.GetPath())
altimin1ab631012016-08-04 18:43:45258 .SetIncognitoMode(true)
259 .Build();
260
261 HeadlessWebContents* web_contents =
262 browser_context->CreateWebContentsBuilder()
263 .SetInitialURL(embedded_test_server()->GetURL("/hello.html"))
264 .Build();
265
266 EXPECT_TRUE(WaitForLoad(web_contents));
267
268 // Similar to test above, but now we are in incognito mode,
269 // so nothing should be written to this directory.
vabr16e5f602016-09-15 18:14:00270 EXPECT_TRUE(base::IsDirectoryEmpty(user_data_dir.GetPath()));
altimin1ab631012016-08-04 18:43:45271}
272
esecklerd71fc502016-09-30 10:07:59273IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ContextWebPreferences) {
274 // By default, hide_scrollbars should be false.
275 EXPECT_FALSE(WebPreferences().hide_scrollbars);
276
277 // Set hide_scrollbars preference to true for a new BrowserContext.
278 HeadlessBrowserContext* browser_context =
279 browser()
280 ->CreateBrowserContextBuilder()
281 .SetOverrideWebPreferencesCallback(
282 base::Bind([](headless::WebPreferences* preferences) {
283 preferences->hide_scrollbars = true;
284 }))
285 .Build();
286 HeadlessWebContents* web_contents =
287 browser_context->CreateWebContentsBuilder()
288 .SetInitialURL(GURL("about:blank"))
289 .Build();
290
291 // Verify that the preference takes effect.
292 HeadlessWebContentsImpl* contents_impl =
293 HeadlessWebContentsImpl::From(web_contents);
294 EXPECT_TRUE(contents_impl->web_contents()
295 ->GetRenderViewHost()
296 ->GetWebkitPreferences().hide_scrollbars);
297}
298
skyostild34af142016-06-23 17:19:45299} // namespace headless