| 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 "extensions/renderer/dispatcher.h" | 5 #include "extensions/renderer/dispatcher.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/callback.h" | 8 #include "base/callback.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/containers/scoped_ptr_map.h" | 10 #include "base/containers/scoped_ptr_map.h" |
| (...skipping 179 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 190 void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) { | 190 void GetChrome(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 191 args.GetReturnValue().Set(GetOrCreateChrome(context())); | 191 args.GetReturnValue().Set(GetOrCreateChrome(context())); |
| 192 } | 192 } |
| 193 }; | 193 }; |
| 194 | 194 |
| 195 class ServiceWorkerScriptContextSet { | 195 class ServiceWorkerScriptContextSet { |
| 196 public: | 196 public: |
| 197 ServiceWorkerScriptContextSet() {} | 197 ServiceWorkerScriptContextSet() {} |
| 198 ~ServiceWorkerScriptContextSet() {} | 198 ~ServiceWorkerScriptContextSet() {} |
| 199 | 199 |
| 200 void Insert(scoped_ptr<ScriptContext> context) { | 200 void Insert(const GURL& url, scoped_ptr<ScriptContext> context) { |
| 201 base::AutoLock lock(lock_); | 201 base::AutoLock lock(lock_); |
| 202 CHECK(FindScriptContext(context->v8_context()) == contexts_.end()); | 202 CHECK(script_contexts_.find(url) == script_contexts_.end()); |
| 203 contexts_.push_back(context.Pass()); | 203 script_contexts_.set(url, context.Pass()); |
| 204 } | 204 } |
| 205 | 205 |
| 206 void Remove(v8::Local<v8::Context> v8_context) { | 206 void Remove(const GURL& url) { |
| 207 base::AutoLock lock(lock_); | 207 base::AutoLock lock(lock_); |
| 208 ScriptContextList::iterator context_it = FindScriptContext(v8_context); | 208 scoped_ptr<ScriptContext> context = script_contexts_.take_and_erase(url); |
| 209 // TODO(kalman): It would be good to CHECK(context_it != contexts_.end()) | 209 CHECK(context); |
| 210 // here, but service workers can be started before the extension has been | 210 context->Invalidate(); |
| 211 // installed. See the length comment explaining why this happens, and | |
| 212 // how to solve it, in DidInitializeServiceWorkerContextOnWorkerThread. | |
| 213 // This does need to be fixed eventually, but for now, at least don't crash. | |
| 214 if (context_it == contexts_.end()) | |
| 215 return; | |
| 216 (*context_it)->Invalidate(); | |
| 217 contexts_.erase(context_it); | |
| 218 } | 211 } |
| 219 | 212 |
| 220 private: | 213 private: |
| 221 using ScriptContextList = ScopedVector<ScriptContext>; | 214 base::ScopedPtrMap<GURL, scoped_ptr<ScriptContext>> script_contexts_; |
| 222 | |
| 223 // Returns an iterator to the ScriptContext associated with |v8_context|, or | |
| 224 // contexts_.end() if not found. | |
| 225 ScriptContextList::iterator FindScriptContext( | |
| 226 v8::Local<v8::Context> v8_context) { | |
| 227 for (auto it = contexts_.begin(); it != contexts_.end(); ++it) { | |
| 228 if ((*it)->v8_context() == v8_context) | |
| 229 return it; | |
| 230 } | |
| 231 return contexts_.end(); | |
| 232 } | |
| 233 | |
| 234 ScriptContextList contexts_; | |
| 235 | 215 |
| 236 mutable base::Lock lock_; | 216 mutable base::Lock lock_; |
| 237 | 217 |
| 238 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerScriptContextSet); | 218 DISALLOW_COPY_AND_ASSIGN(ServiceWorkerScriptContextSet); |
| 239 }; | 219 }; |
| 240 | 220 |
| 241 base::LazyInstance<ServiceWorkerScriptContextSet> | 221 base::LazyInstance<ServiceWorkerScriptContextSet> |
| 242 g_service_worker_script_context_set = LAZY_INSTANCE_INITIALIZER; | 222 g_service_worker_script_context_set = LAZY_INSTANCE_INITIALIZER; |
| 243 | 223 |
| 244 } // namespace | 224 } // namespace |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 396 | 376 |
| 397 // static | 377 // static |
| 398 void Dispatcher::DidInitializeServiceWorkerContextOnWorkerThread( | 378 void Dispatcher::DidInitializeServiceWorkerContextOnWorkerThread( |
| 399 v8::Local<v8::Context> v8_context, | 379 v8::Local<v8::Context> v8_context, |
| 400 const GURL& url) { | 380 const GURL& url) { |
| 401 const base::TimeTicks start_time = base::TimeTicks::Now(); | 381 const base::TimeTicks start_time = base::TimeTicks::Now(); |
| 402 | 382 |
| 403 const Extension* extension = | 383 const Extension* extension = |
| 404 RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(url); | 384 RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(url); |
| 405 | 385 |
| 406 if (!extension) { | 386 if (!extension) |
| 407 // TODO(kalman): This is no good. Instead we need to either: | |
| 408 // | |
| 409 // - Hold onto the v8::Context and create the ScriptContext and install | |
| 410 // our bindings when this extension is loaded. | |
| 411 // - Deal with there being an extension ID (url.host()) but no | |
| 412 // extension associated with it, then document that getBackgroundClient | |
| 413 // may fail if the extension hasn't loaded yet. | |
| 414 // | |
| 415 // The former is safer, but is unfriendly to caching (e.g. session restore). | |
| 416 // It seems to contradict the service worker idiom. | |
| 417 // | |
| 418 // The latter is friendly to caching, but running extension code without an | |
| 419 // installed extension makes me nervous, and means that we won't be able to | |
| 420 // expose arbitrary (i.e. capability-checked) extension APIs to service | |
| 421 // workers. We will probably need to relax some assertions - we just need | |
| 422 // to find them. | |
| 423 // | |
| 424 // Perhaps this could be solved with our own event on the service worker | |
| 425 // saying that an extension is ready, and documenting that extension APIs | |
| 426 // won't work before that event has fired? | |
| 427 return; | 387 return; |
| 428 } | |
| 429 | 388 |
| 430 ScriptContext* context = new ScriptContext( | 389 ScriptContext* context = new ScriptContext( |
| 431 v8_context, nullptr, extension, Feature::SERVICE_WORKER_CONTEXT, | 390 v8_context, nullptr, extension, Feature::SERVICE_WORKER_CONTEXT, |
| 432 extension, Feature::SERVICE_WORKER_CONTEXT); | 391 extension, Feature::SERVICE_WORKER_CONTEXT); |
| 433 | 392 |
| 434 g_service_worker_script_context_set.Get().Insert(make_scoped_ptr(context)); | 393 g_service_worker_script_context_set.Get().Insert(url, |
| 394 make_scoped_ptr(context)); |
| 435 | 395 |
| 436 v8::Isolate* isolate = context->isolate(); | 396 v8::Isolate* isolate = context->isolate(); |
| 437 | 397 |
| 438 // Fetch the source code for service_worker_bindings.js. | 398 // Fetch the source code for service_worker_bindings.js. |
| 439 base::StringPiece script_resource = | 399 base::StringPiece script_resource = |
| 440 ResourceBundle::GetSharedInstance().GetRawDataResource( | 400 ResourceBundle::GetSharedInstance().GetRawDataResource( |
| 441 IDR_SERVICE_WORKER_BINDINGS_JS); | 401 IDR_SERVICE_WORKER_BINDINGS_JS); |
| 442 v8::Local<v8::String> script = v8::String::NewExternal( | 402 v8::Local<v8::String> script = v8::String::NewExternal( |
| 443 isolate, new StaticV8ExternalOneByteStringResource(script_resource)); | 403 isolate, new StaticV8ExternalOneByteStringResource(script_resource)); |
| 444 | 404 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 471 // TODO(kalman): Make |request_sender| use |context->AddInvalidationObserver|. | 431 // TODO(kalman): Make |request_sender| use |context->AddInvalidationObserver|. |
| 472 // In fact |request_sender_| should really be owned by ScriptContext. | 432 // In fact |request_sender_| should really be owned by ScriptContext. |
| 473 request_sender_->InvalidateSource(context); | 433 request_sender_->InvalidateSource(context); |
| 474 | 434 |
| 475 script_context_set_->Remove(context); | 435 script_context_set_->Remove(context); |
| 476 VLOG(1) << "Num tracked contexts: " << script_context_set_->size(); | 436 VLOG(1) << "Num tracked contexts: " << script_context_set_->size(); |
| 477 } | 437 } |
| 478 | 438 |
| 479 // static | 439 // static |
| 480 void Dispatcher::WillDestroyServiceWorkerContextOnWorkerThread( | 440 void Dispatcher::WillDestroyServiceWorkerContextOnWorkerThread( |
| 481 v8::Local<v8::Context> v8_context, | |
| 482 const GURL& url) { | 441 const GURL& url) { |
| 483 if (url.SchemeIs(kExtensionScheme)) | 442 if (RendererExtensionRegistry::Get()->GetExtensionOrAppByURL(url)) |
| 484 g_service_worker_script_context_set.Get().Remove(v8_context); | 443 g_service_worker_script_context_set.Get().Remove(url); |
| 485 } | 444 } |
| 486 | 445 |
| 487 void Dispatcher::DidCreateDocumentElement(blink::WebLocalFrame* frame) { | 446 void Dispatcher::DidCreateDocumentElement(blink::WebLocalFrame* frame) { |
| 488 // Note: use GetEffectiveDocumentURL not just frame->document()->url() | 447 // Note: use GetEffectiveDocumentURL not just frame->document()->url() |
| 489 // so that this also injects the stylesheet on about:blank frames that | 448 // so that this also injects the stylesheet on about:blank frames that |
| 490 // are hosted in the extension process. | 449 // are hosted in the extension process. |
| 491 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL( | 450 GURL effective_document_url = ScriptContext::GetEffectiveDocumentURL( |
| 492 frame, frame->document().url(), true /* match_about_blank */); | 451 frame, frame->document().url(), true /* match_about_blank */); |
| 493 | 452 |
| 494 const Extension* extension = | 453 const Extension* extension = |
| (...skipping 1115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1610 void Dispatcher::AddChannelSpecificFeatures() { | 1569 void Dispatcher::AddChannelSpecificFeatures() { |
| 1611 // chrome-extension: resources should be allowed to register a Service Worker. | 1570 // chrome-extension: resources should be allowed to register a Service Worker. |
| 1612 if (FeatureProvider::GetBehaviorFeature(BehaviorFeature::kServiceWorker) | 1571 if (FeatureProvider::GetBehaviorFeature(BehaviorFeature::kServiceWorker) |
| 1613 ->IsAvailableToEnvironment() | 1572 ->IsAvailableToEnvironment() |
| 1614 .is_available()) | 1573 .is_available()) |
| 1615 WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers( | 1574 WebSecurityPolicy::registerURLSchemeAsAllowingServiceWorkers( |
| 1616 WebString::fromUTF8(kExtensionScheme)); | 1575 WebString::fromUTF8(kExtensionScheme)); |
| 1617 } | 1576 } |
| 1618 | 1577 |
| 1619 } // namespace extensions | 1578 } // namespace extensions |
| OLD | NEW |