messaging_bindings.cc revision 010d83a9304c5a91596085d917d248abff47903a
1010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "extensions/renderer/messaging_bindings.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <map>
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
12bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/bind_helpers.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/lazy_instance.h"
14bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch#include "base/message_loop/message_loop.h"
15c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/values.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/renderer/render_thread.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/renderer/render_view.h"
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "content/public/renderer/v8_value_converter.h"
19effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch#include "extensions/common/api/messaging/message.h"
20a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/common/extension_messages.h"
21010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "extensions/common/manifest_handlers/externally_connectable.h"
22010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)#include "extensions/renderer/dispatcher.h"
23a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch#include "extensions/renderer/event_bindings.h"
240529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "extensions/renderer/object_backed_native_handler.h"
25c5cede9ae108bb15f6b7a8aea21c7e1fefa2834cBen Murdoch#include "extensions/renderer/scoped_persistent.h"
260529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "extensions/renderer/script_context.h"
270529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch#include "extensions/renderer/script_context_set.h"
287d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebScopedMicrotaskSuppression.h"
291e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "third_party/WebKit/public/web/WebScopedUserGesture.h"
305d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/WebKit/public/web/WebScopedWindowFocusAllowedIndicator.h"
311e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)#include "third_party/WebKit/public/web/WebUserGestureIndicator.h"
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "v8/include/v8.h"
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Message passing API example (in a content script):
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// var extension =
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//    new chrome.Extension('00123456789abcdef0123456789abcdef0123456');
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// var port = runtime.connect();
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// port.postMessage('Can you hear me now?');
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// port.onmessage.addListener(function(msg, port) {
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   alert('response=' + msg);
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//   port.postMessage('I got your reponse');
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// });
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderThread;
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::V8ValueConverter;
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)namespace extensions {
485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)struct ExtensionData {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  struct PortData {
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int ref_count;  // how many contexts have a handle to this port
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    PortData() : ref_count(0) {}
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  };
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  std::map<int, PortData> ports;  // port ID -> data
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
59010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)base::LazyInstance<ExtensionData> g_extension_data = LAZY_INSTANCE_INITIALIZER;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)bool HasPortData(int port_id) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_extension_data.Get().ports.find(port_id) !=
63010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)         g_extension_data.Get().ports.end();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)ExtensionData::PortData& GetPortData(int port_id) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return g_extension_data.Get().ports[port_id];
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)void ClearPortData(int port_id) {
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  g_extension_data.Get().ports.erase(port_id);
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char kPortClosedError[] = "Attempting to use a disconnected port object";
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)const char kReceivingEndDoesntExistError[] =
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    "Could not establish connection. Receiving end does not exist.";
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
780529e5d033099cbfc42635f6f6183833b09dff6eBen Murdochclass ExtensionImpl : public ObjectBackedNativeHandler {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
800529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  ExtensionImpl(Dispatcher* dispatcher, ScriptContext* context)
810529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch      : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) {
82010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RouteFunction(
83010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "CloseChannel",
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&ExtensionImpl::CloseChannel, base::Unretained(this)));
85010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RouteFunction(
86010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "PortAddRef",
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&ExtensionImpl::PortAddRef, base::Unretained(this)));
88010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RouteFunction(
89010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "PortRelease",
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&ExtensionImpl::PortRelease, base::Unretained(this)));
91010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    RouteFunction(
92010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "PostMessage",
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        base::Bind(&ExtensionImpl::PostMessage, base::Unretained(this)));
943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    // TODO(fsamuel, kalman): Move BindToGC out of messaging natives.
952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    RouteFunction("BindToGC",
96010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                  base::Bind(&ExtensionImpl::BindToGC, base::Unretained(this)));
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  virtual ~ExtensionImpl() {}
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1010529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch private:
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  void ClearPortDataAndNotifyDispatcher(int port_id) {
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ClearPortData(port_id);
1040529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    dispatcher_->ClearPortData(port_id);
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Sends a message along the given channel.
1087d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  void PostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
1090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    content::RenderView* renderview = context()->GetRenderView();
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!renderview)
1117d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return;
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
113eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    // Arguments are (int32 port_id, string message).
114010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    CHECK(args.Length() == 2 && args[0]->IsInt32() && args[1]->IsString());
115868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
116868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int port_id = args[0]->Int32Value();
117868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!HasPortData(port_id)) {
118a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      args.GetIsolate()->ThrowException(v8::Exception::Error(
119a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          v8::String::NewFromUtf8(args.GetIsolate(), kPortClosedError)));
1207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
122868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
123868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    renderview->Send(new ExtensionHostMsg_PostMessage(
124010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        renderview->GetRoutingID(), port_id,
125010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        Message(*v8::String::Utf8Value(args[1]),
126010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                blink::WebUserGestureIndicator::isProcessingUserGesture())));
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Forcefully disconnects a port.
1307d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  void CloseChannel(const v8::FunctionCallbackInfo<v8::Value>& args) {
131868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Arguments are (int32 port_id, boolean notify_browser).
132868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK_EQ(2, args.Length());
133868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK(args[0]->IsInt32());
134868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK(args[1]->IsBoolean());
135868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
136868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int port_id = args[0]->Int32Value();
137868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!HasPortData(port_id))
1387d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return;
139868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
140868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Send via the RenderThread because the RenderView might be closing.
141868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    bool notify_browser = args[1]->BooleanValue();
142868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (notify_browser) {
143868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      content::RenderThread::Get()->Send(
144868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          new ExtensionHostMsg_CloseChannel(port_id, std::string()));
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
146868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
1475d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ClearPortDataAndNotifyDispatcher(port_id);
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // A new port has been created for a context.  This occurs both when script
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // opens a connection, and when a connection is opened to this script.
1527d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  void PortAddRef(const v8::FunctionCallbackInfo<v8::Value>& args) {
153868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Arguments are (int32 port_id).
154868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK_EQ(1, args.Length());
155868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK(args[0]->IsInt32());
156868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
157868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int port_id = args[0]->Int32Value();
158868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ++GetPortData(port_id).ref_count;
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The frame a port lived in has been destroyed.  When there are no more
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // frames with a reference to a given port, we will disconnect it and notify
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // the other end of the channel.
1647d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  void PortRelease(const v8::FunctionCallbackInfo<v8::Value>& args) {
165868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // Arguments are (int32 port_id).
166868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK_EQ(1, args.Length());
167868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    CHECK(args[0]->IsInt32());
168868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
169868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    int port_id = args[0]->Int32Value();
170868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (HasPortData(port_id) && --GetPortData(port_id).ref_count == 0) {
171868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      // Send via the RenderThread because the RenderView might be closing.
172868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      content::RenderThread::Get()->Send(
173868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          new ExtensionHostMsg_CloseChannel(port_id, std::string()));
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      ClearPortDataAndNotifyDispatcher(port_id);
1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
178bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Holds a |callback| to run sometime after |object| is GC'ed. |callback| will
179bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // not be executed re-entrantly to avoid running JS in an unexpected state.
180bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  class GCCallback {
181bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch   public:
182bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    static void Bind(v8::Handle<v8::Object> object,
18358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     v8::Handle<v8::Function> callback,
18458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     v8::Isolate* isolate) {
18558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      GCCallback* cb = new GCCallback(object, callback, isolate);
186a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      cb->object_.SetWeak(cb, NearDeathCallback);
187bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    }
1882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1892a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)   private:
190a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    static void NearDeathCallback(
191a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)        const v8::WeakCallbackData<v8::Object, GCCallback>& data) {
192bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      // v8 says we need to explicitly reset weak handles from their callbacks.
193bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      // It's not implicit as one might expect.
194a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      data.GetParameter()->object_.reset();
195a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      base::MessageLoop::current()->PostTask(
196a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          FROM_HERE,
197a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          base::Bind(&GCCallback::RunCallback,
198a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                     base::Owned(data.GetParameter())));
199bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    }
2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
20158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GCCallback(v8::Handle<v8::Object> object,
20258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               v8::Handle<v8::Function> callback,
20358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)               v8::Isolate* isolate)
20458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        : object_(object), callback_(callback), isolate_(isolate) {}
205bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
206bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    void RunCallback() {
20758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      v8::HandleScope handle_scope(isolate_);
20858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      v8::Handle<v8::Function> callback = callback_.NewHandle(isolate_);
20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      v8::Handle<v8::Context> context = callback->CreationContext();
210bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      if (context.IsEmpty())
211bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch        return;
212bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch      v8::Context::Scope context_scope(context);
213f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      blink::WebScopedMicrotaskSuppression suppression;
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      callback->Call(context->Global(), 0, NULL);
215bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    }
216bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
2175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ScopedPersistent<v8::Object> object_;
2185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    ScopedPersistent<v8::Function> callback_;
21958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    v8::Isolate* isolate_;
220bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch
221bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch    DISALLOW_COPY_AND_ASSIGN(GCCallback);
222bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  };
2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
224bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // void BindToGC(object, callback)
225bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  //
226bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // Binds |callback| to be invoked *sometime after* |object| is garbage
227bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // collected. We don't call the method re-entrantly so as to avoid executing
228bbcdd45c55eb7c4641ab97aef9889b0fc828e7d3Ben Murdoch  // JS in some bizarro undefined mid-GC state.
2297d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)  void BindToGC(const v8::FunctionCallbackInfo<v8::Value>& args) {
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    CHECK(args.Length() == 2 && args[0]->IsObject() && args[1]->IsFunction());
23158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    GCCallback::Bind(args[0].As<v8::Object>(),
23258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     args[1].As<v8::Function>(),
23358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                     args.GetIsolate());
2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
2350529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch
2360529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // Dispatcher handle. Not owned.
2370529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  Dispatcher* dispatcher_;
2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2420529e5d033099cbfc42635f6f6183833b09dff6eBen MurdochObjectBackedNativeHandler* MessagingBindings::Get(Dispatcher* dispatcher,
2430529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch                                                  ScriptContext* context) {
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return new ExtensionImpl(dispatcher, context);
2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
248fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochvoid MessagingBindings::DispatchOnConnect(
2490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const ScriptContextSet::ContextSet& contexts,
2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int target_port_id,
2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& channel_name,
252c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const base::DictionaryValue& source_tab,
2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& source_extension_id,
2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& target_extension_id,
255c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const GURL& source_url,
2564e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    const std::string& tls_channel_id,
2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::RenderView* restrict_to_render_view) {
258a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::Isolate* isolate = v8::Isolate::GetCurrent();
259a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::HandleScope handle_scope(isolate);
2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
261c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
262c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool port_created = false;
264c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  std::string source_url_spec = source_url.spec();
2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
2660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(kalman): pass in the full ScriptContextSet; call ForEach.
2670529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin();
2680529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       it != contexts.end();
2690529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       ++it) {
2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (restrict_to_render_view &&
2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        restrict_to_render_view != (*it)->GetRenderView()) {
2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
275868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // TODO(kalman): remove when ContextSet::ForEach is available.
276868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if ((*it)->v8_context().IsEmpty())
277868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      continue;
278868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
279a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    v8::Handle<v8::Value> tab = v8::Null(isolate);
280a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    v8::Handle<v8::Value> tls_channel_id_value = v8::Undefined(isolate);
2815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    const Extension* extension = (*it)->extension();
2825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if (extension) {
2835d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if (!source_tab.empty() && !extension->is_platform_app())
2845d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        tab = converter->ToV8Value(&source_tab, (*it)->v8_context());
2855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
2864e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      ExternallyConnectableInfo* externally_connectable =
2875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)          ExternallyConnectableInfo::Get(extension);
2884e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      if (externally_connectable &&
2894e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)          externally_connectable->accepts_tls_channel_id) {
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        tls_channel_id_value =
291a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)            v8::String::NewFromUtf8(isolate,
292a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    tls_channel_id.c_str(),
293a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    v8::String::kNormalString,
294a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                    tls_channel_id.size());
2954e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      }
2964e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    }
2974e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
298c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    v8::Handle<v8::Value> arguments[] = {
299010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        // portId
300010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        v8::Integer::New(isolate, target_port_id),
301010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        // channelName
302010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        v8::String::NewFromUtf8(isolate,
303010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                channel_name.c_str(),
304010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                v8::String::kNormalString,
305010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                channel_name.size()),
306010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        // sourceTab
307010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        tab,
308010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        // sourceExtensionId
309010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        v8::String::NewFromUtf8(isolate,
310010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                source_extension_id.c_str(),
311010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                v8::String::kNormalString,
312010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                source_extension_id.size()),
313010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        // targetExtensionId
314010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        v8::String::NewFromUtf8(isolate,
315010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                target_extension_id.c_str(),
316010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                v8::String::kNormalString,
317010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                target_extension_id.size()),
318010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        // sourceUrl
319010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        v8::String::NewFromUtf8(isolate,
320010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                source_url_spec.c_str(),
321010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                v8::String::kNormalString,
322010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)                                source_url_spec.size()),
323010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        // tlsChannelId
324010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        tls_channel_id_value,
325c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    };
326c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
327868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    v8::Handle<v8::Value> retval = (*it)->module_system()->CallModuleMethod(
328010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "messaging", "dispatchOnConnect", arraysize(arguments), arguments);
3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (retval.IsEmpty()) {
331868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      LOG(ERROR) << "Empty return value from dispatchOnConnect.";
3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(retval->IsBoolean());
336868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    port_created |= retval->BooleanValue();
3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // If we didn't create a port, notify the other end of the channel (treat it
3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // as a disconnect).
3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!port_created) {
342010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    content::RenderThread::Get()->Send(new ExtensionHostMsg_CloseChannel(
343010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        target_port_id, kReceivingEndDoesntExistError));
3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
348fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochvoid MessagingBindings::DeliverMessage(
3490529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const ScriptContextSet::ContextSet& contexts,
3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int target_port_id,
3511e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)    const Message& message,
3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::RenderView* restrict_to_render_view) {
353f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)  scoped_ptr<blink::WebScopedUserGesture> web_user_gesture;
3545d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  scoped_ptr<blink::WebScopedWindowFocusAllowedIndicator> allow_window_focus;
3555d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  if (message.user_gesture) {
356f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    web_user_gesture.reset(new blink::WebScopedUserGesture);
3575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    allow_window_focus.reset(new blink::WebScopedWindowFocusAllowedIndicator);
3585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  }
3591e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles)
360a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::Isolate* isolate = v8::Isolate::GetCurrent();
361a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::HandleScope handle_scope(isolate);
3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3630529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(kalman): pass in the full ScriptContextSet; call ForEach.
3640529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin();
3650529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       it != contexts.end();
3660529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       ++it) {
3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (restrict_to_render_view &&
3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        restrict_to_render_view != (*it)->GetRenderView()) {
3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
372868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // TODO(kalman): remove when ContextSet::ForEach is available.
373868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if ((*it)->v8_context().IsEmpty())
374868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      continue;
375868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Check to see whether the context has this port before bothering to create
3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // the message.
3785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    v8::Handle<v8::Value> port_id_handle =
3795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        v8::Integer::New(isolate, target_port_id);
380868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    v8::Handle<v8::Value> has_port = (*it)->module_system()->CallModuleMethod(
381010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "messaging", "hasPort", 1, &port_id_handle);
3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    CHECK(!has_port.IsEmpty());
3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!has_port->BooleanValue())
3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<v8::Handle<v8::Value> > arguments;
388a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)    arguments.push_back(v8::String::NewFromUtf8(isolate,
389a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                message.data.c_str(),
390a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                v8::String::kNormalString,
391a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)                                                message.data.size()));
3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    arguments.push_back(port_id_handle);
393010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    (*it)->module_system()->CallModuleMethod(
394010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "messaging", "dispatchOnMessage", &arguments);
3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// static
399fb250657ef40d7500f20882d5c9909c1013367d3Ben Murdochvoid MessagingBindings::DispatchOnDisconnect(
4000529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch    const ScriptContextSet::ContextSet& contexts,
4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    int port_id,
4022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const std::string& error_message,
4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::RenderView* restrict_to_render_view) {
404a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::Isolate* isolate = v8::Isolate::GetCurrent();
405a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)  v8::HandleScope handle_scope(isolate);
4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4070529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  // TODO(kalman): pass in the full ScriptContextSet; call ForEach.
4080529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch  for (ScriptContextSet::ContextSet::const_iterator it = contexts.begin();
4090529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       it != contexts.end();
4100529e5d033099cbfc42635f6f6183833b09dff6eBen Murdoch       ++it) {
4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (restrict_to_render_view &&
4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        restrict_to_render_view != (*it)->GetRenderView()) {
4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
416868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // TODO(kalman): remove when ContextSet::ForEach is available.
417868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if ((*it)->v8_context().IsEmpty())
418868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      continue;
419868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    std::vector<v8::Handle<v8::Value> > arguments;
4215d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    arguments.push_back(v8::Integer::New(isolate, port_id));
4222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if (!error_message.empty()) {
423a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      arguments.push_back(
424a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)          v8::String::NewFromUtf8(isolate, error_message.c_str()));
4252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    } else {
426a3f6a49ab37290eeeb8db0f41ec0f1cb74a68be7Torne (Richard Coles)      arguments.push_back(v8::Null(isolate));
4272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
428010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)    (*it)->module_system()->CallModuleMethod(
429010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)        "messaging", "dispatchOnDisconnect", &arguments);
4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
434