• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 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.
4 
5 #include "chrome/renderer/extensions/chrome_v8_context_set.h"
6 
7 #include "base/logging.h"
8 #include "base/message_loop/message_loop.h"
9 #include "base/tracked_objects.h"
10 #include "base/values.h"
11 #include "chrome/common/url_constants.h"
12 #include "chrome/renderer/extensions/chrome_v8_context.h"
13 #include "content/public/renderer/render_thread.h"
14 #include "content/public/renderer/render_view.h"
15 #include "extensions/common/constants.h"
16 #include "extensions/common/extension.h"
17 #include "third_party/WebKit/public/platform/WebURL.h"
18 #include "third_party/WebKit/public/platform/WebURLRequest.h"
19 #include "third_party/WebKit/public/web/WebDocument.h"
20 #include "third_party/WebKit/public/web/WebFrame.h"
21 #include "third_party/WebKit/public/web/WebView.h"
22 #include "v8/include/v8.h"
23 
24 using content::RenderThread;
25 
26 namespace extensions {
27 
ChromeV8ContextSet()28 ChromeV8ContextSet::ChromeV8ContextSet() {
29 }
~ChromeV8ContextSet()30 ChromeV8ContextSet::~ChromeV8ContextSet() {
31 }
32 
size() const33 int ChromeV8ContextSet::size() const {
34   return static_cast<int>(contexts_.size());
35 }
36 
Add(ChromeV8Context * context)37 void ChromeV8ContextSet::Add(ChromeV8Context* context) {
38   if (DCHECK_IS_ON()) {
39     // It's OK to insert the same context twice, but we should only ever have
40     // one ChromeV8Context per v8::Context.
41     for (ContextSet::iterator iter = contexts_.begin(); iter != contexts_.end();
42         ++iter) {
43       ChromeV8Context* candidate = *iter;
44       if (candidate != context)
45         DCHECK(candidate->v8_context() != context->v8_context());
46     }
47   }
48   contexts_.insert(context);
49 }
50 
Remove(ChromeV8Context * context)51 void ChromeV8ContextSet::Remove(ChromeV8Context* context) {
52   if (contexts_.erase(context)) {
53     context->Invalidate();
54     base::MessageLoop::current()->DeleteSoon(FROM_HERE, context);
55   }
56 }
57 
GetAll() const58 ChromeV8ContextSet::ContextSet ChromeV8ContextSet::GetAll() const {
59   return contexts_;
60 }
61 
GetCurrent() const62 ChromeV8Context* ChromeV8ContextSet::GetCurrent() const {
63   v8::Isolate* isolate = v8::Isolate::GetCurrent();
64   return isolate->InContext() ? GetByV8Context(isolate->GetCurrentContext())
65                               : NULL;
66 }
67 
GetCalling() const68 ChromeV8Context* ChromeV8ContextSet::GetCalling() const {
69   v8::Isolate* isolate = v8::Isolate::GetCurrent();
70   v8::Local<v8::Context> calling = isolate->GetCallingContext();
71   return calling.IsEmpty() ? NULL : GetByV8Context(calling);
72 }
73 
GetByV8Context(v8::Handle<v8::Context> v8_context) const74 ChromeV8Context* ChromeV8ContextSet::GetByV8Context(
75     v8::Handle<v8::Context> v8_context) const {
76   for (ContextSet::const_iterator iter = contexts_.begin();
77        iter != contexts_.end(); ++iter) {
78     if ((*iter)->v8_context() == v8_context)
79       return *iter;
80   }
81 
82   return NULL;
83 }
84 
ForEach(const std::string & extension_id,content::RenderView * render_view,const base::Callback<void (ChromeV8Context *)> & callback) const85 void ChromeV8ContextSet::ForEach(
86     const std::string& extension_id,
87     content::RenderView* render_view,
88     const base::Callback<void(ChromeV8Context*)>& callback) const {
89   // We copy the context list, because calling into javascript may modify it
90   // out from under us.
91   ContextSet contexts = GetAll();
92 
93   for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
94        ++it) {
95     ChromeV8Context* context = *it;
96 
97     // For the same reason as above, contexts may become invalid while we run.
98     if (!context->is_valid())
99       continue;
100 
101     if (!extension_id.empty()) {
102       const Extension* extension = context->extension();
103       if (!extension || (extension_id != extension->id()))
104         continue;
105     }
106 
107     content::RenderView* context_render_view = context->GetRenderView();
108     if (!context_render_view)
109       continue;
110 
111     if (render_view && render_view != context_render_view)
112       continue;
113 
114     callback.Run(context);
115   }
116 }
117 
OnExtensionUnloaded(const std::string & extension_id)118 ChromeV8ContextSet::ContextSet ChromeV8ContextSet::OnExtensionUnloaded(
119     const std::string& extension_id) {
120   ContextSet contexts = GetAll();
121   ContextSet removed;
122 
123   // Clean up contexts belonging to the unloaded extension. This is done so
124   // that content scripts (which remain injected into the page) don't continue
125   // receiving events and sending messages.
126   for (ContextSet::iterator it = contexts.begin(); it != contexts.end();
127        ++it) {
128     if ((*it)->extension() && (*it)->extension()->id() == extension_id) {
129       (*it)->DispatchOnUnloadEvent();
130       removed.insert(*it);
131       Remove(*it);
132     }
133   }
134 
135   return removed;
136 }
137 
138 }  // namespace extensions
139