597a7d0b5f97473c732d8b7508e774bad2ddf542
[platform/framework/web/crosswalk-tizen.git] / src / common / resource_manager.cc
1 // Copyright 2015 Samsung Electronics Co, Ltd. 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 "common/resource_manager.h"
6
7 #include <stdio.h>
8 #include <aul.h>
9
10 #include <memory>
11 #include <regex>
12 #include <vector>
13
14 #include "common/logger.h"
15 #include "common/file_utils.h"
16 #include "common/string_utils.h"
17 #include "common/app_control.h"
18 #include "common/application_data.h"
19 #include "common/locale_manager.h"
20
21 using wgt::parse::AppControlInfo;
22
23 namespace wrt {
24
25 namespace {
26
27 typedef std::vector<AppControlInfo> AppControlList;
28
29 // Scheme type
30 const char* kSchemeTypeApp = "app://";
31 const char* kSchemeTypeFile = "file://";
32 // TODO(wy80.choi): comment out below unused const variables if needed.
33 // const char* kSchemeTypeHttp = "http://";
34 // const char* kSchemeTypeHttps = "https://";
35 // const char* kSchemeTypeWidget = "widget://";
36
37 // Default Start Files
38 const char* kDefaultStartFiles[] = {
39   "index.htm",
40   "index.html",
41   "index.svg",
42   "index.xhtml",
43   "index.xht"
44 };
45
46 static std::string GetMimeFromUri(const std::string& uri) {
47   // checking passed uri is local file
48   std::string file_uri_case(kSchemeTypeFile);
49   int ret = AUL_R_EINVAL;
50   char mimetype[128] = {0, };
51   size_t pos = std::string::npos;
52   if (utils::StartsWith(uri, file_uri_case)) {
53     // case 1. uri = file:///xxxx
54     ret = aul_get_mime_from_file(uri.substr(pos+file_uri_case.length()).c_str(),
55                                  mimetype, sizeof(mimetype));
56   } else if (utils::StartsWith(uri, "/")) {
57     // case 2. uri = /xxxx
58     ret = aul_get_mime_from_file(uri.c_str(),
59                                  mimetype, sizeof(mimetype));
60   }
61
62   if (ret == AUL_R_OK) {
63     return std::string(mimetype);
64   } else {
65     return std::string();
66   }
67 }
68
69 static bool CompareStringWithWildcard(const std::string& origin,
70                                       const std::string& target) {
71   std::string wildcard_str = utils::ReplaceAll(origin, "*", ".*");
72   try {
73     std::regex re(wildcard_str, std::regex_constants::icase);
74     return std::regex_match(target.begin(), target.end(), re);
75   } catch (std::regex_error& e) {
76     LOGGER(ERROR) << "regex_error caught: " << e.what();
77     return false;
78   }
79 }
80
81 static bool CompareMime(const std::string& origin, const std::string& target) {
82   return CompareStringWithWildcard(origin, target);
83 }
84
85 static bool CompareUri(const std::string& origin_uri,
86                        const std::string& target_uri) {
87   std::string origin_scheme = utils::SchemeName(origin_uri);
88   std::string target_scheme = utils::SchemeName(target_uri);
89
90   if (!origin_scheme.empty() && !target_scheme.empty()) {
91     return (origin_scheme == target_scheme);
92   } else {
93     return CompareStringWithWildcard(origin_uri, target_uri);
94   }
95 }
96
97 static AppControlList::const_iterator CompareMimeAndUri(
98     const AppControlList& operation_list,
99     const std::string& mime, const std::string& uri) {
100   if (mime.empty() && uri.empty()) {
101     // 1. request_mime = "", request_uri = ""
102     for (auto iter = operation_list.begin();
103          iter != operation_list.end(); ++iter) {
104       if (iter->mime().empty() && iter->uri().empty()) {
105         return iter;
106       }
107     }
108   } else if (mime.empty() && !uri.empty()) {
109     // 2.. request_mime = "", request_uri = "blahblah"
110     for (auto iter = operation_list.begin();
111          iter != operation_list.end(); ++iter) {
112       if (iter->mime().empty() && CompareUri(iter->uri(), uri)) {
113         return iter;
114       }
115     }
116   } else if (!mime.empty() && uri.empty()) {
117     // 3... request_mime = "blahblah", request_uri = ""
118     for (auto iter = operation_list.begin();
119          iter != operation_list.end(); ++iter) {
120       if (iter->uri().empty() && CompareMime(iter->mime(), mime)) {
121         return iter;
122       }
123     }
124   } else {
125     // 4... request_mime = "blahblah", request_uri = "blahblah"
126     for (auto iter = operation_list.begin();
127          iter != operation_list.end(); ++iter) {
128       if (CompareMime(iter->mime(), mime) &&
129           CompareUri(iter->uri(), uri)) {
130         return iter;
131       }
132     }
133   }
134   return operation_list.end();
135 }
136
137 static void FindOperations(AppControlList* app_control_list,
138                            const std::string& operation) {
139   auto iter = app_control_list->begin();
140   while (iter != app_control_list->end()) {
141     if (iter->operation() != operation) {
142       app_control_list->erase(iter++);
143     } else {
144       ++iter;
145     }
146   }
147 }
148
149 static std::string InsertPrefixPath(const std::string& start_uri) {
150   if (start_uri.find("://") != std::string::npos) {
151     return start_uri;
152   } else {
153     return std::string() + kSchemeTypeFile + "/" + start_uri;
154   }
155 }
156
157 }  // namespace
158
159 ResourceManager::Resource::Resource(const std::string& uri)
160   : uri_(uri), should_reset_(true) {}
161
162 ResourceManager::Resource::Resource(const std::string& uri,
163                                     const std::string& mime)
164   : uri_(uri), mime_(mime), should_reset_(true) {}
165
166 ResourceManager::Resource::Resource(const std::string& uri,
167                                     const std::string& mime, bool should_reset)
168   : uri_(uri), mime_(mime), should_reset_(should_reset) {}
169
170 ResourceManager::Resource::Resource(const ResourceManager::Resource& res) {
171   *this = res;
172 }
173
174 ResourceManager::Resource& ResourceManager::Resource::operator=(
175     const ResourceManager::Resource& res) {
176   this->uri_ = res.uri();
177   this->mime_ = res.mime();
178   this->should_reset_ = res.should_reset();
179   return *this;
180 }
181
182 bool ResourceManager::Resource::operator==(const Resource& res) {
183   if (this->uri_ == res.uri() && this->mime_ == res.mime()
184      && this->should_reset_ == res.should_reset()) {
185     return true;
186   } else {
187     return false;
188   }
189 }
190
191 ResourceManager::ResourceManager(ApplicationData* application_data,
192                                  LocaleManager* locale_manager)
193     : application_data_(application_data), locale_manager_(locale_manager) {
194   if (application_data != NULL) {
195     appid_ = application_data->tizen_application_info()->id();
196   }
197 }
198
199 std::string ResourceManager::GetDefaultOrEmpty() {
200   std::string default_src;
201
202   // content src
203   auto content_info = application_data_->content_info();
204   if (content_info) {
205     default_src = content_info->src();
206   } else {
207     LOGGER(WARN) << "ContentInfo is NULL.";
208   }
209
210   if (!default_src.empty()) {
211     return InsertPrefixPath(default_src);
212   }
213
214   // if there is no content src, find reserved index files
215   for (auto& start_file : kDefaultStartFiles) {
216     if (utils::Exists(resource_base_path_ + start_file)) {
217       default_src = start_file;
218     }
219   }
220
221   return InsertPrefixPath(default_src);
222 }
223
224 std::string ResourceManager::GetMatchedSrcOrUri(
225     const AppControlInfo& app_control_info) {
226   if (!app_control_info.src().empty()) {
227     return InsertPrefixPath(app_control_info.src());
228   }
229
230   if (!app_control_info.uri().empty()) {
231     return InsertPrefixPath(app_control_info.uri());
232   }
233
234   return GetDefaultOrEmpty();
235 }
236
237 std::unique_ptr<ResourceManager::Resource> ResourceManager::GetStartResource(
238     const AppControl* app_control) {
239   std::string operation = app_control->operation();
240   if (operation.empty()) {
241     LOGGER(ERROR) << "operation(mandatory) is NULL";
242     return std::unique_ptr<Resource>(new Resource(GetDefaultOrEmpty()));
243   }
244
245   std::string mime = app_control->mime();
246   std::string uri = app_control->uri();
247   if (mime.empty() && !uri.empty()) {
248     mime = GetMimeFromUri(uri);
249   }
250
251   LOGGER(DEBUG) << "Passed AppControl data";
252   LOGGER(DEBUG) << " - operation : " << operation;
253   LOGGER(DEBUG) << " - mimetype  : " << mime;
254   LOGGER(DEBUG) << " - uri       : " << uri;
255
256   if (application_data_ == NULL ||
257       application_data_->app_control_info_list() == NULL) {
258     return std::unique_ptr<Resource>(new Resource(GetDefaultOrEmpty()));
259   }
260
261   AppControlList app_control_list =
262     application_data_->app_control_info_list()->controls;
263   FindOperations(&app_control_list, operation);
264
265   if (!app_control_list.empty()) {
266     AppControlList::const_iterator iter =
267       CompareMimeAndUri(app_control_list, mime, uri);
268     if (iter != app_control_list.end()) {
269       // TODO(jh5.cho) : following comment will be added after SRPOL implement
270       return std::unique_ptr<Resource>(
271         new Resource(GetMatchedSrcOrUri(*iter), iter->mime()
272                    /*, iter->should_reset()*/));
273     } else {
274     return std::unique_ptr<Resource>(new Resource(GetDefaultOrEmpty()));
275     }
276   } else {
277     return std::unique_ptr<Resource>(new Resource(GetDefaultOrEmpty()));
278   }
279 }
280
281 std::string ResourceManager::GetLocalizedPath(const std::string& origin) {
282   std::string file_scheme = std::string() + kSchemeTypeFile + "/";
283   std::string app_scheme = std::string() + kSchemeTypeApp;
284   std::string locale_path = "locales/";
285   auto find = locale_cache_.find(origin);
286   if (find != locale_cache_.end()) {
287     return find->second;
288   }
289   std::string& result = locale_cache_[origin];
290   std::string url = origin;
291
292   std::string suffix;
293   size_t pos = url.find_first_of("#?");
294   if (pos != std::string::npos) {
295     suffix = url.substr(pos);
296     url.resize(pos);
297   }
298
299   if (utils::StartsWith(url, app_scheme)) {
300     // remove "app://"
301     url.erase(0, app_scheme.length());
302
303     // remove app id + /
304     std::string check = appid_ + "/";
305     if (utils::StartsWith(url, check)) {
306       url.erase(0, check.length());
307     } else {
308       LOGGER(ERROR) << "Invalid appid";
309       return result;
310     }
311   } else if (utils::StartsWith(url, file_scheme)) {
312     // remove "file:///"
313     url.erase(0, file_scheme.length());
314   }
315
316   if (!url.empty() && url[url.length()-1] == '/') {
317       url.erase(url.length()-1, 1);
318   }
319
320   if (url.empty()) {
321     LOGGER(ERROR) << "URL Localization error";
322     return result;
323   }
324
325   for (auto& locales : locale_manager_->system_locales()) {
326     // check ../locales/
327     std::string app_locale_path = resource_base_path_ + locale_path;
328     if (!Exists(app_locale_path)) {
329       break;
330     }
331     std::string resource_path = app_locale_path + locales + "/" + url;
332     if (Exists(resource_path)) {
333       result = "file://" + resource_path + suffix;
334       return result;
335     }
336   }
337
338   std::string default_locale = resource_base_path_ + url;
339   if (Exists(default_locale)) {
340     result = "file://" + default_locale + suffix;
341     return result;
342   }
343   result = url + suffix;
344   return result;
345 }
346
347 void ResourceManager::set_base_resource_path(const std::string& path) {
348   if (path.empty()) {
349     return;
350   }
351
352   resource_base_path_ = path;
353   if (resource_base_path_[resource_base_path_.length()-1] != '/') {
354     resource_base_path_ += "/";
355   }
356 }
357
358 bool ResourceManager::Exists(const std::string& path) {
359   auto find = file_existed_cache_.find(path);
360   if (find != file_existed_cache_.end()) {
361     return find->second;
362   }
363   bool ret = file_existed_cache_[path] = utils::Exists(path);
364   return ret;
365 }
366
367 }  // namespace wrt