Validate incoming JS Message Headers: test message parser
[chromium-blink-merge.git] / content / browser / webui / web_ui_mojo_browsertest.cc
blob17b1bc8c41b40392407b886e3a831f76996dd305
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
3 // found in the LICENSE file.
5 #include <limits>
7 #include "base/command_line.h"
8 #include "base/file_util.h"
9 #include "base/files/file_path.h"
10 #include "base/path_service.h"
11 #include "base/run_loop.h"
12 #include "base/strings/string_util.h"
13 #include "content/browser/webui/web_ui_controller_factory_registry.h"
14 #include "content/public/browser/browser_context.h"
15 #include "content/public/browser/render_frame_host.h"
16 #include "content/public/browser/render_process_host.h"
17 #include "content/public/browser/render_view_host.h"
18 #include "content/public/browser/web_contents.h"
19 #include "content/public/browser/web_ui_controller.h"
20 #include "content/public/browser/web_ui_data_source.h"
21 #include "content/public/common/content_paths.h"
22 #include "content/public/common/content_switches.h"
23 #include "content/public/common/service_registry.h"
24 #include "content/public/common/url_utils.h"
25 #include "content/public/test/content_browser_test.h"
26 #include "content/public/test/content_browser_test_utils.h"
27 #include "content/shell/browser/shell.h"
28 #include "content/test/data/web_ui_test_mojo_bindings.mojom.h"
29 #include "grit/content_resources.h"
30 #include "mojo/common/test/test_utils.h"
31 #include "mojo/public/js/bindings/constants.h"
33 namespace content {
34 namespace {
36 bool got_message = false;
38 // The bindings for the page are generated from a .mojom file. This code looks
39 // up the generated file from disk and returns it.
40 bool GetResource(const std::string& id,
41 const WebUIDataSource::GotDataCallback& callback) {
42 // These are handled by the WebUIDataSource that AddMojoDataSource() creates.
43 if (id == mojo::kBufferModuleName ||
44 id == mojo::kCodecModuleName ||
45 id == mojo::kConnectionModuleName ||
46 id == mojo::kConnectorModuleName ||
47 id == mojo::kUnicodeModuleName ||
48 id == mojo::kRouterModuleName)
49 return false;
51 std::string contents;
52 CHECK(base::ReadFileToString(mojo::test::GetFilePathForJSResource(id),
53 &contents,
54 std::string::npos)) << id;
55 base::RefCountedString* ref_contents = new base::RefCountedString;
56 ref_contents->data() = contents;
57 callback.Run(ref_contents);
58 return true;
61 class BrowserTargetImpl : public BrowserTarget {
62 public:
63 BrowserTargetImpl(mojo::ScopedMessagePipeHandle handle,
64 base::RunLoop* run_loop)
65 : run_loop_(run_loop) {
66 renderer_.Bind(handle.Pass());
67 renderer_.set_client(this);
70 virtual ~BrowserTargetImpl() {}
72 // BrowserTarget overrides:
73 virtual void PingResponse() OVERRIDE {
74 NOTREACHED();
77 protected:
78 RendererTargetPtr renderer_;
79 base::RunLoop* run_loop_;
81 private:
82 DISALLOW_COPY_AND_ASSIGN(BrowserTargetImpl);
85 class PingBrowserTargetImpl : public BrowserTargetImpl {
86 public:
87 PingBrowserTargetImpl(mojo::ScopedMessagePipeHandle handle,
88 base::RunLoop* run_loop)
89 : BrowserTargetImpl(handle.Pass(), run_loop) {
90 renderer_->Ping();
93 virtual ~PingBrowserTargetImpl() {}
95 // BrowserTarget overrides:
96 // Quit the RunLoop when called.
97 virtual void PingResponse() OVERRIDE {
98 got_message = true;
99 run_loop_->Quit();
102 private:
103 DISALLOW_COPY_AND_ASSIGN(PingBrowserTargetImpl);
106 // WebUIController that sets up mojo bindings.
107 class TestWebUIController : public WebUIController {
108 public:
109 TestWebUIController(WebUI* web_ui, base::RunLoop* run_loop)
110 : WebUIController(web_ui),
111 run_loop_(run_loop) {
112 content::WebUIDataSource* data_source =
113 WebUIDataSource::AddMojoDataSource(
114 web_ui->GetWebContents()->GetBrowserContext());
115 data_source->SetRequestFilter(base::Bind(&GetResource));
118 protected:
119 base::RunLoop* run_loop_;
120 scoped_ptr<BrowserTargetImpl> browser_target_;
122 private:
123 DISALLOW_COPY_AND_ASSIGN(TestWebUIController);
126 // TestWebUIController that additionally creates the ping test BrowserTarget
127 // implementation at the right time.
128 class PingTestWebUIController : public TestWebUIController {
129 public:
130 PingTestWebUIController(WebUI* web_ui, base::RunLoop* run_loop)
131 : TestWebUIController(web_ui, run_loop) {
133 virtual ~PingTestWebUIController() {}
135 // WebUIController overrides:
136 virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE {
137 render_view_host->GetMainFrame()->GetServiceRegistry()->AddService(
138 "webui_controller",
139 base::Bind(&PingTestWebUIController::CreateHandler,
140 base::Unretained(this)));
143 void CreateHandler(mojo::ScopedMessagePipeHandle handle) {
144 browser_target_.reset(new PingBrowserTargetImpl(handle.Pass(), run_loop_));
147 private:
148 DISALLOW_COPY_AND_ASSIGN(PingTestWebUIController);
151 // WebUIControllerFactory that creates TestWebUIController.
152 class TestWebUIControllerFactory : public WebUIControllerFactory {
153 public:
154 TestWebUIControllerFactory() : run_loop_(NULL) {}
156 void set_run_loop(base::RunLoop* run_loop) { run_loop_ = run_loop; }
158 virtual WebUIController* CreateWebUIControllerForURL(
159 WebUI* web_ui, const GURL& url) const OVERRIDE {
160 if (url.query() == "ping")
161 return new PingTestWebUIController(web_ui, run_loop_);
162 return NULL;
164 virtual WebUI::TypeID GetWebUIType(BrowserContext* browser_context,
165 const GURL& url) const OVERRIDE {
166 return reinterpret_cast<WebUI::TypeID>(1);
168 virtual bool UseWebUIForURL(BrowserContext* browser_context,
169 const GURL& url) const OVERRIDE {
170 return true;
172 virtual bool UseWebUIBindingsForURL(BrowserContext* browser_context,
173 const GURL& url) const OVERRIDE {
174 return true;
177 private:
178 base::RunLoop* run_loop_;
180 DISALLOW_COPY_AND_ASSIGN(TestWebUIControllerFactory);
183 class WebUIMojoTest : public ContentBrowserTest {
184 public:
185 WebUIMojoTest() {
186 WebUIControllerFactory::RegisterFactory(&factory_);
189 virtual ~WebUIMojoTest() {
190 WebUIControllerFactory::UnregisterFactoryForTesting(&factory_);
193 TestWebUIControllerFactory* factory() { return &factory_; }
195 private:
196 TestWebUIControllerFactory factory_;
198 DISALLOW_COPY_AND_ASSIGN(WebUIMojoTest);
201 // Loads a webui page that contains mojo bindings and verifies a message makes
202 // it from the browser to the page and back.
203 IN_PROC_BROWSER_TEST_F(WebUIMojoTest, EndToEndPing) {
204 // Currently there is no way to have a generated file included in the isolate
205 // files. If the bindings file doesn't exist assume we're on such a bot and
206 // pass.
207 // TODO(sky): remove this conditional when isolates support copying from gen.
208 const base::FilePath test_file_path(
209 mojo::test::GetFilePathForJSResource(
210 "content/test/data/web_ui_test_mojo_bindings.mojom"));
211 if (!base::PathExists(test_file_path)) {
212 LOG(WARNING) << " mojom binding file doesn't exist, assuming on isolate";
213 return;
216 got_message = false;
217 ASSERT_TRUE(test_server()->Start());
218 base::RunLoop run_loop;
219 factory()->set_run_loop(&run_loop);
220 GURL test_url(test_server()->GetURL("files/web_ui_mojo.html?ping"));
221 NavigateToURL(shell(), test_url);
222 // RunLoop is quit when message received from page.
223 run_loop.Run();
224 EXPECT_TRUE(got_message);
226 // Check that a second render frame in the same renderer process works
227 // correctly.
228 Shell* other_shell = CreateBrowser();
229 got_message = false;
230 base::RunLoop other_run_loop;
231 factory()->set_run_loop(&other_run_loop);
232 NavigateToURL(other_shell, test_url);
233 // RunLoop is quit when message received from page.
234 other_run_loop.Run();
235 EXPECT_TRUE(got_message);
236 EXPECT_EQ(shell()->web_contents()->GetRenderProcessHost(),
237 other_shell->web_contents()->GetRenderProcessHost());
240 } // namespace
241 } // namespace content