| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 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 <memory> | 5 #include <memory> |
| 6 | 6 |
| 7 #include "base/memory/ptr_util.h" | 7 #include "base/memory/ptr_util.h" |
| 8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
| 9 #include "content/public/test/browser_test.h" | 9 #include "content/public/test/browser_test.h" |
| 10 #include "headless/public/domains/page.h" | |
| 11 #include "headless/public/domains/runtime.h" | 10 #include "headless/public/domains/runtime.h" |
| 12 #include "headless/public/domains/types.h" | |
| 13 #include "headless/public/headless_browser.h" | 11 #include "headless/public/headless_browser.h" |
| 14 #include "headless/public/headless_browser_context.h" | 12 #include "headless/public/headless_browser_context.h" |
| 15 #include "headless/public/headless_devtools_client.h" | 13 #include "headless/public/headless_devtools_client.h" |
| 16 #include "headless/public/headless_devtools_target.h" | 14 #include "headless/public/headless_devtools_target.h" |
| 17 #include "headless/public/headless_web_contents.h" | 15 #include "headless/public/headless_web_contents.h" |
| 18 #include "headless/test/headless_browser_test.h" | 16 #include "headless/test/headless_browser_test.h" |
| 17 #include "headless/test/test_protocol_handler.h" |
| 19 #include "net/base/io_buffer.h" | 18 #include "net/base/io_buffer.h" |
| 20 #include "net/http/http_response_headers.h" | 19 #include "net/http/http_response_headers.h" |
| 21 #include "net/test/spawned_test_server/spawned_test_server.h" | 20 #include "net/test/spawned_test_server/spawned_test_server.h" |
| 22 #include "net/url_request/url_request_job.h" | 21 #include "net/url_request/url_request_job.h" |
| 23 #include "testing/gtest/include/gtest/gtest.h" | 22 #include "testing/gtest/include/gtest/gtest.h" |
| 24 #include "ui/gfx/geometry/size.h" | 23 #include "ui/gfx/geometry/size.h" |
| 25 | 24 |
| 26 namespace headless { | 25 namespace headless { |
| 27 namespace { | 26 namespace { |
| 28 | |
| 29 class TestURLRequestJob : public net::URLRequestJob { | |
| 30 public: | |
| 31 TestURLRequestJob(net::URLRequest* request, | |
| 32 net::NetworkDelegate* network_delegate, | |
| 33 const std::string& body); | |
| 34 ~TestURLRequestJob() override {} | |
| 35 | |
| 36 // net::URLRequestJob implementation: | |
| 37 void Start() override; | |
| 38 void GetResponseInfo(net::HttpResponseInfo* info) override; | |
| 39 int ReadRawData(net::IOBuffer* buf, int buf_size) override; | |
| 40 | |
| 41 private: | |
| 42 scoped_refptr<net::StringIOBuffer> body_; | |
| 43 scoped_refptr<net::DrainableIOBuffer> src_buf_; | |
| 44 | |
| 45 DISALLOW_COPY_AND_ASSIGN(TestURLRequestJob); | |
| 46 }; | |
| 47 | |
| 48 TestURLRequestJob::TestURLRequestJob(net::URLRequest* request, | |
| 49 net::NetworkDelegate* network_delegate, | |
| 50 const std::string& body) | |
| 51 : net::URLRequestJob(request, network_delegate), | |
| 52 body_(new net::StringIOBuffer(body)), | |
| 53 src_buf_(new net::DrainableIOBuffer(body_.get(), body_->size())) {} | |
| 54 | |
| 55 void TestURLRequestJob::Start() { | |
| 56 NotifyHeadersComplete(); | |
| 57 } | |
| 58 | |
| 59 void TestURLRequestJob::GetResponseInfo(net::HttpResponseInfo* info) { | |
| 60 info->headers = | |
| 61 new net::HttpResponseHeaders("Content-Type: text/html\r\n\r\n"); | |
| 62 } | |
| 63 | |
| 64 int TestURLRequestJob::ReadRawData(net::IOBuffer* buf, int buf_size) { | |
| 65 scoped_refptr<net::DrainableIOBuffer> dest_buf( | |
| 66 new net::DrainableIOBuffer(buf, buf_size)); | |
| 67 while (src_buf_->BytesRemaining() > 0 && dest_buf->BytesRemaining() > 0) { | |
| 68 *dest_buf->data() = *src_buf_->data(); | |
| 69 src_buf_->DidConsume(1); | |
| 70 dest_buf->DidConsume(1); | |
| 71 } | |
| 72 return dest_buf->BytesConsumed(); | |
| 73 } | |
| 74 | |
| 75 class TestProtocolHandler : public net::URLRequestJobFactory::ProtocolHandler { | |
| 76 public: | |
| 77 TestProtocolHandler(const std::string& body); | |
| 78 ~TestProtocolHandler() override {} | |
| 79 | |
| 80 net::URLRequestJob* MaybeCreateJob( | |
| 81 net::URLRequest* request, | |
| 82 net::NetworkDelegate* network_delegate) const override; | |
| 83 | |
| 84 private: | |
| 85 std::string body_; | |
| 86 | |
| 87 DISALLOW_COPY_AND_ASSIGN(TestProtocolHandler); | |
| 88 }; | |
| 89 | |
| 90 TestProtocolHandler::TestProtocolHandler(const std::string& body) | |
| 91 : body_(body) {} | |
| 92 | |
| 93 net::URLRequestJob* TestProtocolHandler::MaybeCreateJob( | |
| 94 net::URLRequest* request, | |
| 95 net::NetworkDelegate* network_delegate) const { | |
| 96 return new TestURLRequestJob(request, network_delegate, body_); | |
| 97 } | |
| 98 | |
| 99 } // namespace | |
| 100 | |
| 101 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateAndDestroyWebContents) { | |
| 102 HeadlessWebContents* web_contents = | |
| 103 browser()->CreateWebContentsBuilder().Build(); | |
| 104 EXPECT_TRUE(web_contents); | |
| 105 | |
| 106 EXPECT_EQ(static_cast<size_t>(1), browser()->GetAllWebContents().size()); | |
| 107 EXPECT_EQ(web_contents, browser()->GetAllWebContents()[0]); | |
| 108 // TODO(skyostil): Verify viewport dimensions once we can. | |
| 109 web_contents->Close(); | |
| 110 | |
| 111 EXPECT_TRUE(browser()->GetAllWebContents().empty()); | |
| 112 } | |
| 113 | |
| 114 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, CreateWithBadURL) { | |
| 115 GURL bad_url("not_valid"); | |
| 116 HeadlessWebContents* web_contents = | |
| 117 browser()->CreateWebContentsBuilder().SetInitialURL(bad_url).Build(); | |
| 118 EXPECT_FALSE(web_contents); | |
| 119 EXPECT_TRUE(browser()->GetAllWebContents().empty()); | |
| 120 } | |
| 121 | |
| 122 class HeadlessBrowserTestWithProxy : public HeadlessBrowserTest { | |
| 123 public: | |
| 124 HeadlessBrowserTestWithProxy() | |
| 125 : proxy_server_(net::SpawnedTestServer::TYPE_HTTP, | |
| 126 net::SpawnedTestServer::kLocalhost, | |
| 127 base::FilePath(FILE_PATH_LITERAL("headless/test/data"))) { | |
| 128 } | |
| 129 | |
| 130 void SetUp() override { | |
| 131 ASSERT_TRUE(proxy_server_.Start()); | |
| 132 HeadlessBrowserTest::SetUp(); | |
| 133 } | |
| 134 | |
| 135 void TearDown() override { | |
| 136 proxy_server_.Stop(); | |
| 137 HeadlessBrowserTest::TearDown(); | |
| 138 } | |
| 139 | |
| 140 net::SpawnedTestServer* proxy_server() { return &proxy_server_; } | |
| 141 | |
| 142 private: | |
| 143 net::SpawnedTestServer proxy_server_; | |
| 144 }; | |
| 145 | |
| 146 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTestWithProxy, SetProxyServer) { | |
| 147 HeadlessBrowser::Options::Builder builder; | |
| 148 builder.SetProxyServer(proxy_server()->host_port_pair()); | |
| 149 SetBrowserOptions(builder.Build()); | |
| 150 | |
| 151 // Load a page which doesn't actually exist, but for which the our proxy | |
| 152 // returns valid content anyway. | |
| 153 // | |
| 154 // TODO(altimin): Currently this construction does not serve hello.html | |
| 155 // from headless/test/data as expected. We should fix this. | |
| 156 HeadlessWebContents* web_contents = | |
| 157 browser() | |
| 158 ->CreateWebContentsBuilder() | |
| 159 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html")) | |
| 160 .Build(); | |
| 161 EXPECT_TRUE(WaitForLoad(web_contents)); | |
| 162 EXPECT_EQ(static_cast<size_t>(1), browser()->GetAllWebContents().size()); | |
| 163 EXPECT_EQ(web_contents, browser()->GetAllWebContents()[0]); | |
| 164 web_contents->Close(); | |
| 165 EXPECT_TRUE(browser()->GetAllWebContents().empty()); | |
| 166 } | |
| 167 | |
| 168 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, SetHostResolverRules) { | |
| 169 EXPECT_TRUE(embedded_test_server()->Start()); | |
| 170 HeadlessBrowser::Options::Builder builder; | |
| 171 builder.SetHostResolverRules( | |
| 172 base::StringPrintf("MAP not-an-actual-domain.tld 127.0.0.1:%d", | |
| 173 embedded_test_server()->host_port_pair().port())); | |
| 174 SetBrowserOptions(builder.Build()); | |
| 175 | |
| 176 // Load a page which doesn't actually exist, but which is turned into a valid | |
| 177 // address by our host resolver rules. | |
| 178 HeadlessWebContents* web_contents = | |
| 179 browser() | |
| 180 ->CreateWebContentsBuilder() | |
| 181 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html")) | |
| 182 .Build(); | |
| 183 EXPECT_TRUE(WaitForLoad(web_contents)); | |
| 184 } | |
| 185 | |
| 186 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, HttpProtocolHandler) { | |
| 187 const std::string kResponseBody = "<p>HTTP response body</p>"; | |
| 188 ProtocolHandlerMap protocol_handlers; | |
| 189 protocol_handlers[url::kHttpScheme] = | |
| 190 base::WrapUnique(new TestProtocolHandler(kResponseBody)); | |
| 191 | |
| 192 HeadlessBrowser::Options::Builder builder; | |
| 193 builder.SetProtocolHandlers(std::move(protocol_handlers)); | |
| 194 SetBrowserOptions(builder.Build()); | |
| 195 | |
| 196 // Load a page which doesn't actually exist, but which is fetched by our | |
| 197 // custom protocol handler. | |
| 198 HeadlessWebContents* web_contents = | |
| 199 browser() | |
| 200 ->CreateWebContentsBuilder() | |
| 201 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html")) | |
| 202 .Build(); | |
| 203 EXPECT_TRUE(WaitForLoad(web_contents)); | |
| 204 | |
| 205 std::string inner_html; | |
| 206 EXPECT_TRUE(EvaluateScript(web_contents, "document.body.innerHTML") | |
| 207 ->GetResult() | |
| 208 ->GetValue() | |
| 209 ->GetAsString(&inner_html)); | |
| 210 EXPECT_EQ(kResponseBody, inner_html); | |
| 211 } | |
| 212 | |
| 213 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, HttpsProtocolHandler) { | |
| 214 const std::string kResponseBody = "<p>HTTPS response body</p>"; | |
| 215 ProtocolHandlerMap protocol_handlers; | |
| 216 protocol_handlers[url::kHttpsScheme] = | |
| 217 base::WrapUnique(new TestProtocolHandler(kResponseBody)); | |
| 218 | |
| 219 HeadlessBrowser::Options::Builder builder; | |
| 220 builder.SetProtocolHandlers(std::move(protocol_handlers)); | |
| 221 SetBrowserOptions(builder.Build()); | |
| 222 | |
| 223 // Load a page which doesn't actually exist, but which is fetched by our | |
| 224 // custom protocol handler. | |
| 225 HeadlessWebContents* web_contents = | |
| 226 browser() | |
| 227 ->CreateWebContentsBuilder() | |
| 228 .SetInitialURL(GURL("https://not-an-actual-domain.tld/hello.html")) | |
| 229 .Build(); | |
| 230 EXPECT_TRUE(WaitForLoad(web_contents)); | |
| 231 | |
| 232 std::string inner_html; | |
| 233 EXPECT_TRUE(EvaluateScript(web_contents, "document.body.innerHTML") | |
| 234 ->GetResult() | |
| 235 ->GetValue() | |
| 236 ->GetAsString(&inner_html)); | |
| 237 EXPECT_EQ(kResponseBody, inner_html); | |
| 238 } | |
| 239 | |
| 240 namespace { | |
| 241 const char kMainPageCookie[] = "mood=quizzical"; | 27 const char kMainPageCookie[] = "mood=quizzical"; |
| 242 const char kIsolatedPageCookie[] = "mood=quixotic"; | 28 const char kIsolatedPageCookie[] = "mood=quixotic"; |
| 243 } // namespace | 29 } // namespace |
| 244 | 30 |
| 245 // This test creates two tabs pointing to the same security origin in two | 31 // This test creates two tabs pointing to the same security origin in two |
| 246 // different browser contexts and checks that they are isolated by creating two | 32 // different browser contexts and checks that they are isolated by creating two |
| 247 // cookies with the same name in both tabs. The steps are: | 33 // cookies with the same name in both tabs. The steps are: |
| 248 // | 34 // |
| 249 // 1. Wait for tab #1 to become ready for DevTools. | 35 // 1. Wait for tab #1 to become ready for DevTools. |
| 250 // 2. Create tab #2 and wait for it to become ready for DevTools. | 36 // 2. Create tab #2 and wait for it to become ready for DevTools. |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 | 149 |
| 364 private: | 150 private: |
| 365 std::unique_ptr<HeadlessBrowserContext> browser_context_; | 151 std::unique_ptr<HeadlessBrowserContext> browser_context_; |
| 366 HeadlessWebContents* web_contents2_; | 152 HeadlessWebContents* web_contents2_; |
| 367 std::unique_ptr<HeadlessDevToolsClient> devtools_client2_; | 153 std::unique_ptr<HeadlessDevToolsClient> devtools_client2_; |
| 368 std::unique_ptr<LoadObserver> load_observer_; | 154 std::unique_ptr<LoadObserver> load_observer_; |
| 369 }; | 155 }; |
| 370 | 156 |
| 371 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessBrowserContextIsolationTest); | 157 HEADLESS_ASYNC_DEVTOOLED_TEST_F(HeadlessBrowserContextIsolationTest); |
| 372 | 158 |
| 159 IN_PROC_BROWSER_TEST_F(HeadlessBrowserTest, ContextProtocolHandler) { |
| 160 const std::string kResponseBody = "<p>HTTP response body</p>"; |
| 161 ProtocolHandlerMap protocol_handlers; |
| 162 protocol_handlers[url::kHttpScheme] = |
| 163 base::WrapUnique(new TestProtocolHandler(kResponseBody)); |
| 164 |
| 165 // Load a page which doesn't actually exist, but which is fetched by our |
| 166 // custom protocol handler. |
| 167 std::unique_ptr<HeadlessBrowserContext> browser_context = |
| 168 browser() |
| 169 ->CreateBrowserContextBuilder() |
| 170 .SetProtocolHandlers(std::move(protocol_handlers)) |
| 171 .Build(); |
| 172 HeadlessWebContents* web_contents = |
| 173 browser() |
| 174 ->CreateWebContentsBuilder() |
| 175 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html")) |
| 176 .SetBrowserContext(browser_context.get()) |
| 177 .Build(); |
| 178 EXPECT_TRUE(WaitForLoad(web_contents)); |
| 179 |
| 180 std::string inner_html; |
| 181 EXPECT_TRUE(EvaluateScript(web_contents, "document.body.innerHTML") |
| 182 ->GetResult() |
| 183 ->GetValue() |
| 184 ->GetAsString(&inner_html)); |
| 185 EXPECT_EQ(kResponseBody, inner_html); |
| 186 web_contents->Close(); |
| 187 |
| 188 // Loading the same non-existent page using a tab with the default context |
| 189 // should not work since the protocol handler only exists on the custom |
| 190 // context. |
| 191 web_contents = |
| 192 browser() |
| 193 ->CreateWebContentsBuilder() |
| 194 .SetInitialURL(GURL("http://not-an-actual-domain.tld/hello.html")) |
| 195 .Build(); |
| 196 EXPECT_TRUE(WaitForLoad(web_contents)); |
| 197 EXPECT_TRUE(EvaluateScript(web_contents, "document.body.innerHTML") |
| 198 ->GetResult() |
| 199 ->GetValue() |
| 200 ->GetAsString(&inner_html)); |
| 201 EXPECT_EQ("", inner_html); |
| 202 web_contents->Close(); |
| 203 } |
| 204 |
| 373 } // namespace headless | 205 } // namespace headless |
| OLD | NEW |