Make USB permissions work in the new permission message system
[chromium-blink-merge.git] / content / browser / navigator_connect / navigator_connect_context_impl.cc
blob553ba64785db972824e5918f85cc96ec7ac27dc7
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_service.h"
8 #include "content/browser/navigator_connect/service_port_service_impl.h"
9 #include "content/browser/service_worker/service_worker_context_wrapper.h"
10 #include "content/common/service_worker/service_worker_utils.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "content/public/browser/navigator_connect_service_factory.h"
13 #include "content/public/common/navigator_connect_client.h"
15 namespace content {
17 struct NavigatorConnectContextImpl::Port {
18 // ID of this port.
19 int id;
20 // ID of the port this port is connected to.
21 int entangled_id;
23 // Service url and client origin describing this connection. These fields will
24 // always be the same as the same fields for the entangled port.
25 GURL target_url;
26 GURL client_origin;
28 // Set to nullptr when the ServicePortService goes away.
29 ServicePortServiceImpl* service = nullptr;
31 // If this port is associated with a service worker, these fields store that
32 // information.
33 int64 service_worker_registration_id = kInvalidServiceWorkerRegistrationId;
34 GURL service_worker_registration_origin;
37 NavigatorConnectContextImpl::NavigatorConnectContextImpl(
38 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context)
39 : service_worker_context_(service_worker_context), next_port_id_(0) {}
41 NavigatorConnectContextImpl::~NavigatorConnectContextImpl() {
44 void NavigatorConnectContextImpl::AddFactory(
45 scoped_ptr<NavigatorConnectServiceFactory> factory) {
46 DCHECK_CURRENTLY_ON(BrowserThread::UI);
47 BrowserThread::PostTask(
48 BrowserThread::IO, FROM_HERE,
49 base::Bind(&NavigatorConnectContextImpl::AddFactoryOnIOThread, this,
50 base::Passed(&factory)));
53 void NavigatorConnectContextImpl::AddFactoryOnIOThread(
54 scoped_ptr<NavigatorConnectServiceFactory> factory) {
55 DCHECK_CURRENTLY_ON(BrowserThread::IO);
56 service_factories_.push_back(factory.release());
59 void NavigatorConnectContextImpl::Connect(
60 const GURL& target_url,
61 const GURL& origin,
62 ServicePortServiceImpl* service_port_service,
63 const ConnectCallback& callback) {
64 DCHECK_CURRENTLY_ON(BrowserThread::IO);
65 // Create a new message channel.
66 int client_port_id = next_port_id_++;
67 int service_port_id = next_port_id_++;
69 Port& client_port = ports_[client_port_id];
70 client_port.id = client_port_id;
71 client_port.entangled_id = service_port_id;
72 client_port.target_url = target_url;
73 client_port.client_origin = origin;
74 client_port.service = service_port_service;
76 Port& service_port = ports_[service_port_id];
77 service_port.id = service_port_id;
78 service_port.entangled_id = client_port_id;
79 service_port.target_url = target_url;
80 service_port.client_origin = origin;
82 // Find the right service worker to service this connection.
83 service_worker_context_->FindRegistrationForDocument(
84 target_url,
85 base::Bind(&NavigatorConnectContextImpl::GotServiceWorkerRegistration,
86 this, callback, client_port_id, service_port_id));
89 void NavigatorConnectContextImpl::PostMessage(
90 int sender_port_id,
91 const MessagePortMessage& message,
92 const std::vector<TransferredMessagePort>& sent_message_ports) {
93 DCHECK_CURRENTLY_ON(BrowserThread::IO);
94 DCHECK(ports_.find(sender_port_id) != ports_.end());
95 DCHECK(message.message_as_value.empty());
97 const Port& sender_port = ports_[sender_port_id];
98 DCHECK(ports_.find(sender_port.entangled_id) != ports_.end());
99 const Port& port = ports_[sender_port.entangled_id];
101 if (port.service_worker_registration_id !=
102 kInvalidServiceWorkerRegistrationId) {
103 // Port is associated with service worker, dispatch message event via
104 // ServiceWorkerVersion.
106 // Hold messages on transferred message ports. Actual delivery of the
107 // message by the service can be asynchronous. When a message is delivered,
108 // WebMessagePortChannelImpl instances will be constructed which send
109 // MessagePortHostMsg_ReleaseMessages to release messages.
110 for (const auto& sent_port : sent_message_ports)
111 MessagePortService::GetInstance()->HoldMessages(sent_port.id);
113 service_worker_context_->FindRegistrationForId(
114 port.service_worker_registration_id,
115 port.service_worker_registration_origin,
116 base::Bind(&NavigatorConnectContextImpl::DeliverMessage, this, port.id,
117 message.message_as_string, sent_message_ports));
118 return;
121 if (!port.service) {
122 // TODO(mek): Figure out what to do in this situation.
123 return;
125 port.service->PostMessageToClient(port.id, message, sent_message_ports);
128 void NavigatorConnectContextImpl::GotServiceWorkerRegistration(
129 const ConnectCallback& callback,
130 int client_port_id,
131 int service_port_id,
132 ServiceWorkerStatusCode status,
133 const scoped_refptr<ServiceWorkerRegistration>& registration) {
134 DCHECK_CURRENTLY_ON(BrowserThread::IO);
135 DCHECK(ports_.find(client_port_id) != ports_.end());
136 DCHECK(ports_.find(service_port_id) != ports_.end());
138 if (status != SERVICE_WORKER_OK) {
139 // No service worker found, reject connection attempt.
140 OnConnectResult(callback, client_port_id, service_port_id, registration,
141 status, false, base::string16(), base::string16());
142 return;
145 ServiceWorkerVersion* active_version = registration->active_version();
146 if (!active_version) {
147 // No active version, reject connection attempt.
148 OnConnectResult(callback, client_port_id, service_port_id, registration,
149 status, false, base::string16(), base::string16());
150 return;
153 Port& service_port = ports_[service_port_id];
154 service_port.service_worker_registration_id = registration->id();
155 service_port.service_worker_registration_origin =
156 registration->pattern().GetOrigin();
158 active_version->DispatchServicePortConnectEvent(
159 base::Bind(&NavigatorConnectContextImpl::OnConnectResult, this, callback,
160 client_port_id, service_port_id, registration),
161 service_port.target_url, service_port.client_origin, service_port_id);
164 void NavigatorConnectContextImpl::ServicePortServiceDestroyed(
165 ServicePortServiceImpl* service_port_service) {
166 DCHECK_CURRENTLY_ON(BrowserThread::IO);
167 for (auto& port : ports_) {
168 if (port.second.service != service_port_service)
169 continue;
170 port.second.service = nullptr;
171 // TODO(mek): Should actually inform other side of connections that the
172 // connection was closed, or in the case of service workers somehow keep
173 // track of the connection.
177 void NavigatorConnectContextImpl::OnConnectResult(
178 const ConnectCallback& callback,
179 int client_port_id,
180 int service_port_id,
181 const scoped_refptr<ServiceWorkerRegistration>& service_worker_registration,
182 ServiceWorkerStatusCode status,
183 bool accept_connection,
184 const base::string16& name,
185 const base::string16& data) {
186 DCHECK_CURRENTLY_ON(BrowserThread::IO);
187 if (accept_connection) {
188 // TODO(mek): Might have to do something else if the client connection got
189 // severed while the service side connection was being set up.
190 callback.Run(client_port_id, true);
191 } else {
192 // Destroy ports since connection failed.
193 ports_.erase(service_port_id);
194 ports_.erase(client_port_id);
195 callback.Run(MSG_ROUTING_NONE, false);
199 void NavigatorConnectContextImpl::DeliverMessage(
200 int port_id,
201 const base::string16& message,
202 const std::vector<TransferredMessagePort>& sent_message_ports,
203 ServiceWorkerStatusCode service_worker_status,
204 const scoped_refptr<ServiceWorkerRegistration>&
205 service_worker_registration) {
206 DCHECK_CURRENTLY_ON(BrowserThread::IO);
207 DCHECK(ports_.find(port_id) != ports_.end());
209 if (service_worker_status != SERVICE_WORKER_OK) {
210 // TODO(mek): Do something when no service worker was found.
211 return;
214 ServiceWorkerVersion* active_version =
215 service_worker_registration->active_version();
216 if (!active_version) {
217 // TODO(mek): Do something when no active version exists.
218 return;
221 const Port& port = ports_[port_id];
222 NavigatorConnectClient client(port.target_url, port.client_origin, port_id);
223 active_version->DispatchCrossOriginMessageEvent(
224 client, message, sent_message_ports,
225 base::Bind(&ServiceWorkerUtils::NoOpStatusCallback));
228 } // namespace content