1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/navigator_connect/navigator_connect_context_impl.h"
7 #include "content/browser/message_port_message_filter.h"
8 #include "content/browser/message_port_service.h"
9 #include "content/browser/navigator_connect/service_port_service_impl.h"
10 #include "content/public/browser/message_port_provider.h"
11 #include "content/public/browser/navigator_connect_service_factory.h"
12 #include "content/public/common/navigator_connect_client.h"
16 struct NavigatorConnectContextImpl::Port
{
18 // Set to nullptr when the ServicePortService goes away.
19 ServicePortServiceImpl
* service
;
22 NavigatorConnectContextImpl::NavigatorConnectContextImpl() {
25 NavigatorConnectContextImpl::~NavigatorConnectContextImpl() {
28 void NavigatorConnectContextImpl::AddFactory(
29 scoped_ptr
<NavigatorConnectServiceFactory
> factory
) {
30 DCHECK_CURRENTLY_ON(BrowserThread::UI
);
31 BrowserThread::PostTask(
32 BrowserThread::IO
, FROM_HERE
,
33 base::Bind(&NavigatorConnectContextImpl::AddFactoryOnIOThread
, this,
34 base::Passed(&factory
)));
37 void NavigatorConnectContextImpl::AddFactoryOnIOThread(
38 scoped_ptr
<NavigatorConnectServiceFactory
> factory
) {
39 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
40 service_factories_
.push_back(factory
.release());
43 void NavigatorConnectContextImpl::Connect(
44 const GURL
& target_url
,
46 ServicePortServiceImpl
* service_port_service
,
47 const ConnectCallback
& callback
) {
48 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
49 // Create a new message channel. Use |this| as delegate for both ports until
50 // the real delegate for the service port is known later on.
53 MessagePortProvider::CreateMessageChannel(this, &client_port_id
,
55 // Hold messages send to the client while setting up connection.
56 MessagePortService::GetInstance()->HoldMessages(client_port_id
);
58 Port
& client_port
= ports_
[client_port_id
];
59 client_port
.message_port_id
= client_port_id
;
60 client_port
.service
= service_port_service
;
62 // The message_port_id stored in the client object is the one associated with
64 NavigatorConnectClient
client(target_url
, origin
, service_port
);
66 // Find factory to handle request, more recently added factories should take
67 // priority as per comment at NavigatorConnectContext::AddFactory..
68 NavigatorConnectServiceFactory
* factory
= nullptr;
69 for (auto it
= service_factories_
.rbegin(); it
!= service_factories_
.rend();
71 if ((*it
)->HandlesUrl(client
.target_url
)) {
78 // No factories found.
79 OnConnectResult(client
, client_port_id
, callback
, nullptr, false);
83 // Actually initiate connection.
85 client
, base::Bind(&NavigatorConnectContextImpl::OnConnectResult
, this,
86 client
, client_port_id
, callback
));
89 void NavigatorConnectContextImpl::ServicePortServiceDestroyed(
90 ServicePortServiceImpl
* service_port_service
) {
91 for (auto& port
: ports_
) {
92 if (port
.second
.service
!= service_port_service
)
94 port
.second
.service
= nullptr;
95 // TODO(mek): Should actually inform other side of connections that the
96 // connection was closed, or in the case of service workers somehow keep
97 // track of the connection.
101 void NavigatorConnectContextImpl::SendMessage(
103 const MessagePortMessage
& message
,
104 const std::vector
<TransferredMessagePort
>& sent_message_ports
) {
105 DCHECK(ports_
.find(route_id
) != ports_
.end());
106 const Port
& port
= ports_
[route_id
];
108 // TODO(mek): Figure out what to do in this situation.
112 port
.service
->PostMessageToClient(route_id
, message
, sent_message_ports
);
115 void NavigatorConnectContextImpl::SendMessagesAreQueued(int route_id
) {
116 NOTREACHED() << "navigator.services endpoints should never queue messages.";
119 void NavigatorConnectContextImpl::OnConnectResult(
120 const NavigatorConnectClient
& client
,
121 int client_message_port_id
,
122 const ConnectCallback
& callback
,
123 MessagePortDelegate
* delegate
,
124 bool data_as_values
) {
125 DCHECK_CURRENTLY_ON(BrowserThread::IO
);
127 DCHECK(!data_as_values
) << "Data as values is not currently implemented";
128 // TODO(mek): Might have to do something else if the client connection got
129 // severed while the service side connection was being set up.
131 // Update service side port with delegate.
132 MessagePortService::GetInstance()->UpdateMessagePort(
133 client
.message_port_id
, delegate
, client
.message_port_id
);
134 callback
.Run(client_message_port_id
, true);
135 MessagePortService::GetInstance()->ReleaseMessages(client_message_port_id
);
137 // Destroy ports since connection failed.
138 MessagePortService::GetInstance()->Destroy(client
.message_port_id
);
139 MessagePortService::GetInstance()->Destroy(client_message_port_id
);
140 ports_
.erase(client_message_port_id
);
141 callback
.Run(MSG_ROUTING_NONE
, false);
145 } // namespace content