blob: 373ba2038cf8e5ddc2b2b6ac23af6c270ad7dc72 [file] [log] [blame]
// Copyright 2020 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 THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_WEB_MESSAGE_PORT_H_
#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_WEB_MESSAGE_PORT_H_
#include <utility>
#include "base/strings/string16.h"
#include "mojo/public/cpp/bindings/connector.h"
#include "mojo/public/cpp/bindings/message.h"
#include "third_party/blink/public/common/common_export.h"
#include "third_party/blink/public/common/messaging/message_port_descriptor.h"
namespace blink {
// Defines a WebMessagePort, which is used by embedders to send and receive
// messages to and from Javascript content. This is a simplified version of the
// full MessagePort concept implemented by renderer/core/messaging/message_port.
// It is a lightweight wrapper of a Mojo message pipe, and provides
// functionality for sending and receiving messages that consist of text content
// and a vector of ports, automatically handling the message serialization and
// formatting. Note the Mojo pipe is bound in SINGLE_THREADED_SEND mode. If you
// need to send more complex message types then refer to transferable_message.*
// and string_message_codec.*.
//
// Intended embedder usage is as follows:
//
// // Create a pair of ports. The two ends of the pipe are conjugates of each
// // other.
// std::pair<WebMessagePort, WebMessagePort> ports =
// WebMessagePort::CreatePair();
//
// // Keep one end for ourselves.
// MessageReceiverImpl receiver; // Implements MessageReceiver.
// auto embedder_port = std::move(ports.first);
// embedder_port.SetReceiver(&receiver, task_runner);
//
// // Send the other end of the pipe to a WebContents. This will arrive in the
// // main frame of that WebContents. See
// // content/browser/public/message_port_provider.h for the API that allows
// // this injection.
// std::vector<MessagePortDescriptor> ports;
// ports.emplace_back(ports.second.PassPort());
// MessagePortProvider::PostMessageToFrame(
// web_contents, ..., std::move(ports));
//
// // The web contents can now talk back to us via |embedder_port|, and we can
// // talk back directly to it over that same pipe.
//
// Note that some embedders provide "PostMessageToFrame" functions directly on
// their wrapped WebContents equivalents (Android and Cast, for example). Also
// note that for Android embedders, there are equivalent Java interfaces defined
// in org.chromium.content_public.browser.
//
// This is a move-only type, which makes it (almost) impossible to try to send a
// port across itself (which is illegal). This doesn't explicitly prevent you
// from sending a port's conjugate port to its conjugate, but note that the
// underlying impl will close the pipe with an error if you do that.
//
// This object is not thread safe, and is intended to be used from a single
// sequence. The sequence from which it is used does not have to be the same
// sequence that the bound receiver uses.
//
// Further note that a WebMessagePort is not "reusable". That is, once it has
// been bound via SetReceiver, it is no longer transmittable (can't be passed as
// a port in part of a Message). This is enforced via runtime CHECKs.
class BLINK_COMMON_EXPORT WebMessagePort : public mojo::MessageReceiver {
public:
// See below for definitions.
struct Message;
class MessageReceiver;
WebMessagePort();
WebMessagePort(const WebMessagePort&) = delete;
WebMessagePort(WebMessagePort&&);
WebMessagePort& operator=(const WebMessagePort&) = delete;
WebMessagePort& operator=(WebMessagePort&&);
~WebMessagePort() override;
// Factory function for creating two ends of a message channel. The two ports
// are conjugates of each other.
static std::pair<WebMessagePort, WebMessagePort> CreatePair();
// Sets a message receiver for this message port. Once bound any incoming
// messages to this port will be routed to the provided |receiver| with
// callbacks invoked on the provided |runner|. Note that if you set a receiver
// *after* a pipe has already transitioned to being in error, you will not
// receive an "OnPipeError" callback; you should instead manually check
// "is_errored" before setting the receiver. Once a receiver has been set a
// WebMessagePort is no longer transferable.
void SetReceiver(MessageReceiver* receiver,
scoped_refptr<base::SequencedTaskRunner> runner);
// Clears the message receiver for this message port. Without a receiver
// incoming messages will be queued on the port until a receiver is set.
// Note that it is possible that there are pending message tasks already
// posted to the previous |receiver|, thus the previous |receiver| may
// continue to be invoked after calling this.
void ClearReceiver();
// Returns true if this WebMessagePort currently has a receiver.
bool HasReceiver() const { return receiver_; }
// Returns the receiver to which this WebMessagePort is bound. This can
// return nullptr if it has not been bound to a receiver.
MessageReceiver* receiver() const { return receiver_; }
// Returns the task runner to which this WebMessagePort is bound. This can
// return nullptr if the port is not bound to a receiver.
base::SequencedTaskRunner* GetTaskRunner() const;
// Returns true if its safe to post a message to this message port. That is,
// a receiver has been set and the pipe is open and not in an error state.
bool CanPostMessage() const;
// Transmits a |message| over this port. If the port is in a state such that
// "CanPostMessage" returns false then the message is dropped and this will
// return false. Returns true if the message was actually accepted to be sent.
// Note that this does not guarantee delivery, as the other end of the pipe
// could be closed before the message is processed on the remote end.
bool PostMessage(Message&& message);
// Returns true if this port is bound to a valid message pipe.
bool IsValid() const;
// Returns true if this WebMessagePort has been closed.
bool is_closed() const { return is_closed_; }
// Returns true if this WebMessagePort has experienced an error.
bool is_errored() const { return is_errored_; }
// Returns true if this WebMessagePort is transferable as part of a
// Message. This is true for a brand new WebMessagePort, but becomes false
// if SetReceiver is ever called.
bool is_transferable() const { return is_transferable_; }
// Closes this message port. This also clears the receiver, if it is set.
// After calling this "is_closed" will return true, "is_transferable" will
// return false, and "is_errored" will retain the state it had before the pipe
// was closed. This function can be called at any time, and repeatedly.
void Close();
// Reset this WebMessagePort to a completely default state. Similar to
// close, but also resets the "is_closed", "is_errored" and "is_transferable"
// states. Can be called at any time, and repeatedly.
void Reset();
// Passes out the underlying port descriptor. This port will be reset after
// calling this (all of "IsValid", "is_closed" and "is_errored" will return
// false). This can only be called if "is_transferable()" returns true.
MessagePortDescriptor PassPort();
private:
// Creates a message port that wraps the provided |port|. This provided |port|
// must be valid. This is private as it should only be called by message
// deserialization code, or the CreatePair factory.
explicit WebMessagePort(MessagePortDescriptor&& port);
void Take(WebMessagePort&& other);
void OnPipeError();
void CloseIfNecessary();
// mojo::MessageReceiver implementation:
bool Accept(mojo::Message* mojo_message) override;
MessagePortDescriptor port_;
std::unique_ptr<mojo::Connector> connector_;
bool is_closed_ = true;
bool is_errored_ = false;
bool is_transferable_ = false;
MessageReceiver* receiver_ = nullptr;
};
// A very simple message format. This is a subset of a TransferableMessage, as
// many of the fields in the full message type aren't appropriate for messages
// originating from the embedder.
struct BLINK_COMMON_EXPORT WebMessagePort::Message {
Message();
Message(const Message&) = delete;
Message(Message&&);
Message& operator=(const Message&) = delete;
Message& operator=(Message&&);
~Message();
// Creates a message with the given |data|.
explicit Message(const base::string16& data);
// Creates a message with the given collection of |ports| to be transferred.
explicit Message(std::vector<WebMessagePort> ports);
// Creates a message with a single |port| to be transferred.
explicit Message(WebMessagePort&& port);
// Creates a message with |data| and a collection of |ports| to be
// transferred.
Message(const base::string16& data, std::vector<WebMessagePort> ports);
// Creates a message with |data| and a single |port| to be transferred.
Message(const base::string16& data, WebMessagePort port);
// A UTF-16 message.
base::string16 data;
// Other message ports that are to be transmitted as part of this message.
std::vector<WebMessagePort> ports;
};
// Interface to be implemented by receivers.
class BLINK_COMMON_EXPORT WebMessagePort::MessageReceiver {
public:
MessageReceiver();
MessageReceiver(const MessageReceiver&) = delete;
MessageReceiver(MessageReceiver&&) = delete;
MessageReceiver& operator=(const MessageReceiver&) = delete;
MessageReceiver& operator=(MessageReceiver&&) = delete;
virtual ~MessageReceiver();
// Called for each incoming |message|. Returns false if the message could not
// be successfully handled, in which case the pipe should be torn-down and
// OnPipeError() invoked.
virtual bool OnMessage(Message message);
// Invoked when the underlying pipe has experienced an error.
virtual void OnPipeError() {}
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_WEB_MESSAGE_PORT_H_