Chromium Code Reviews| 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 |