15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/renderer/extensions/chrome_v8_context_set.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
89ab5563a3196760eb381d102cbb2bc0f7abc6a50Ben Murdoch#include "base/message_loop/message_loop.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/tracked_objects.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/values.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/extensions/extension.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/common/url_constants.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/renderer/extensions/chrome_v8_context.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/renderer/render_thread.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/renderer/render_view.h"
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "extensions/common/constants.h"
17868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebURL.h"
18868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "third_party/WebKit/public/platform/WebURLRequest.h"
197d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebDocument.h"
207d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebFrame.h"
217d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "third_party/WebKit/public/web/WebView.h"
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "v8/include/v8.h"
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::RenderThread;
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace extensions {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeV8ContextSet::ChromeV8ContextSet() {
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeV8ContextSet::~ChromeV8ContextSet() {
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int ChromeV8ContextSet::size() const {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return static_cast<int>(contexts_.size());
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeV8ContextSet::Add(ChromeV8Context* context) {
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (DCHECK_IS_ON()) {
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // It's OK to insert the same context twice, but we should only ever have
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    // one ChromeV8Context per v8::Context.
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    for (ContextSet::iterator iter = contexts_.begin(); iter != contexts_.end();
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        ++iter) {
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ChromeV8Context* candidate = *iter;
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      if (candidate != context)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        DCHECK(candidate->v8_context() != context->v8_context());
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  contexts_.insert(context);
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ChromeV8ContextSet::Remove(ChromeV8Context* context) {
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (contexts_.erase(context)) {
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    context->Invalidate();
54a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    base::MessageLoop::current()->DeleteSoon(FROM_HERE, context);
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ChromeV8ContextSet::ContextSet ChromeV8ContextSet::GetAll() const {
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return contexts_;
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeV8Context* ChromeV8ContextSet::GetCurrent() const {
63eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return v8::Context::InContext() ?
64eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      GetByV8Context(v8::Context::GetCurrent()) : NULL;
65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochChromeV8Context* ChromeV8ContextSet::GetCalling() const {
68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  v8::Local<v8::Context> calling = v8::Context::GetCalling();
69eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  return calling.IsEmpty() ? NULL : GetByV8Context(calling);
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ChromeV8Context* ChromeV8ContextSet::GetByV8Context(
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    v8::Handle<v8::Context> v8_context) const {
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ContextSet::const_iterator iter = contexts_.begin();
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       iter != contexts_.end(); ++iter) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if ((*iter)->v8_context() == v8_context)
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return *iter;
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
83868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)void ChromeV8ContextSet::ForEach(
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const std::string& extension_id,
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::RenderView* render_view,
86868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    const base::Callback<void(ChromeV8Context*)>& callback) const {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // We copy the context list, because calling into javascript may modify it
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // out from under us.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ContextSet contexts = GetAll();
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)       ++it) {
93868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    ChromeV8Context* context = *it;
94868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)
95868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    // For the same reason as above, contexts may become invalid while we run.
96868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (!context->is_valid())
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!extension_id.empty()) {
100868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      const Extension* extension = context->extension();
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (!extension || (extension_id != extension->id()))
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        continue;
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
105868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    content::RenderView* context_render_view = context->GetRenderView();
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!context_render_view)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (render_view && render_view != context_render_view)
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      continue;
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
112868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    callback.Run(context);
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
116c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)ChromeV8ContextSet::ContextSet ChromeV8ContextSet::OnExtensionUnloaded(
117c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const std::string& extension_id) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ContextSet contexts = GetAll();
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ContextSet removed;
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // Clean up contexts belonging to the unloaded extension. This is done so
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // that content scripts (which remain injected into the page) don't continue
1232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // receiving events and sending messages.
1242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
1252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)       ++it) {
1262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if ((*it)->extension() && (*it)->extension()->id() == extension_id) {
1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      (*it)->DispatchOnUnloadEvent();
128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      removed.insert(*it);
1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      Remove(*it);
1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  return removed;
1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace extensions
137