Upstream version 5.34.97.0
[platform/framework/web/crosswalk.git] / src / xwalk / extensions / common / xwalk_extension_server.cc
1 // Copyright (c) 2013 Intel Corporation. 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 "xwalk/extensions/common/xwalk_extension_server.h"
6
7 #include "base/file_util.h"
8 #include "base/files/file_enumerator.h"
9 #include "base/files/file_path.h"
10 #include "base/strings/string16.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/stl_util.h"
13 #include "content/public/browser/render_process_host.h"
14 #include "ipc/ipc_sender.h"
15 #include "xwalk/extensions/common/xwalk_extension_messages.h"
16 #include "xwalk/extensions/common/xwalk_external_extension.h"
17
18 namespace xwalk {
19 namespace extensions {
20
21 XWalkExtensionServer::XWalkExtensionServer()
22     : sender_(NULL),
23       permissions_delegate_(NULL) {}
24
25 XWalkExtensionServer::~XWalkExtensionServer() {
26   DeleteInstanceMap();
27   STLDeleteValues(&extensions_);
28 }
29
30 bool XWalkExtensionServer::OnMessageReceived(const IPC::Message& message) {
31   bool handled = true;
32   IPC_BEGIN_MESSAGE_MAP(XWalkExtensionServer, message)
33     IPC_MESSAGE_HANDLER(XWalkExtensionServerMsg_CreateInstance,
34         OnCreateInstance)
35     IPC_MESSAGE_HANDLER(XWalkExtensionServerMsg_DestroyInstance,
36         OnDestroyInstance)
37     IPC_MESSAGE_HANDLER(XWalkExtensionServerMsg_PostMessageToNative,
38         OnPostMessageToNative)
39     IPC_MESSAGE_HANDLER_DELAY_REPLY(
40         XWalkExtensionServerMsg_SendSyncMessageToNative,
41         OnSendSyncMessageToNative)
42     IPC_MESSAGE_HANDLER(XWalkExtensionServerMsg_GetExtensions,
43         OnGetExtensions)
44     IPC_MESSAGE_UNHANDLED(handled = false)
45   IPC_END_MESSAGE_MAP()
46
47   return handled;
48 }
49
50 void XWalkExtensionServer::OnCreateInstance(int64_t instance_id,
51     std::string name) {
52   ExtensionMap::const_iterator it = extensions_.find(name);
53
54   if (it == extensions_.end()) {
55     LOG(WARNING) << "Can't create instance of extension: " << name
56         << ". Extension is not registered.";
57     return;
58   }
59
60   XWalkExtensionInstance* instance = it->second->CreateInstance();
61   instance->SetPostMessageCallback(
62       base::Bind(&XWalkExtensionServer::PostMessageToJSCallback,
63                  base::Unretained(this), instance_id));
64
65   instance->SetSendSyncReplyCallback(
66       base::Bind(&XWalkExtensionServer::SendSyncReplyToJSCallback,
67                  base::Unretained(this), instance_id));
68
69   InstanceExecutionData data;
70   data.instance = instance;
71   data.pending_reply = NULL;
72
73   instances_[instance_id] = data;
74 }
75
76 void XWalkExtensionServer::OnPostMessageToNative(int64_t instance_id,
77     const base::ListValue& msg) {
78   InstanceMap::const_iterator it = instances_.find(instance_id);
79   if (it == instances_.end()) {
80     LOG(WARNING) << "Can't PostMessage to invalid Extension instance id: "
81                  << instance_id;
82     return;
83   }
84
85   const InstanceExecutionData& data = it->second;
86
87   // The const_cast is needed to remove the only Value contained by the
88   // ListValue (which is solely used as wrapper, since Value doesn't
89   // have param traits for serialization) and we pass the ownership to to
90   // HandleMessage. It is safe to do this because the |msg| won't be used
91   // anywhere else when this function returns. Saves a DeepCopy(), which
92   // can be costly depending on the size of Value.
93   scoped_ptr<base::Value> value;
94   const_cast<base::ListValue*>(&msg)->Remove(0, &value);
95   data.instance->HandleMessage(value.Pass());
96 }
97
98 void XWalkExtensionServer::Initialize(IPC::Sender* sender) {
99   base::AutoLock l(sender_lock_);
100   DCHECK(!sender_);
101   sender_ = sender;
102 }
103
104 bool XWalkExtensionServer::Send(IPC::Message* msg) {
105   base::AutoLock l(sender_lock_);
106   if (!sender_)
107     return false;
108   return sender_->Send(msg);
109 }
110
111 namespace {
112
113 bool ValidateExtensionIdentifier(const std::string& name) {
114   bool dot_allowed = false;
115   bool digit_or_underscore_allowed = false;
116   for (size_t i = 0; i < name.size(); ++i) {
117     char c = name[i];
118     if (IsAsciiDigit(c)) {
119       if (!digit_or_underscore_allowed)
120         return false;
121     } else if (c == '_') {
122       if (!digit_or_underscore_allowed)
123         return false;
124     } else if (c == '.') {
125       if (!dot_allowed)
126         return false;
127       dot_allowed = false;
128       digit_or_underscore_allowed = false;
129     } else if (IsAsciiAlpha(c)) {
130       dot_allowed = true;
131       digit_or_underscore_allowed = true;
132     } else {
133       return false;
134     }
135   }
136
137   // If after going through the entire name we finish with dot_allowed, it means
138   // the previous character is not a dot, so it's a valid name.
139   return dot_allowed;
140 }
141
142 }  // namespace
143
144 bool XWalkExtensionServer::RegisterExtension(
145     scoped_ptr<XWalkExtension> extension) {
146   if (!ValidateExtensionIdentifier(extension->name())) {
147     LOG(WARNING) << "Ignoring extension with invalid name: "
148                  << extension->name();
149     return false;
150   }
151
152   if (ContainsKey(extension_symbols_, extension->name())) {
153     LOG(WARNING) << "Ignoring extension with name already registered: "
154                  << extension->name();
155     return false;
156   }
157
158   if (!ValidateExtensionEntryPoints(extension->entry_points())) {
159     LOG(WARNING) << "Ignoring extension '" << extension->name()
160                  << "' with invalid entry point.";
161     return false;
162   }
163
164   const base::ListValue& entry_points = extension->entry_points();
165   base::ListValue::const_iterator it = entry_points.begin();
166
167   for (; it != entry_points.end(); ++it) {
168     std::string entry_point;
169     (*it)->GetAsString(&entry_point);
170     extension_symbols_.insert(entry_point);
171   }
172
173   std::string name = extension->name();
174   extension_symbols_.insert(name);
175   extensions_[name] = extension.release();
176   return true;
177 }
178
179 bool XWalkExtensionServer::ContainsExtension(
180     const std::string& extension_name) const {
181   return ContainsKey(extensions_, extension_name);
182 }
183
184 void XWalkExtensionServer::PostMessageToJSCallback(
185     int64_t instance_id, scoped_ptr<base::Value> msg) {
186   base::ListValue wrapped_msg;
187   wrapped_msg.Append(msg.release());
188   Send(new XWalkExtensionClientMsg_PostMessageToJS(instance_id, wrapped_msg));
189 }
190
191 void XWalkExtensionServer::SendSyncReplyToJSCallback(
192     int64_t instance_id, scoped_ptr<base::Value> reply) {
193
194   InstanceMap::iterator it = instances_.find(instance_id);
195   if (it == instances_.end()) {
196     LOG(WARNING) << "Can't SendSyncMessage to invalid Extension instance id: "
197                  << instance_id;
198     return;
199   }
200
201   InstanceExecutionData& data = it->second;
202   if (!data.pending_reply) {
203     LOG(WARNING) << "There's no pending SyncMessage for instance id: "
204                  << instance_id;
205     return;
206   }
207
208   base::ListValue wrapped_reply;
209   wrapped_reply.Append(reply.release());
210
211   // TODO(cmarcelo): we need to inline WriteReplyParams here because it takes
212   // a copy of the parameter and ListValue is noncopyable. This may be
213   // improved in ipc_message_utils.h so we don't need to inline the code here.
214   XWalkExtensionServerMsg_SendSyncMessageToNative::ReplyParam
215       reply_param(wrapped_reply);
216   IPC::WriteParam(data.pending_reply, reply_param);
217   Send(data.pending_reply);
218
219   data.pending_reply = NULL;
220 }
221
222 void XWalkExtensionServer::DeleteInstanceMap() {
223   InstanceMap::iterator it = instances_.begin();
224   int pending_replies_left = 0;
225
226   for (; it != instances_.end(); ++it) {
227     delete it->second.instance;
228     if (it->second.pending_reply) {
229       pending_replies_left++;
230       delete it->second.pending_reply;
231     }
232   }
233
234   instances_.clear();
235
236   if (pending_replies_left > 0) {
237     LOG(WARNING) << pending_replies_left
238                  << " pending replies left when destroying server.";
239   }
240 }
241
242 bool XWalkExtensionServer::ValidateExtensionEntryPoints(
243     const base::ListValue& entry_points) {
244   base::ListValue::const_iterator it = entry_points.begin();
245
246   for (; it != entry_points.end(); ++it) {
247     std::string entry_point;
248
249     (*it)->GetAsString(&entry_point);
250
251     if (!ValidateExtensionIdentifier(entry_point))
252       return false;
253
254     if (ContainsKey(extension_symbols_, entry_point)) {
255       LOG(WARNING) << "Entry point '" << entry_point
256                    << "' clashes with another extension entry point.";
257       return false;
258     }
259   }
260
261   return true;
262 }
263
264 void XWalkExtensionServer::OnSendSyncMessageToNative(int64_t instance_id,
265     const base::ListValue& msg, IPC::Message* ipc_reply) {
266   InstanceMap::iterator it = instances_.find(instance_id);
267   if (it == instances_.end()) {
268     LOG(WARNING) << "Can't SendSyncMessage to invalid Extension instance id: "
269                  << instance_id;
270     return;
271   }
272
273   InstanceExecutionData& data = it->second;
274   if (data.pending_reply) {
275     LOG(WARNING) << "There's already a pending Sync Message for "
276                  << "Extension instance id: " << instance_id;
277     return;
278   }
279
280   data.pending_reply = ipc_reply;
281
282   // The const_cast is needed to remove the only Value contained by the
283   // ListValue (which is solely used as wrapper, since Value doesn't
284   // have param traits for serialization) and we pass the ownership to to
285   // HandleMessage. It is safe to do this because the |msg| won't be used
286   // anywhere else when this function returns. Saves a DeepCopy(), which
287   // can be costly depending on the size of Value.
288   scoped_ptr<base::Value> value;
289   const_cast<base::ListValue*>(&msg)->Remove(0, &value);
290   XWalkExtensionInstance* instance = data.instance;
291
292   instance->HandleSyncMessage(value.Pass());
293 }
294
295 void XWalkExtensionServer::OnDestroyInstance(int64_t instance_id) {
296   InstanceMap::iterator it = instances_.find(instance_id);
297   if (it == instances_.end()) {
298     LOG(WARNING) << "Can't destroy inexistent instance:" << instance_id;
299     return;
300   }
301
302   InstanceExecutionData& data = it->second;
303
304   delete data.instance;
305   instances_.erase(it);
306
307   Send(new XWalkExtensionClientMsg_InstanceDestroyed(instance_id));
308 }
309
310 void XWalkExtensionServer::OnGetExtensions(
311     std::vector<XWalkExtensionServerMsg_ExtensionRegisterParams>* reply) {
312   ExtensionMap::iterator it = extensions_.begin();
313   for (; it != extensions_.end(); ++it) {
314     XWalkExtensionServerMsg_ExtensionRegisterParams extension_parameters;
315     XWalkExtension* extension = it->second;
316
317     extension_parameters.name = extension->name();
318     extension_parameters.js_api = extension->javascript_api();
319
320     const base::ListValue& entry_points = extension->entry_points();
321     base::ListValue::const_iterator entry_it = entry_points.begin();
322     for (; entry_it != entry_points.end(); ++entry_it) {
323       std::string entry_point;
324       (*entry_it)->GetAsString(&entry_point);
325       extension_parameters.entry_points.push_back(entry_point);
326     }
327
328     reply->push_back(extension_parameters);
329   }
330 }
331
332 void XWalkExtensionServer::Invalidate() {
333   base::AutoLock l(sender_lock_);
334   sender_ = NULL;
335 }
336
337 namespace {
338 base::FilePath::StringType GetNativeLibraryPattern() {
339   const base::string16 library_pattern = base::GetNativeLibraryName(
340       base::UTF8ToUTF16("*"));
341 #if defined(OS_WIN)
342   return library_pattern;
343 #else
344   return base::UTF16ToUTF8(library_pattern);
345 #endif
346 }
347 }  // namespace
348
349 std::vector<std::string> RegisterExternalExtensionsInDirectory(
350     XWalkExtensionServer* server, const base::FilePath& dir,
351     const base::ValueMap& runtime_variables) {
352   CHECK(server);
353
354   std::vector<std::string> registered_extensions;
355
356   if (!base::DirectoryExists(dir)) {
357     LOG(WARNING) << "Couldn't load external extensions from non-existent"
358                  << " directory " << dir.AsUTF8Unsafe();
359     return registered_extensions;
360   }
361
362   base::FileEnumerator libraries(
363       dir, false, base::FileEnumerator::FILES, GetNativeLibraryPattern());
364
365   for (base::FilePath extension_path = libraries.Next();
366         !extension_path.empty(); extension_path = libraries.Next()) {
367     scoped_ptr<XWalkExternalExtension> extension(
368         new XWalkExternalExtension(extension_path));
369     extension->set_runtime_variables(runtime_variables);
370     if (server->permissions_delegate())
371       extension->set_permissions_delegate(server->permissions_delegate());
372     if (extension->Initialize()) {
373       registered_extensions.push_back(extension->name());
374       server->RegisterExtension(extension.PassAs<XWalkExtension>());
375     } else {
376       LOG(WARNING) << "Failed to initialize extension: "
377                    << extension_path.AsUTF8Unsafe();
378     }
379   }
380
381   return registered_extensions;
382 }
383
384 bool ValidateExtensionNameForTesting(const std::string& extension_name) {
385   return ValidateExtensionIdentifier(extension_name);
386 }
387
388 }  // namespace extensions
389 }  // namespace xwalk
390