summaryrefslogtreecommitdiffstats
path: root/content/child/navigator_connect/service_port_provider.cc
blob: 7c1625043d1419200d535bf3b36035a1383f330f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2014 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.

#include "content/child/navigator_connect/service_port_provider.h"

#include <utility>

#include "base/lazy_instance.h"
#include "base/single_thread_task_runner.h"
#include "base/task_runner_util.h"
#include "content/child/child_thread_impl.h"
#include "content/child/webmessageportchannel_impl.h"
#include "content/common/message_port_messages.h"
#include "content/common/service_port_type_converters.h"
#include "content/public/common/navigator_connect_client.h"
#include "mojo/common/common_type_converters.h"
#include "third_party/WebKit/public/platform/WebURL.h"
#include "third_party/WebKit/public/platform/modules/navigator_services/WebServicePortProviderClient.h"

namespace content {

namespace {

void ConnectToServiceOnMainThread(
    mojo::InterfaceRequest<mojom::ServicePortService> ptr) {
  ChildThreadImpl::current()->service_registry()->ConnectToRemoteService(
      std::move(ptr));
}

}  // namespace

ServicePortProvider::ServicePortProvider(
    blink::WebServicePortProviderClient* client,
    const scoped_refptr<base::SingleThreadTaskRunner>& main_loop)
    : client_(client), binding_(this), main_loop_(main_loop) {
  DCHECK(client_);
  AddRef();
}

void ServicePortProvider::destroy() {
  Release();
}

void ServicePortProvider::connect(
    const blink::WebURL& target_url,
    const blink::WebString& origin,
    blink::WebServicePortConnectCallbacks* raw_callbacks) {
  scoped_ptr<blink::WebServicePortConnectCallbacks> callbacks(raw_callbacks);
  // base::Unretained is safe here, as the mojo channel will be deleted (and
  // will wipe its callbacks) before 'this' is deleted.
  GetServicePortServicePtr()->Connect(
      target_url.string().utf8(), origin.utf8(),
      base::Bind(&ServicePortProvider::OnConnectResult, base::Unretained(this),
                 base::Passed(&callbacks)));
}

void ServicePortProvider::postMessage(
    blink::WebServicePortID port_id,
    const blink::WebString& message,
    blink::WebMessagePortChannelArray* channels) {
  // TODO(mek): If necesary, handle sending messages as values for system
  // services.

  // Have to extract IDs for the transferred MessagePorts on the main thread
  // to make sure all ports have been fully initialized. Actually sending the
  // message can safely be done on this thread, and using mojo, since there
  // shouldn't be any other IPCs where ordering matters.
  scoped_ptr<blink::WebMessagePortChannelArray> channel_array(channels);
  base::PostTaskAndReplyWithResult(
      main_loop_.get(), FROM_HERE,
      base::Bind(
          &WebMessagePortChannelImpl::ExtractMessagePortIDsWithoutQueueing,
          base::Passed(&channel_array)),
      base::Bind(&ServicePortProvider::PostMessageToBrowser, this, port_id,
                 // We cast WebString to string16 before crossing threads.
                 // for thread-safety.
                 static_cast<base::string16>(message)));
}

void ServicePortProvider::closePort(blink::WebServicePortID port_id) {
  GetServicePortServicePtr()->ClosePort(port_id);
}

void ServicePortProvider::PostMessageToPort(
    int32_t port_id,
    const mojo::String& message,
    mojo::Array<mojom::MojoTransferredMessagePortPtr> ports,
    mojo::Array<int32_t> new_routing_ids) {
  client_->postMessage(port_id, message.To<base::string16>(),
                       WebMessagePortChannelImpl::CreatePorts(
                           ports.To<std::vector<TransferredMessagePort>>(),
                           new_routing_ids.To<std::vector<int>>(), main_loop_));
}

ServicePortProvider::~ServicePortProvider() {
}

void ServicePortProvider::PostMessageToBrowser(
    int port_id,
    const base::string16& message,
    const std::vector<TransferredMessagePort> ports) {
  GetServicePortServicePtr()->PostMessageToPort(
      port_id, mojo::String::From(message),
      mojo::Array<mojom::MojoTransferredMessagePortPtr>::From(ports));
}

void ServicePortProvider::OnConnectResult(
    scoped_ptr<blink::WebServicePortConnectCallbacks> callbacks,
    mojom::ServicePortConnectResult result,
    int32_t port_id) {
  if (result == mojom::ServicePortConnectResult::ACCEPT) {
    callbacks->onSuccess(port_id);
  } else {
    callbacks->onError();
  }
}

mojom::ServicePortServicePtr& ServicePortProvider::GetServicePortServicePtr() {
  if (!service_port_service_.get()) {
    mojo::InterfaceRequest<mojom::ServicePortService> request =
        mojo::GetProxy(&service_port_service_);
    main_loop_->PostTask(FROM_HERE, base::Bind(&ConnectToServiceOnMainThread,
                                               base::Passed(&request)));

    // Setup channel for browser to post events back to this class.
    service_port_service_->SetClient(binding_.CreateInterfacePtrAndBind());
  }
  return service_port_service_;
}

}  // namespace content