blob: 044f9840f18d04f2d5e3deb82cfd56038d04b105 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_PUBLIC_BROWSER_WEB_UI_MESSAGE_HANDLER_H_
#define CONTENT_PUBLIC_BROWSER_WEB_UI_MESSAGE_HANDLER_H_
#include <vector>
#include "base/gtest_prod_util.h"
#include "base/logging.h"
#include "base/strings/string16.h"
#include "base/values.h"
#include "content/common/content_export.h"
#include "content/public/browser/web_ui.h"
class WebUIBrowserTest;
class MojoWebUIBrowserTest;
namespace base {
class ListValue;
}
namespace content {
class TestWebUI;
class WebUI;
class WebUIImpl;
// Messages sent from the DOM are forwarded via the WebUI to handler
// classes. These objects are owned by WebUI and destroyed when the
// host is destroyed.
class CONTENT_EXPORT WebUIMessageHandler {
public:
WebUIMessageHandler() : javascript_allowed_(false), web_ui_(nullptr) {}
virtual ~WebUIMessageHandler() {}
// Call this when a page should not receive JavaScript messages.
void DisallowJavascript();
// Called from tests to toggle JavaScript to catch bugs. If AllowJavascript()
// is needed from production code, just publicize AllowJavascript() instead.
void AllowJavascriptForTesting();
bool IsJavascriptAllowed() const;
protected:
FRIEND_TEST_ALL_PREFIXES(WebUIMessageHandlerTest, ExtractIntegerValue);
FRIEND_TEST_ALL_PREFIXES(WebUIMessageHandlerTest, ExtractDoubleValue);
FRIEND_TEST_ALL_PREFIXES(WebUIMessageHandlerTest, ExtractStringValue);
// This method must be called once the handler's corresponding JavaScript
// component is initialized. In practice, it should be called from a WebUI
// message handler similar to: 'initializeFooPage' or 'getInitialState'.
//
// There should be ideally one or two calls to this per handler, as JavaScript
// components should have a specific message that signals that it's initalized
// and ready to receive events from the C++ handler.
//
// This should never be called from a function that is not a message handler.
// This should never be called from a C++ callback used as a reply for a
// posted task or asynchronous operation.
void AllowJavascript();
// Helper methods:
// Extract an integer value from a list Value.
static bool ExtractIntegerValue(const base::ListValue* value, int* out_int);
// Extract a floating point (double) value from a list Value.
static bool ExtractDoubleValue(const base::ListValue* value,
double* out_value);
// Extract a string value from a list Value.
static base::string16 ExtractStringValue(const base::ListValue* value);
// This is where subclasses specify which messages they'd like to handle and
// perform any additional initialization.. At this point web_ui() will return
// the associated WebUI object.
virtual void RegisterMessages() = 0;
// Will be called whenever JavaScript from this handler becomes allowed from
// the disallowed state. Subclasses should override this method to register
// observers that push JavaScript calls to the page.
virtual void OnJavascriptAllowed() {}
// Will be called whenever JavaScript from this handler becomes disallowed
// from the allowed state. This will never be called before
// OnJavascriptAllowed has been called. Subclasses should override this method
// to deregister or disabled observers that push JavaScript calls to the page.
virtual void OnJavascriptDisallowed() {}
// Helper method for responding to Javascript requests initiated with
// cr.sendWithPromise() (defined in cr.js) for the case where the returned
// promise should be resolved (request succeeded).
void ResolveJavascriptCallback(const base::Value& callback_id,
const base::Value& response);
// Helper method for responding to Javascript requests initiated with
// cr.sendWithPromise() (defined in cr.js), for the case where the returned
// promise should be rejected (request failed).
void RejectJavascriptCallback(const base::Value& callback_id,
const base::Value& response);
// Helper method for notifying Javascript listeners added with
// cr.addWebUIListener() (defined in cr.js).
template <typename... Values>
void FireWebUIListener(const std::string& event_name,
const Values&... values) {
// cr.webUIListenerCallback is a global JS function exposed from cr.js.
CallJavascriptFunction("cr.webUIListenerCallback", base::Value(event_name),
values...);
}
// Call a Javascript function by sending its name and arguments down to
// the renderer. This is asynchronous; there's no way to get the result
// of the call, and should be thought of more like sending a message to
// the page.
// All function names in WebUI must consist of only ASCII characters.
// These functions will crash if JavaScript is not currently allowed.
template <typename... Values>
void CallJavascriptFunction(const std::string& function_name,
const Values&... values) {
CHECK(IsJavascriptAllowed()) << "Cannot CallJavascriptFunction before "
"explicitly allowing JavaScript.";
// The CHECK above makes this call safe.
web_ui()->CallJavascriptFunctionUnsafe(function_name, values...);
}
// Returns the attached WebUI for this handler.
WebUI* web_ui() const { return web_ui_; }
// Sets the attached WebUI - exposed to subclasses for testing purposes.
void set_web_ui(WebUI* web_ui) { web_ui_ = web_ui; }
private:
// Provide external classes access to web_ui(), set_web_ui(), and
// RenderViewReused.
friend class TestWebUI;
friend class WebUIImpl;
friend class ::WebUIBrowserTest;
friend class ::MojoWebUIBrowserTest;
// TODO(dbeam): disallow JavaScript when a renderer process crashes.
// http://crbug.com/610450
// True if the page is for JavaScript calls from this handler.
bool javascript_allowed_;
WebUI* web_ui_;
};
} // namespace content
#endif // CONTENT_PUBLIC_BROWSER_WEB_UI_MESSAGE_HANDLER_H_