OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "content/browser/navigator_connect/navigator_connect_context_impl.h" | 5 #include "content/browser/navigator_connect/navigator_connect_context_impl.h" |
6 | 6 |
7 #include "content/browser/message_port_message_filter.h" | |
8 #include "content/browser/message_port_service.h" | 7 #include "content/browser/message_port_service.h" |
9 #include "content/browser/navigator_connect/service_port_service_impl.h" | 8 #include "content/browser/navigator_connect/service_port_service_impl.h" |
10 #include "content/public/browser/message_port_provider.h" | 9 #include "content/browser/service_worker/service_worker_context_wrapper.h" |
10 #include "content/browser/service_worker/service_worker_utils.h" | |
11 #include "content/public/browser/browser_thread.h" | |
11 #include "content/public/browser/navigator_connect_service_factory.h" | 12 #include "content/public/browser/navigator_connect_service_factory.h" |
12 #include "content/public/common/navigator_connect_client.h" | 13 #include "content/public/common/navigator_connect_client.h" |
13 | 14 |
14 namespace content { | 15 namespace content { |
15 | 16 |
16 struct NavigatorConnectContextImpl::Port { | 17 struct NavigatorConnectContextImpl::Port { |
17 int message_port_id; | 18 // ID of this port. |
19 int id; | |
20 // ID of the port this port is connected to. | |
21 int entangled_id; | |
22 | |
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; | |
27 | |
18 // Set to nullptr when the ServicePortService goes away. | 28 // Set to nullptr when the ServicePortService goes away. |
19 ServicePortServiceImpl* service; | 29 ServicePortServiceImpl* service; |
30 | |
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; | |
20 }; | 35 }; |
21 | 36 |
22 NavigatorConnectContextImpl::NavigatorConnectContextImpl() { | 37 NavigatorConnectContextImpl::NavigatorConnectContextImpl( |
23 } | 38 const scoped_refptr<ServiceWorkerContextWrapper>& service_worker_context) |
39 : service_worker_context_(service_worker_context), next_port_id_(0) {} | |
24 | 40 |
25 NavigatorConnectContextImpl::~NavigatorConnectContextImpl() { | 41 NavigatorConnectContextImpl::~NavigatorConnectContextImpl() { |
26 } | 42 } |
27 | 43 |
28 void NavigatorConnectContextImpl::AddFactory( | 44 void NavigatorConnectContextImpl::AddFactory( |
29 scoped_ptr<NavigatorConnectServiceFactory> factory) { | 45 scoped_ptr<NavigatorConnectServiceFactory> factory) { |
30 DCHECK_CURRENTLY_ON(BrowserThread::UI); | 46 DCHECK_CURRENTLY_ON(BrowserThread::UI); |
31 BrowserThread::PostTask( | 47 BrowserThread::PostTask( |
32 BrowserThread::IO, FROM_HERE, | 48 BrowserThread::IO, FROM_HERE, |
33 base::Bind(&NavigatorConnectContextImpl::AddFactoryOnIOThread, this, | 49 base::Bind(&NavigatorConnectContextImpl::AddFactoryOnIOThread, this, |
34 base::Passed(&factory))); | 50 base::Passed(&factory))); |
35 } | 51 } |
36 | 52 |
37 void NavigatorConnectContextImpl::AddFactoryOnIOThread( | 53 void NavigatorConnectContextImpl::AddFactoryOnIOThread( |
38 scoped_ptr<NavigatorConnectServiceFactory> factory) { | 54 scoped_ptr<NavigatorConnectServiceFactory> factory) { |
39 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 55 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
40 service_factories_.push_back(factory.release()); | 56 service_factories_.push_back(factory.release()); |
41 } | 57 } |
42 | 58 |
43 void NavigatorConnectContextImpl::Connect( | 59 void NavigatorConnectContextImpl::Connect( |
44 const GURL& target_url, | 60 const GURL& target_url, |
45 const GURL& origin, | 61 const GURL& origin, |
46 ServicePortServiceImpl* service_port_service, | 62 ServicePortServiceImpl* service_port_service, |
47 const ConnectCallback& callback) { | 63 const ConnectCallback& callback) { |
48 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 64 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
49 // Create a new message channel. Use |this| as delegate for both ports until | 65 // Create a new message channel. |
50 // the real delegate for the service port is known later on. | 66 int client_port_id = next_port_id_++; |
51 int client_port_id; | 67 int service_port_id = next_port_id_++; |
52 int service_port; | |
53 MessagePortProvider::CreateMessageChannel(this, &client_port_id, | |
54 &service_port); | |
55 // Hold messages send to the client while setting up connection. | |
56 MessagePortService::GetInstance()->HoldMessages(client_port_id); | |
57 | 68 |
58 Port& client_port = ports_[client_port_id]; | 69 Port& client_port = ports_[client_port_id]; |
59 client_port.message_port_id = 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; | |
60 client_port.service = service_port_service; | 74 client_port.service = service_port_service; |
61 | 75 |
62 // The message_port_id stored in the client object is the one associated with | 76 Port& service_port = ports_[service_port_id]; |
63 // the service. | 77 service_port.id = service_port_id; |
64 NavigatorConnectClient client(target_url, origin, service_port); | 78 service_port.entangled_id = client_port_id; |
79 service_port.target_url = target_url; | |
80 service_port.client_origin = origin; | |
65 | 81 |
66 // Find factory to handle request, more recently added factories should take | 82 // Find the right service worker to service this connection. |
67 // priority as per comment at NavigatorConnectContext::AddFactory.. | 83 service_worker_context_->FindRegistrationForDocument( |
68 NavigatorConnectServiceFactory* factory = nullptr; | 84 target_url, |
69 for (auto it = service_factories_.rbegin(); it != service_factories_.rend(); | 85 base::Bind(&NavigatorConnectContextImpl::GotServiceWorkerRegistration, |
70 ++it) { | 86 this, callback, client_port_id, service_port_id)); |
71 if ((*it)->HandlesUrl(client.target_url)) { | 87 } |
72 factory = *it; | 88 |
73 break; | 89 void NavigatorConnectContextImpl::PostMessage( |
74 } | 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()); | |
96 | |
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]; | |
100 | |
101 if (port.service_worker_registration_id != | |
102 kInvalidServiceWorkerRegistrationId) { | |
103 // Port is associated with service worker, dispatch message event via | |
104 // ServiceWorkerVersion. | |
105 | |
106 // Hold messages on transferred message ports. Actual delivery of the | |
107 // message | |
Avi (use Gerrit)
2015/08/05 15:17:20
re-wrap this comment block
Marijn Kruisselbrink
2015/08/05 17:00:16
Done
| |
108 // by the service can be asynchronous. When a message is delivered, | |
109 // WebMessagePortChannelImpl instances will be constructed which send | |
110 // MessagePortHostMsg_ReleaseMessages to release messages. | |
111 for (const auto& sent_port : sent_message_ports) | |
112 MessagePortService::GetInstance()->HoldMessages(sent_port.id); | |
113 | |
114 service_worker_context_->FindRegistrationForId( | |
115 port.service_worker_registration_id, | |
116 port.service_worker_registration_origin, | |
117 base::Bind(&NavigatorConnectContextImpl::DeliverMessage, this, port.id, | |
118 message.message_as_string, sent_message_ports)); | |
75 } | 119 } |
76 | 120 |
77 if (!factory) { | 121 if (!port.service) { |
78 // No factories found. | 122 // TODO(mek): Figure out what to do in this situation. |
79 OnConnectResult(client, client_port_id, callback, nullptr, false); | 123 return; |
124 } | |
125 port.service->PostMessageToClient(port.id, message, sent_message_ports); | |
126 } | |
127 | |
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()); | |
137 | |
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()); | |
80 return; | 142 return; |
81 } | 143 } |
82 | 144 |
83 // Actually initiate connection. | 145 ServiceWorkerVersion* active_version = registration->active_version(); |
84 factory->Connect( | 146 if (!active_version) { |
85 client, base::Bind(&NavigatorConnectContextImpl::OnConnectResult, this, | 147 // No active version, reject connection attempt. |
86 client, client_port_id, callback)); | 148 OnConnectResult(callback, client_port_id, service_port_id, registration, |
149 status, false, base::string16(), base::string16()); | |
150 return; | |
151 } | |
152 | |
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(); | |
157 | |
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); | |
87 } | 162 } |
88 | 163 |
89 void NavigatorConnectContextImpl::ServicePortServiceDestroyed( | 164 void NavigatorConnectContextImpl::ServicePortServiceDestroyed( |
90 ServicePortServiceImpl* service_port_service) { | 165 ServicePortServiceImpl* service_port_service) { |
166 DCHECK_CURRENTLY_ON(BrowserThread::IO); | |
91 for (auto& port : ports_) { | 167 for (auto& port : ports_) { |
92 if (port.second.service != service_port_service) | 168 if (port.second.service != service_port_service) |
93 continue; | 169 continue; |
94 port.second.service = nullptr; | 170 port.second.service = nullptr; |
95 // TODO(mek): Should actually inform other side of connections that the | 171 // TODO(mek): Should actually inform other side of connections that the |
96 // connection was closed, or in the case of service workers somehow keep | 172 // connection was closed, or in the case of service workers somehow keep |
97 // track of the connection. | 173 // track of the connection. |
98 } | 174 } |
99 } | 175 } |
100 | 176 |
101 void NavigatorConnectContextImpl::SendMessage( | |
102 int route_id, | |
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]; | |
107 if (!port.service) { | |
108 // TODO(mek): Figure out what to do in this situation. | |
109 return; | |
110 } | |
111 | |
112 port.service->PostMessageToClient(route_id, message, sent_message_ports); | |
113 } | |
114 | |
115 void NavigatorConnectContextImpl::SendMessagesAreQueued(int route_id) { | |
116 NOTREACHED() << "navigator.services endpoints should never queue messages."; | |
117 } | |
118 | |
119 void NavigatorConnectContextImpl::OnConnectResult( | 177 void NavigatorConnectContextImpl::OnConnectResult( |
120 const NavigatorConnectClient& client, | |
121 int client_message_port_id, | |
122 const ConnectCallback& callback, | 178 const ConnectCallback& callback, |
123 MessagePortDelegate* delegate, | 179 int client_port_id, |
124 bool data_as_values) { | 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) { | |
125 DCHECK_CURRENTLY_ON(BrowserThread::IO); | 186 DCHECK_CURRENTLY_ON(BrowserThread::IO); |
126 if (delegate) { | 187 if (accept_connection) { |
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 | 188 // TODO(mek): Might have to do something else if the client connection got |
129 // severed while the service side connection was being set up. | 189 // severed while the service side connection was being set up. |
130 | 190 callback.Run(client_port_id, true); |
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); | |
136 } else { | 191 } else { |
137 // Destroy ports since connection failed. | 192 // Destroy ports since connection failed. |
138 MessagePortService::GetInstance()->Destroy(client.message_port_id); | 193 ports_.erase(service_port_id); |
139 MessagePortService::GetInstance()->Destroy(client_message_port_id); | 194 ports_.erase(client_port_id); |
140 ports_.erase(client_message_port_id); | |
141 callback.Run(MSG_ROUTING_NONE, false); | 195 callback.Run(MSG_ROUTING_NONE, false); |
142 } | 196 } |
143 } | 197 } |
144 | 198 |
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()); | |
208 | |
209 if (service_worker_status != SERVICE_WORKER_OK) { | |
210 // TODO(mek): Do something when no service worker was found. | |
211 return; | |
212 } | |
213 | |
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; | |
219 } | |
220 | |
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)); | |
226 } | |
227 | |
145 } // namespace content | 228 } // namespace content |
OLD | NEW |