| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 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 "chrome/renderer/extensions/extension_process_bindings.h" | 5 #include "chrome/renderer/extensions/extension_process_bindings.h" |
| 6 | 6 |
| 7 #include "base/singleton.h" | 7 #include "base/singleton.h" |
| 8 #include "base/stl_util-inl.h" | |
| 9 #include "chrome/common/render_messages.h" | 8 #include "chrome/common/render_messages.h" |
| 10 #include "chrome/common/url_constants.h" | 9 #include "chrome/common/url_constants.h" |
| 11 #include "chrome/renderer/extensions/bindings_utils.h" | 10 #include "chrome/renderer/extensions/bindings_utils.h" |
| 12 #include "chrome/renderer/extensions/event_bindings.h" | 11 #include "chrome/renderer/extensions/event_bindings.h" |
| 13 #include "chrome/renderer/extensions/renderer_extension_bindings.h" | 12 #include "chrome/renderer/extensions/renderer_extension_bindings.h" |
| 14 #include "chrome/renderer/js_only_v8_extensions.h" | 13 #include "chrome/renderer/js_only_v8_extensions.h" |
| 15 #include "chrome/renderer/render_view.h" | 14 #include "chrome/renderer/render_view.h" |
| 16 #include "grit/renderer_resources.h" | 15 #include "grit/renderer_resources.h" |
| 17 #include "webkit/api/public/WebScriptSource.h" | |
| 18 #include "webkit/glue/webframe.h" | 16 #include "webkit/glue/webframe.h" |
| 19 | 17 |
| 20 using WebKit::WebScriptSource; | 18 using bindings_utils::GetStringResource; |
| 21 using WebKit::WebString; | 19 using bindings_utils::ContextInfo; |
| 20 using bindings_utils::ContextList; |
| 21 using bindings_utils::GetContexts; |
| 22 using bindings_utils::ExtensionBase; |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 const char kExtensionName[] = "chrome/ExtensionProcessBindings"; | 26 const char kExtensionName[] = "chrome/ExtensionProcessBindings"; |
| 26 const char* kExtensionDeps[] = { | 27 const char* kExtensionDeps[] = { |
| 27 BaseJsV8Extension::kName, | 28 BaseJsV8Extension::kName, |
| 28 EventBindings::kName, | 29 EventBindings::kName, |
| 29 JsonSchemaJsV8Extension::kName, | 30 JsonSchemaJsV8Extension::kName, |
| 30 RendererExtensionBindings::kName, | 31 RendererExtensionBindings::kName, |
| 31 }; | 32 }; |
| 32 | 33 |
| 33 // Types for storage of per-renderer-singleton data structure that maps | |
| 34 // |extension_id| -> <List of v8 Contexts for the "views" of that extension> | |
| 35 typedef std::list< v8::Persistent<v8::Context> > ContextList; | |
| 36 typedef std::map<std::string, ContextList> ExtensionIdContextsMap; | |
| 37 | |
| 38 // Contains info relevant to a pending request. | |
| 39 struct CallContext { | |
| 40 public : | |
| 41 CallContext(v8::Persistent<v8::Context> context, const std::string& name) | |
| 42 : context(context), name(name) { | |
| 43 } | |
| 44 v8::Persistent<v8::Context> context; | |
| 45 std::string name; | |
| 46 }; | |
| 47 typedef std::map<int, CallContext*> PendingRequestMap; | |
| 48 | |
| 49 struct SingletonData { | 34 struct SingletonData { |
| 50 std::set<std::string> function_names_; | 35 std::set<std::string> function_names_; |
| 51 ExtensionIdContextsMap contexts; | |
| 52 PendingRequestMap pending_requests; | |
| 53 | |
| 54 ~SingletonData() { | |
| 55 STLDeleteContainerPairSecondPointers(pending_requests.begin(), | |
| 56 pending_requests.end()); | |
| 57 } | |
| 58 }; | 36 }; |
| 59 | 37 |
| 60 static std::set<std::string>* GetFunctionNameSet() { | 38 static std::set<std::string>* GetFunctionNameSet() { |
| 61 return &Singleton<SingletonData>()->function_names_; | 39 return &Singleton<SingletonData>()->function_names_; |
| 62 } | 40 } |
| 63 | 41 |
| 64 static ContextList& GetRegisteredContexts(std::string extension_id) { | 42 class ExtensionImpl : public ExtensionBase { |
| 65 return Singleton<SingletonData>::get()->contexts[extension_id]; | |
| 66 } | |
| 67 | |
| 68 static PendingRequestMap& GetPendingRequestMap() { | |
| 69 return Singleton<SingletonData>::get()->pending_requests; | |
| 70 } | |
| 71 | |
| 72 class ExtensionImpl : public v8::Extension { | |
| 73 public: | 43 public: |
| 74 ExtensionImpl() : v8::Extension( | 44 ExtensionImpl() : ExtensionBase( |
| 75 kExtensionName, GetStringResource<IDR_EXTENSION_PROCESS_BINDINGS_JS>(), | 45 kExtensionName, GetStringResource<IDR_EXTENSION_PROCESS_BINDINGS_JS>(), |
| 76 arraysize(kExtensionDeps), kExtensionDeps) {} | 46 arraysize(kExtensionDeps), kExtensionDeps) {} |
| 77 | 47 |
| 78 static void SetFunctionNames(const std::vector<std::string>& names) { | 48 static void SetFunctionNames(const std::vector<std::string>& names) { |
| 79 std::set<std::string>* name_set = GetFunctionNameSet(); | 49 std::set<std::string>* name_set = GetFunctionNameSet(); |
| 80 for (size_t i = 0; i < names.size(); ++i) { | 50 for (size_t i = 0; i < names.size(); ++i) { |
| 81 name_set->insert(names[i]); | 51 name_set->insert(names[i]); |
| 82 } | 52 } |
| 83 } | 53 } |
| 84 | 54 |
| 85 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | 55 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( |
| 86 v8::Handle<v8::String> name) { | 56 v8::Handle<v8::String> name) { |
| 87 std::set<std::string>* names = GetFunctionNameSet(); | 57 std::set<std::string>* names = GetFunctionNameSet(); |
| 88 | 58 |
| 89 if (name->Equals(v8::String::New("GetNextRequestId"))) | 59 if (name->Equals(v8::String::New("GetViews"))) { |
| 90 return v8::FunctionTemplate::New(GetNextRequestId); | |
| 91 else if (name->Equals(v8::String::New("RegisterExtension"))) | |
| 92 return v8::FunctionTemplate::New(RegisterExtension); | |
| 93 else if (name->Equals(v8::String::New("UnregisterExtension"))) | |
| 94 return v8::FunctionTemplate::New(UnregisterExtension); | |
| 95 else if (name->Equals(v8::String::New("GetViews"))) | |
| 96 return v8::FunctionTemplate::New(GetViews); | 60 return v8::FunctionTemplate::New(GetViews); |
| 97 else if (names->find(*v8::String::AsciiValue(name)) != names->end()) | 61 } else if (names->find(*v8::String::AsciiValue(name)) != names->end()) { |
| 98 return v8::FunctionTemplate::New(StartRequest, name); | 62 return v8::FunctionTemplate::New(ExtensionBase::StartRequest, name); |
| 63 } |
| 99 | 64 |
| 100 return v8::Handle<v8::FunctionTemplate>(); | 65 return ExtensionBase::GetNativeFunction(name); |
| 101 } | 66 } |
| 102 | 67 |
| 103 private: | 68 private: |
| 104 static v8::Handle<v8::Value> RegisterExtension(const v8::Arguments& args) { | |
| 105 RenderView* renderview = GetRenderViewForCurrentContext(); | |
| 106 DCHECK(renderview); | |
| 107 GURL url = renderview->webview()->GetMainFrame()->GetURL(); | |
| 108 DCHECK(url.scheme() == chrome::kExtensionScheme); | |
| 109 | |
| 110 v8::Persistent<v8::Context> current_context = | |
| 111 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); | |
| 112 DCHECK(!current_context.IsEmpty()); | |
| 113 | |
| 114 std::string extension_id = url.host(); | |
| 115 GetRegisteredContexts(extension_id).push_back(current_context); | |
| 116 return v8::String::New(extension_id.c_str()); | |
| 117 } | |
| 118 | |
| 119 static v8::Handle<v8::Value> UnregisterExtension(const v8::Arguments& args) { | |
| 120 DCHECK_EQ(args.Length(), 1); | |
| 121 DCHECK(args[0]->IsString()); | |
| 122 | |
| 123 v8::Local<v8::Context> current_context = v8::Context::GetCurrent(); | |
| 124 DCHECK(!current_context.IsEmpty()); | |
| 125 | |
| 126 // Remove all pending requests for this context. | |
| 127 PendingRequestMap& pending_requests = GetPendingRequestMap(); | |
| 128 for (PendingRequestMap::iterator it = pending_requests.begin(); | |
| 129 it != pending_requests.end(); ) { | |
| 130 PendingRequestMap::iterator current = it++; | |
| 131 if (current->second->context == current_context) { | |
| 132 current->second->context.Dispose(); | |
| 133 current->second->context.Clear(); | |
| 134 delete current->second; | |
| 135 pending_requests.erase(current); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 std::string extension_id(*v8::String::Utf8Value(args[0])); | |
| 140 ContextList& contexts = GetRegisteredContexts(extension_id); | |
| 141 ContextList::iterator it = std::find(contexts.begin(), contexts.end(), | |
| 142 current_context); | |
| 143 if (it == contexts.end()) { | |
| 144 NOTREACHED(); | |
| 145 return v8::Undefined(); | |
| 146 } | |
| 147 | |
| 148 it->Dispose(); | |
| 149 it->Clear(); | |
| 150 contexts.erase(it); | |
| 151 | |
| 152 return v8::Undefined(); | |
| 153 } | |
| 154 | |
| 155 static v8::Handle<v8::Value> GetViews(const v8::Arguments& args) { | 69 static v8::Handle<v8::Value> GetViews(const v8::Arguments& args) { |
| 156 RenderView* renderview = GetRenderViewForCurrentContext(); | 70 RenderView* renderview = bindings_utils::GetRenderViewForCurrentContext(); |
| 157 DCHECK(renderview); | 71 DCHECK(renderview); |
| 158 GURL url = renderview->webview()->GetMainFrame()->GetURL(); | 72 GURL url = renderview->webview()->GetMainFrame()->GetURL(); |
| 159 std::string extension_id = url.host(); | 73 std::string extension_id = url.host(); |
| 160 | 74 |
| 161 ContextList& contexts = GetRegisteredContexts(extension_id); | 75 ContextList contexts = |
| 76 bindings_utils::GetContextsForExtension(extension_id); |
| 162 DCHECK(contexts.size() > 0); | 77 DCHECK(contexts.size() > 0); |
| 163 | 78 |
| 164 v8::Local<v8::Array> views = v8::Array::New(contexts.size()); | 79 v8::Local<v8::Array> views = v8::Array::New(contexts.size()); |
| 165 int index = 0; | 80 int index = 0; |
| 166 ContextList::const_iterator it = contexts.begin(); | 81 ContextList::const_iterator it = contexts.begin(); |
| 167 for (; it != contexts.end(); ++it) { | 82 for (; it != contexts.end(); ++it) { |
| 168 v8::Local<v8::Value> window = (*it)->Global()->Get( | 83 v8::Local<v8::Value> window = (*it)->context->Global()->Get( |
| 169 v8::String::New("window")); | 84 v8::String::New("window")); |
| 170 DCHECK(!window.IsEmpty()); | 85 DCHECK(!window.IsEmpty()); |
| 171 views->Set(v8::Integer::New(index), window); | 86 views->Set(v8::Integer::New(index), window); |
| 172 index++; | 87 index++; |
| 173 } | 88 } |
| 174 return views; | 89 return views; |
| 175 } | 90 } |
| 176 | |
| 177 static v8::Handle<v8::Value> GetNextRequestId(const v8::Arguments& args) { | |
| 178 static int next_request_id = 0; | |
| 179 return v8::Integer::New(next_request_id++); | |
| 180 } | |
| 181 | |
| 182 static v8::Handle<v8::Value> StartRequest(const v8::Arguments& args) { | |
| 183 // Get the current RenderView so that we can send a routed IPC message from | |
| 184 // the correct source. | |
| 185 RenderView* renderview = GetRenderViewForCurrentContext(); | |
| 186 if (!renderview) | |
| 187 return v8::Undefined(); | |
| 188 | |
| 189 if (args.Length() != 3 || !args[0]->IsString() || !args[1]->IsInt32() || | |
| 190 !args[2]->IsBoolean()) | |
| 191 return v8::Undefined(); | |
| 192 | |
| 193 std::string name = *v8::String::AsciiValue(args.Data()); | |
| 194 std::string json_args = *v8::String::Utf8Value(args[0]); | |
| 195 int request_id = args[1]->Int32Value(); | |
| 196 bool has_callback = args[2]->BooleanValue(); | |
| 197 | |
| 198 v8::Persistent<v8::Context> current_context = | |
| 199 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); | |
| 200 DCHECK(!current_context.IsEmpty()); | |
| 201 GetPendingRequestMap()[request_id] = | |
| 202 new CallContext(current_context, *v8::String::AsciiValue(args.Data())); | |
| 203 | |
| 204 renderview->SendExtensionRequest(name, json_args, request_id, has_callback); | |
| 205 | |
| 206 return v8::Undefined(); | |
| 207 } | |
| 208 }; | 91 }; |
| 209 | 92 |
| 210 } // namespace | 93 } // namespace |
| 211 | 94 |
| 212 v8::Extension* ExtensionProcessBindings::Get() { | 95 v8::Extension* ExtensionProcessBindings::Get() { |
| 213 return new ExtensionImpl(); | 96 return new ExtensionImpl(); |
| 214 } | 97 } |
| 215 | 98 |
| 216 void ExtensionProcessBindings::SetFunctionNames( | 99 void ExtensionProcessBindings::SetFunctionNames( |
| 217 const std::vector<std::string>& names) { | 100 const std::vector<std::string>& names) { |
| 218 ExtensionImpl::SetFunctionNames(names); | 101 ExtensionImpl::SetFunctionNames(names); |
| 219 } | 102 } |
| 220 | |
| 221 void ExtensionProcessBindings::RegisterExtensionContext(WebFrame* frame) { | |
| 222 frame->ExecuteScript(WebScriptSource(WebString::fromUTF8( | |
| 223 "chrome.self.register_();"))); | |
| 224 } | |
| 225 | |
| 226 void ExtensionProcessBindings::HandleResponse(int request_id, bool success, | |
| 227 const std::string& response, | |
| 228 const std::string& error) { | |
| 229 CallContext* call = GetPendingRequestMap()[request_id]; | |
| 230 if (!call) | |
| 231 return; // The frame went away. | |
| 232 | |
| 233 v8::HandleScope handle_scope; | |
| 234 v8::Handle<v8::Value> argv[5]; | |
| 235 argv[0] = v8::Integer::New(request_id); | |
| 236 argv[1] = v8::String::New(call->name.c_str()); | |
| 237 argv[2] = v8::Boolean::New(success); | |
| 238 argv[3] = v8::String::New(response.c_str()); | |
| 239 argv[4] = v8::String::New(error.c_str()); | |
| 240 CallFunctionInContext(call->context, "chrome.handleResponse_", | |
| 241 arraysize(argv), argv); | |
| 242 | |
| 243 GetPendingRequestMap().erase(request_id); | |
| 244 delete call; | |
| 245 } | |
| OLD | NEW |