• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2014 Marshall A. Greenblatt. All rights reserved.
2 //
3 // Redistribution and use in source and binary forms, with or without
4 // modification, are permitted provided that the following conditions are
5 // met:
6 //
7 //    * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //    * Redistributions in binary form must reproduce the above
10 // copyright notice, this list of conditions and the following disclaimer
11 // in the documentation and/or other materials provided with the
12 // distribution.
13 //    * Neither the name of Google Inc. nor the name Chromium Embedded
14 // Framework nor the names of its contributors may be used to endorse
15 // or promote products derived from this software without specific prior
16 // written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // ---------------------------------------------------------------------------
31 //
32 // The contents of this file are only available to applications that link
33 // against the libcef_dll_wrapper target.
34 //
35 
36 #ifndef CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
37 #define CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
38 #pragma once
39 
40 #include "include/base/cef_ref_counted.h"
41 #include "include/cef_base.h"
42 #include "include/cef_browser.h"
43 #include "include/cef_process_message.h"
44 #include "include/cef_v8.h"
45 
46 // The below classes implement support for routing aynchronous messages between
47 // JavaScript running in the renderer process and C++ running in the browser
48 // process. An application interacts with the router by passing it data from
49 // standard CEF C++ callbacks (OnBeforeBrowse, OnProcessMessageReceived,
50 // OnContextCreated, etc). The renderer-side router supports generic JavaScript
51 // callback registration and execution while the browser-side router supports
52 // application-specific logic via one or more application-provided Handler
53 // instances.
54 //
55 // The renderer-side router implementation exposes a query function and a cancel
56 // function via the JavaScript 'window' object:
57 //
58 //    // Create and send a new query.
59 //    var request_id = window.cefQuery({
60 //        request: 'my_request',
61 //        persistent: false,
62 //        onSuccess: function(response) {},
63 //        onFailure: function(error_code, error_message) {}
64 //    });
65 //
66 //    // Optionally cancel the query.
67 //    window.cefQueryCancel(request_id);
68 //
69 // When |window.cefQuery| is executed the request is sent asynchronously to one
70 // or more C++ Handler objects registered in the browser process. Each C++
71 // Handler can choose to either handle or ignore the query in the
72 // Handler::OnQuery callback. If a Handler chooses to handle the query then it
73 // should execute Callback::Success when a response is available or
74 // Callback::Failure if an error occurs. This will result in asynchronous
75 // execution of the associated JavaScript callback in the renderer process. Any
76 // queries unhandled by C++ code in the browser process will be automatically
77 // canceled and the associated JavaScript onFailure callback will be executed
78 // with an error code of -1.
79 //
80 // Queries can be either persistent or non-persistent. If the query is
81 // persistent then the callbacks will remain registered until one of the
82 // following conditions are met:
83 //
84 // A. The query is canceled in JavaScript using the |window.cefQueryCancel|
85 //    function.
86 // B. The query is canceled in C++ code using the Callback::Failure function.
87 // C. The context associated with the query is released due to browser
88 //    destruction, navigation or renderer process termination.
89 //
90 // If the query is non-persistent then the registration will be removed after
91 // the JavaScript callback is executed a single time. If a query is canceled for
92 // a reason other than Callback::Failure being executed then the associated
93 // Handler's OnQueryCanceled method will be called.
94 //
95 // Some possible usage patterns include:
96 //
97 // One-time Request. Use a non-persistent query to send a JavaScript request.
98 //    The Handler evaluates the request and returns the response. The query is
99 //    then discarded.
100 //
101 // Broadcast. Use a persistent query to register as a JavaScript broadcast
102 //    receiver. The Handler keeps track of all registered Callbacks and executes
103 //    them sequentially to deliver the broadcast message.
104 //
105 // Subscription. Use a persistent query to register as a JavaScript subscription
106 //    receiver. The Handler initiates the subscription feed on the first request
107 //    and delivers responses to all registered subscribers as they become
108 //    available. The Handler cancels the subscription feed when there are no
109 //    longer any registered JavaScript receivers.
110 //
111 // Message routing occurs on a per-browser and per-context basis. Consequently,
112 // additional application logic can be applied by restricting which browser or
113 // context instances are passed into the router. If you choose to use this
114 // approach do so cautiously. In order for the router to function correctly any
115 // browser or context instance passed into a single router callback must then
116 // be passed into all router callbacks.
117 //
118 // There is generally no need to have multiple renderer-side routers unless you
119 // wish to have multiple bindings with different JavaScript function names. It
120 // can be useful to have multiple browser-side routers with different client-
121 // provided Handler instances when implementing different behaviors on a per-
122 // browser basis.
123 //
124 // This implementation places no formatting restrictions on payload content.
125 // An application may choose to exchange anything from simple formatted
126 // strings to serialized XML or JSON data.
127 //
128 //
129 // EXAMPLE USAGE
130 //
131 // 1. Define the router configuration. You can optionally specify settings
132 //    like the JavaScript function names. The configuration must be the same in
133 //    both the browser and renderer processes. If using multiple routers in the
134 //    same application make sure to specify unique function names for each
135 //    router configuration.
136 //
137 //    // Example config object showing the default values.
138 //    CefMessageRouterConfig config;
139 //    config.js_query_function = "cefQuery";
140 //    config.js_cancel_function = "cefQueryCancel";
141 //
142 // 2. Create an instance of CefMessageRouterBrowserSide in the browser process.
143 //    You might choose to make it a member of your CefClient implementation,
144 //    for example.
145 //
146 //    browser_side_router_ = CefMessageRouterBrowserSide::Create(config);
147 //
148 // 3. Register one or more Handlers. The Handler instances must either outlive
149 //    the router or be removed from the router before they're deleted.
150 //
151 //    browser_side_router_->AddHandler(my_handler);
152 //
153 // 4. Call all required CefMessageRouterBrowserSide methods from other callbacks
154 //    in your CefClient implementation (OnBeforeClose, etc). See the
155 //    CefMessageRouterBrowserSide class documentation for the complete list of
156 //    methods.
157 //
158 // 5. Create an instance of CefMessageRouterRendererSide in the renderer
159 // process.
160 //    You might choose to make it a member of your CefApp implementation, for
161 //    example.
162 //
163 //    renderer_side_router_ = CefMessageRouterRendererSide::Create(config);
164 //
165 // 6. Call all required CefMessageRouterRendererSide methods from other
166 //    callbacks in your CefRenderProcessHandler implementation
167 //    (OnContextCreated, etc). See the CefMessageRouterRendererSide class
168 //    documentation for the complete list of methods.
169 //
170 // 7. Execute the query function from JavaScript code.
171 //
172 //    window.cefQuery({request: 'my_request',
173 //                     persistent: false,
174 //                     onSuccess: function(response) { print(response); },
175 //                     onFailure: function(error_code, error_message) {} });
176 //
177 // 8. Handle the query in your Handler::OnQuery implementation and execute the
178 //    appropriate callback either immediately or asynchronously.
179 //
180 //    void MyHandler::OnQuery(int64 query_id,
181 //                            CefRefPtr<CefBrowser> browser,
182 //                            CefRefPtr<CefFrame> frame,
183 //                            const CefString& request,
184 //                            bool persistent,
185 //                            CefRefPtr<Callback> callback) {
186 //      if (request == "my_request") {
187 //        callback->Continue("my_response");
188 //        return true;
189 //      }
190 //      return false;  // Not handled.
191 //    }
192 //
193 // 9. Notice that the onSuccess callback is executed in JavaScript.
194 
195 ///
196 // Used to configure the query router. The same values must be passed to both
197 // CefMessageRouterBrowserSide and CefMessageRouterRendererSide. If using
198 // multiple router pairs make sure to choose values that do not conflict.
199 ///
200 struct CefMessageRouterConfig {
201   CefMessageRouterConfig();
202 
203   // Name of the JavaScript function that will be added to the 'window' object
204   // for sending a query. The default value is "cefQuery".
205   CefString js_query_function;
206 
207   // Name of the JavaScript function that will be added to the 'window' object
208   // for canceling a pending query. The default value is "cefQueryCancel".
209   CefString js_cancel_function;
210 };
211 
212 ///
213 // Implements the browser side of query routing. The methods of this class may
214 // be called on any browser process thread unless otherwise indicated.
215 ///
216 class CefMessageRouterBrowserSide
217     : public base::RefCountedThreadSafe<CefMessageRouterBrowserSide> {
218  public:
219   ///
220   // Callback associated with a single pending asynchronous query. Execute the
221   // Success or Failure method to send an asynchronous response to the
222   // associated JavaScript handler. It is a runtime error to destroy a Callback
223   // object associated with an uncanceled query without first executing one of
224   // the callback methods. The methods of this class may be called on any
225   // browser process thread.
226   ///
227   class Callback : public CefBaseRefCounted {
228    public:
229     ///
230     // Notify the associated JavaScript onSuccess callback that the query has
231     // completed successfully with the specified |response|.
232     ///
233     virtual void Success(const CefString& response) = 0;
234 
235     ///
236     // Notify the associated JavaScript onFailure callback that the query has
237     // failed with the specified |error_code| and |error_message|.
238     ///
239     virtual void Failure(int error_code, const CefString& error_message) = 0;
240   };
241 
242   ///
243   // Implement this interface to handle queries. All methods will be executed on
244   // the browser process UI thread.
245   ///
246   class Handler {
247    public:
248     using Callback = CefMessageRouterBrowserSide::Callback;
249 
250     ///
251     // Executed when a new query is received. |query_id| uniquely identifies the
252     // query for the life span of the router. Return true to handle the query
253     // or false to propagate the query to other registered handlers, if any. If
254     // no handlers return true from this method then the query will be
255     // automatically canceled with an error code of -1 delivered to the
256     // JavaScript onFailure callback. If this method returns true then a
257     // Callback method must be executed either in this method or asynchronously
258     // to complete the query.
259     ///
OnQuery(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id,const CefString & request,bool persistent,CefRefPtr<Callback> callback)260     virtual bool OnQuery(CefRefPtr<CefBrowser> browser,
261                          CefRefPtr<CefFrame> frame,
262                          int64 query_id,
263                          const CefString& request,
264                          bool persistent,
265                          CefRefPtr<Callback> callback) {
266       return false;
267     }
268 
269     ///
270     // Executed when a query has been canceled either explicitly using the
271     // JavaScript cancel function or implicitly due to browser destruction,
272     // navigation or renderer process termination. It will only be called for
273     // the single handler that returned true from OnQuery for the same
274     // |query_id|. No references to the associated Callback object should be
275     // kept after this method is called, nor should any Callback methods be
276     // executed.
277     ///
OnQueryCanceled(CefRefPtr<CefBrowser> browser,CefRefPtr<CefFrame> frame,int64 query_id)278     virtual void OnQueryCanceled(CefRefPtr<CefBrowser> browser,
279                                  CefRefPtr<CefFrame> frame,
280                                  int64 query_id) {}
281 
~Handler()282     virtual ~Handler() {}
283   };
284 
285   ///
286   // Create a new router with the specified configuration.
287   ///
288   static CefRefPtr<CefMessageRouterBrowserSide> Create(
289       const CefMessageRouterConfig& config);
290 
291   ///
292   // Add a new query handler. If |first| is true it will be added as the first
293   // handler, otherwise it will be added as the last handler. Returns true if
294   // the handler is added successfully or false if the handler has already been
295   // added. Must be called on the browser process UI thread. The Handler object
296   // must either outlive the router or be removed before deletion.
297   ///
298   virtual bool AddHandler(Handler* handler, bool first) = 0;
299 
300   ///
301   // Remove an existing query handler. Any pending queries associated with the
302   // handler will be canceled. Handler::OnQueryCanceled will be called and the
303   // associated JavaScript onFailure callback will be executed with an error
304   // code of -1. Returns true if the handler is removed successfully or false
305   // if the handler is not found. Must be called on the browser process UI
306   // thread.
307   ///
308   virtual bool RemoveHandler(Handler* handler) = 0;
309 
310   ///
311   // Cancel all pending queries associated with either |browser| or |handler|.
312   // If both |browser| and |handler| are NULL all pending queries will be
313   // canceled. Handler::OnQueryCanceled will be called and the associated
314   // JavaScript onFailure callback will be executed in all cases with an error
315   // code of -1.
316   ///
317   virtual void CancelPending(CefRefPtr<CefBrowser> browser,
318                              Handler* handler) = 0;
319 
320   ///
321   // Returns the number of queries currently pending for the specified |browser|
322   // and/or |handler|. Either or both values may be empty. Must be called on the
323   // browser process UI thread.
324   ///
325   virtual int GetPendingCount(CefRefPtr<CefBrowser> browser,
326                               Handler* handler) = 0;
327 
328   // The below methods should be called from other CEF handlers. They must be
329   // called exactly as documented for the router to function correctly.
330 
331   ///
332   // Call from CefLifeSpanHandler::OnBeforeClose. Any pending queries associated
333   // with |browser| will be canceled and Handler::OnQueryCanceled will be
334   // called. No JavaScript callbacks will be executed since this indicates
335   // destruction of the browser.
336   ///
337   virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) = 0;
338 
339   ///
340   // Call from CefRequestHandler::OnRenderProcessTerminated. Any pending queries
341   // associated with |browser| will be canceled and Handler::OnQueryCanceled
342   // will be called. No JavaScript callbacks will be executed since this
343   // indicates destruction of the context.
344   ///
345   virtual void OnRenderProcessTerminated(CefRefPtr<CefBrowser> browser) = 0;
346 
347   ///
348   // Call from CefRequestHandler::OnBeforeBrowse only if the navigation is
349   // allowed to proceed. If |frame| is the main frame then any pending queries
350   // associated with |browser| will be canceled and Handler::OnQueryCanceled
351   // will be called. No JavaScript callbacks will be executed since this
352   // indicates destruction of the context.
353   ///
354   virtual void OnBeforeBrowse(CefRefPtr<CefBrowser> browser,
355                               CefRefPtr<CefFrame> frame) = 0;
356 
357   ///
358   // Call from CefClient::OnProcessMessageReceived. Returns true if the message
359   // is handled by this router or false otherwise.
360   ///
361   virtual bool OnProcessMessageReceived(
362       CefRefPtr<CefBrowser> browser,
363       CefRefPtr<CefFrame> frame,
364       CefProcessId source_process,
365       CefRefPtr<CefProcessMessage> message) = 0;
366 
367  protected:
368   // Protect against accidental deletion of this object.
369   friend class base::RefCountedThreadSafe<CefMessageRouterBrowserSide>;
~CefMessageRouterBrowserSide()370   virtual ~CefMessageRouterBrowserSide() {}
371 };
372 
373 ///
374 // Implements the renderer side of query routing. The methods of this class must
375 // be called on the render process main thread.
376 ///
377 class CefMessageRouterRendererSide
378     : public base::RefCountedThreadSafe<CefMessageRouterRendererSide> {
379  public:
380   ///
381   // Create a new router with the specified configuration.
382   ///
383   static CefRefPtr<CefMessageRouterRendererSide> Create(
384       const CefMessageRouterConfig& config);
385 
386   ///
387   // Returns the number of queries currently pending for the specified |browser|
388   // and/or |context|. Either or both values may be empty.
389   ///
390   virtual int GetPendingCount(CefRefPtr<CefBrowser> browser,
391                               CefRefPtr<CefV8Context> context) = 0;
392 
393   // The below methods should be called from other CEF handlers. They must be
394   // called exactly as documented for the router to function correctly.
395 
396   ///
397   // Call from CefRenderProcessHandler::OnContextCreated. Registers the
398   // JavaScripts functions with the new context.
399   ///
400   virtual void OnContextCreated(CefRefPtr<CefBrowser> browser,
401                                 CefRefPtr<CefFrame> frame,
402                                 CefRefPtr<CefV8Context> context) = 0;
403 
404   ///
405   // Call from CefRenderProcessHandler::OnContextReleased. Any pending queries
406   // associated with the released context will be canceled and
407   // Handler::OnQueryCanceled will be called in the browser process.
408   ///
409   virtual void OnContextReleased(CefRefPtr<CefBrowser> browser,
410                                  CefRefPtr<CefFrame> frame,
411                                  CefRefPtr<CefV8Context> context) = 0;
412 
413   ///
414   // Call from CefRenderProcessHandler::OnProcessMessageReceived. Returns true
415   // if the message is handled by this router or false otherwise.
416   ///
417   virtual bool OnProcessMessageReceived(
418       CefRefPtr<CefBrowser> browser,
419       CefRefPtr<CefFrame> frame,
420       CefProcessId source_process,
421       CefRefPtr<CefProcessMessage> message) = 0;
422 
423  protected:
424   // Protect against accidental deletion of this object.
425   friend class base::RefCountedThreadSafe<CefMessageRouterRendererSide>;
~CefMessageRouterRendererSide()426   virtual ~CefMessageRouterRendererSide() {}
427 };
428 
429 #endif  // CEF_INCLUDE_WRAPPER_CEF_MESSAGE_ROUTER_H_
430