[Release] wrt_0.8.227
[platform/framework/web/wrt.git] / src / view / webkit / injected-bundle / wrt-injected-bundle.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  * @file    wrt-injected-bundle.cpp
18  * @author  Lukasz Wrzosek (l.wrzosek@samsung.com)
19  * @brief   Implementation file for injected bundle
20  */
21 #include "wrt-injected-bundle.h"
22
23 #include <WKBundle.h>
24 #include <WKBundleInitialize.h>
25 #include <WKBundlePage.h>
26 #include <WKBundleFrame.h>
27 #include <WKURLRequest.h>
28 #include <WKString.h>
29 #include <WKType.h>
30 #include <WKURL.h>
31 #include <WKError.h>
32 #include <WKURLResponseTizen.h>
33 #include <WKBundlePagePrivate.h>
34 #include <WKBundlePrivate.h>
35
36 #include <string>
37 #include <cstdio>
38 #include <sstream>
39 #include <set>
40 #include <memory>
41
42 #include <dpl/log/log.h>
43 #include <dpl/foreach.h>
44 #include <dpl/assert.h>
45 #include <dpl/wrt-dao-ro/WrtDatabase.h>
46 #include <dpl/localization/localization_utils.h>
47 #include <dpl/string.h>
48 #include <dpl/wrt-dao-ro/global_config.h>
49 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
50 #include <dpl/wrt-dao-ro/common_dao_types.h>
51 #include <dpl/localization/LanguageTagsProvider.h>
52 #include <dpl/event/main_event_dispatcher.h>
53
54 #include <wrt_plugin_module.h>
55 #include <profiling_util.h>
56
57 #include <appcore-efl.h>
58
59 #include <message_support.h>
60
61 #include <scheme.h>
62 #include <scheme_action_map_type.h>
63 #include <scheme_action_map_data.h>
64
65 #include <js_overlay_types.h>
66 #include <dispatch_event_support.h>
67 #include <plugins-ipc-message/ipc_message_support.h>
68
69 #include <sys/resource.h>
70 #include <privilege-control.h>
71
72 // URI localization on WebProcess side
73 #include "injected_bundle_uri_handling.h"
74 #include "injected_bundle_decryption_support.h"
75 #include "injected_bundle_viewmodes_support.h"
76
77 namespace {
78 const char * const SCHEME_HTTP = "http";
79 const char * const SCHEME_HTTPS = "https";
80 const char * const SCHEME_FILE = "file";
81 const char * const SCHEME_FILE_SLASH = "file://";
82 const char * const SCHEME_BOX_SLASH = "box://";
83 const char * const BLANK_PAGE_URL = "about:blank";
84 const char * const HTML_MIME = "text/html";
85 const char * const PHP_MIME = "application/x-php";
86 const std::size_t FILE_BUF_MAX_SIZE = 1024; // bytes
87 const std::size_t PLAIN_CHUNK_SIZE = 1008; // bytes
88 const unsigned int UID_ROOT = 0;
89 const unsigned int DEFAULT_PRIORITY = 0;
90 const char * const PRIVILEGE_APP_TYPE = "wgt";
91 #ifdef CORS_WHITELISTING_ENABLED
92 const char * const warpAllowProtocolsForWildcard[] = { "http", "https" };
93 #endif
94 }
95
96 Bundle::Bundle(WKBundleRef bundle) :
97     m_bundle(bundle),
98     m_scale(0),
99     m_encodedBundle(""),
100     m_theme(""),
101     m_willRemoveContext(NULL),
102     m_widgetType(WrtDB::APP_TYPE_UNKNOWN),
103     m_securityModelVersion(
104         WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1),
105     m_initialized(false),
106     m_decryptionSupport(new InjectedBundle::DecryptionSupport())
107 {
108     Try {
109         LOG_PROFILE_START("Bundle attachToThread");
110         WrtDB::WrtDatabase::attachToThreadRO();
111         LOG_PROFILE_STOP("Bundle attachToThread");
112     } Catch (DPL::DB::SqlConnection::Exception::Base) {
113         LogError("## Db attach was failed! Terminate WebProcess by force. ##");
114         exit(-1);
115     }
116
117 #ifdef MULTIPROCESS_SERVICE_SUPPORT_INLINE
118     sendWebProcessPid();
119 #endif
120 }
121
122 Bundle::~Bundle()
123 {
124     WrtDB::WrtDatabase::detachFromThread();
125
126     if (!m_pagesList.empty()) {
127         LogError("There are not closed pages!");
128     }
129     WKRelease(m_bundle);
130 }
131
132 void Bundle::didCreatePageCallback(
133     WKBundleRef /*bundle*/,
134     WKBundlePageRef page,
135     const void* clientInfo)
136 {
137     LOG_PROFILE_START("didCreatePageCallback");
138     LogDebug("didCreatePageCallback called");
139     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
140     This->didCreatePage(page);
141     LOG_PROFILE_STOP("didCreatePageCallback");
142 }
143
144 void Bundle::didReceiveMessageCallback(
145     WKBundleRef /*bundle*/,
146     WKStringRef messageName,
147     WKTypeRef messageBody,
148     const void *clientInfo)
149 {
150     LogDebug("didReceiveMessageCallback called");
151     Bundle* bundle = static_cast<Bundle*>(const_cast<void*>(clientInfo));
152     bundle->didReceiveMessage(messageName, messageBody);
153 }
154
155 void Bundle::willDestroyPageCallback(
156     WKBundleRef /*bundle*/,
157     WKBundlePageRef page,
158     const void* clientInfo)
159 {
160     LogDebug("willDestroyPageCallback called");
161     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
162     This->willDestroyPage(page);
163 }
164
165 void Bundle::didCreatePage(WKBundlePageRef page)
166 {
167     if (!m_initialized)
168     {
169         LogError("## Injected-bundle was not initialized! Terminate WebProcess by force. ##");
170         exit(-1);
171     }
172
173     auto mainFrame = WKBundlePageGetMainFrame(page);
174     auto context = WKBundleFrameGetJavaScriptContext(mainFrame);
175     m_pagesList.push_back(page);
176     m_pageGlobalContext.insertContextForPage(page, context);
177     LogDebug("created Page : " << page << " created JSContext : " << context);
178     m_viewmodesSupport->initialize(page);
179
180     WKBundlePageResourceLoadClient resourceLoadClient = {
181         kWKBundlePageResourceLoadClientCurrentVersion,  /* version */
182         this, /* clientinfo */
183         0, /* didInitiateLoadForResource */
184         willSendRequestForFrameCallback, /* willSendRequestForFrame */
185         0, /* didReceiveResponseForResource */
186         0, /* didReceiveContentLengthForResource */
187         0, /* didFinishLoadForResource */
188         0, /* didFailLoadForResource */
189         0, /* shouldCacheResponse */
190         0, /* shouldUseCredentialStorage */
191     };
192     WKBundlePageSetResourceLoadClient(page, &resourceLoadClient);
193
194     WKBundlePageLoaderClient loaderClient = {
195         kWKBundlePageLoaderClientCurrentVersion,
196         this, /* clientinfo */
197         didStartProvisionalLoadForFrameCallback, /* didStartProvisionalLoadForFrame */
198         0, /* didReceiveServerRedirectForProvisionalLoadForFrame */
199         0, /* didFailProvisionalLoadWithErrorForFrame */
200         didCommitLoadForFrameCallback, /* didCommitLoadForFrame */
201         0, /* didFinishDocumentLoadForFrame */
202         0, /* didFinishLoadForFrame */
203         0, /* didFailLoadWithErrorForFrame */
204         0, /* didSameDocumentNavigationForFrame */
205         0, /* didReceiveTitleForFrame */
206         0, /* didFirstLayoutForFrame */
207         0, /* didFirstVisuallyNonEmptyLayoutForFrame */
208         didRemoveFrameFromHierarchyCallback, /* didRemoveFrameFromHierarchy */
209         0, /* didDisplayInsecureContentForFrame */
210         0, /* didRunInsecureContentForFrame */
211         0, /* didClearWindowObjectForFrame */
212         0, /* didCancelClientRedirectForFrame */
213         0, /* willPerformClientRedirectForFrame */
214         0, /* didHandleOnloadEventsForFrame */
215         0, /* didLayoutForFrame */
216         0, /* didNewFirstVisuallyNonEmptyLayout */
217         0, /* didDetectXSSForFrame */
218         0, /* shouldGoToBackForwardListItem */
219         0, /* globalObjectIsAvailableForFrame */
220         0, /* willDisconnectDOMWindowExtensionFromGlobalObject */
221         0, /* didReconnectDOMWindowExtensionToGlobalObject */
222         0, /* willDestroyGlobalObjectForDOMWindowExtension */
223         0, /* didFinishProgress */
224         0, /* shouldForceUniversalAccessFromLocalURL */
225         0, /* didReceiveIntentForFrame */
226         0, /* registerIntentServiceForFrame */
227     };
228     WKBundlePageSetPageLoaderClient(page, &loaderClient);
229
230
231     WKBundlePagePolicyClient policyClient = {
232         kWKBundlePagePolicyClientCurrentVersion, /* version */
233         this,                                    /* clientInfo */
234         decidePolicyForNavigationActionCallback, /* decidePolicyForNavigationAction */
235         decidePolicyForNewWindowActionCallback,  /* decidePolicyForNavigationAction */
236         decidePolicyForResponseCallback,         /* decidePolicyForResponse */
237         0,                                       /* unableToImplementPolicy */
238     };
239     WKBundlePageSetPolicyClient(page, &policyClient);
240 }
241
242 void Bundle::willDestroyPage(WKBundlePageRef page)
243 {
244     LogDebug("Destroyed page : " << page);
245
246     auto context = m_pageGlobalContext.getContextForPage(page);
247     m_pagesList.remove(page);
248     m_pageGlobalContext.removeContextForPage(page);
249     m_pageContext[page].erase(context);
250     m_viewmodesSupport->deinitialize(page);
251
252     PluginModule::unloadFrame(context);
253     PluginModule::stop(context);
254 }
255
256 void Bundle::fixWKMessageArgs(std::string & argScale,
257                               std::string & argEncodedBundle,
258                               std::string & argTheme)
259 {
260     if (argScale != "null" && argScale[0] == '_') {
261         argScale.erase(0, 1);
262
263         std::stringstream ssScale(argScale);
264         ssScale >> m_scale;
265     }
266
267     if (argEncodedBundle != "null" && argEncodedBundle[0] == '_') {
268         argEncodedBundle.erase(0, 1);
269
270         m_encodedBundle = argEncodedBundle;
271     }
272
273     if (argTheme != "null" && argTheme[0] == '_') {
274         argTheme.erase(0, 1);
275
276         m_theme = argTheme;
277     }
278 }
279
280 #ifdef CORS_WHITELISTING_ENABLED
281 void Bundle::bypassCORSforWARPAccessList(WrtDB::WidgetDAOReadOnly & dao)
282 {
283     // bypassing CORS using origin whitelist
284     WrtDB::WidgetAccessInfoList WAList;
285     dao.getWidgetAccessInfo(WAList);
286     FOREACH(it, WAList)
287     {
288         const WrtDB::WidgetAccessInfo & access = *it;
289         WKURLRef url = WKURLCreateWithUTF8CString(DPL::ToUTF8String(access.strIRI).c_str());
290
291 #ifdef APP_SCHEME_ENABLED
292         std::string source = std::string("app://") + DPL::ToUTF8String(m_widgetTizenId) + "/";
293 #else
294         std::string source = DPL::ToUTF8String(dao.getFullPath());
295 #endif
296
297         LogDebug("WARP to WK whitelist position: " << source << " for "
298             << access.strIRI << " subDomains: " << access.bSubDomains);
299
300         WKStringRef wkSource = WKStringCreateWithUTF8CString(source.c_str());
301         WKStringRef wkHost;
302         WKStringRef wkProtocol;
303         if(access.strIRI == L"*")
304         {
305             //wildcard force to explicitly say which protocol is used
306             // passed wkHost if empty means wildcard -> allow everything but protocol has to be set.
307             for(unsigned i = 0; i < sizeof(warpAllowProtocolsForWildcard) / sizeof(char*); i++)
308             {
309                 wkHost = WKStringCreateWithUTF8CString("");
310                 wkProtocol = WKStringCreateWithUTF8CString(warpAllowProtocolsForWildcard[i]);
311                 WKBundleAddOriginAccessWhitelistEntry(m_bundle,
312                     wkSource, wkProtocol, wkHost, access.bSubDomains);
313             }
314         }
315         else
316         {
317             wkHost = WKURLCopyHostName(url);
318             wkProtocol = WKURLCopyScheme(url);
319             WKBundleAddOriginAccessWhitelistEntry(m_bundle,
320                 wkSource, wkProtocol, wkHost, access.bSubDomains);
321         }
322
323         WKRelease(wkHost);
324         WKRelease(wkProtocol);
325         WKRelease(wkSource);
326     }
327 }
328 #endif
329
330 void Bundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody)
331 {
332     LogDebug("got message type: " << toString(messageName).c_str());
333     if (WKStringIsEqualToUTF8CString(messageName,
334                                      Message::ToInjectedBundle::START))
335     {
336         if (!messageBody || WKStringGetTypeID() != WKGetTypeID(messageBody)) {
337             LogError("Wrong message format received, ignoring");
338             return;
339         }
340
341         std::string msgString =
342             toString(static_cast<WKStringRef>(messageBody));
343         LogDebug("Got message text: " << msgString);
344         LogDebug("loading Page : " << m_pagesList.back() <<
345                  " loading JSContext : " <<
346                  m_pageGlobalContext.getContextForPage(m_pagesList.back()));
347         // set information from ui process
348         std::stringstream ssMsg(msgString);
349         std::string argScale;
350         std::string argEncodedBundle;
351         std::string argTheme;
352
353         std::string id;
354         ssMsg >> id;
355         m_widgetTizenId = DPL::FromASCIIString(id);
356
357         ssMsg >> argScale;
358         ssMsg >> argEncodedBundle;
359         ssMsg >> argTheme;
360
361         // ** Language tags setting completed **
362         fixWKMessageArgs(argScale, argEncodedBundle, argTheme);
363     } else if (WKStringIsEqualToUTF8CString(messageName,
364                                             Message::ToInjectedBundle::SHUTDOWN))
365     {
366         LogDebug("shutdown plugins");
367
368         if (m_pagesList.empty()) {
369             PluginModule::shutdown();
370         } else {
371             LogInfo(
372                 "PluginModule shutdown ignored, there are still alive pages!");
373         }
374     }
375     else if (WKStringIsEqualToUTF8CString(messageName,
376                                           Message::ToInjectedBundle::SET_CUSTOM_PROPERTIES))
377     {
378         LogDebug("reset custom properties of window objects");
379         // set information from ui process
380         std::string msgString =
381             toString(static_cast<WKStringRef>(messageBody));
382
383         std::string argScale;
384         std::string argEncodedBundle;
385         std::string argTheme;
386
387         std::stringstream ssMsg(msgString);
388         ssMsg >> argScale;
389         ssMsg >> argEncodedBundle;
390         ssMsg >> argTheme;
391
392         fixWKMessageArgs(argScale, argEncodedBundle, argTheme);
393
394         //apply for each context
395         PageGlobalContextContainer::const_iterator it = m_pageGlobalContext.begin();
396         for (; it != m_pageGlobalContext.end(); ++it) {
397             PluginModule::setCustomProperties(it->second,
398                                               m_scale,
399                                               m_encodedBundle.c_str(),
400                                               m_theme.c_str());
401         }
402     } else if (WKStringIsEqualToUTF8CString(
403                    messageName,
404                    Message::ToInjectedBundle::DISPATCH_JS_EVENT))
405     {
406         LogDebug("dispatch javascript event to created frames");
407         using namespace WrtPlugins::W3C;
408
409         // set information from ui process
410         std::string text = toString(static_cast<WKStringRef>(messageBody));
411         int eventType;
412         SoftKeyboardChangeArgs softKeyboardArgs;
413
414         std::stringstream ss(text);
415         ss >> eventType;
416
417         if (eventType == SoftKeyboardChangeCustomEvent)
418         {
419             ss >> softKeyboardArgs.state;
420             ss >> softKeyboardArgs.width;
421             ss >> softKeyboardArgs.height;
422         }
423
424         //apply for each context
425         PageGlobalContextContainer::const_iterator it = m_pageGlobalContext.begin();
426
427         for (; it != m_pageGlobalContext.end(); ++it)
428         {
429             if (eventType == SoftKeyboardChangeCustomEvent)
430             {
431                 DispatchEventSupport::dispatchSoftKeyboardChangeEvent(it->second,
432                                                     softKeyboardArgs.state,
433                                                     softKeyboardArgs.width,
434                                                     softKeyboardArgs.height);
435             }
436         }
437     } else if (WKStringIsEqualToUTF8CString(
438                    messageName,
439                    Message::ToInjectedBundle::INIT))
440     {
441         LogDebug("initialize");
442
443         if (!m_initialized) {
444             std::string msgString = toString(static_cast<WKStringRef>(messageBody));
445             m_widgetTizenId = DPL::FromASCIIString(msgString);
446             WrtDB::WidgetDAOReadOnly dao(m_widgetTizenId);
447
448             // process pool - set app_privilige
449             if (UID_ROOT == getuid()) {
450                 using namespace WrtDB::GlobalConfig;
451
452                 std::string appPath;
453                 std::string tzAppId = DPL::ToUTF8String(dao.getTzAppId());
454                 std::string tzPkgId = DPL::ToUTF8String(dao.getTizenPkgId());
455                 DPL::OptionalString installedPath = dao.getWidgetInstalledPath();
456                 if (installedPath.IsNull()) {
457                     appPath = std::string(GetUserInstalledWidgetPath()) + "/" +
458                         tzPkgId + GetUserWidgetExecPath() + "/" + tzAppId;
459                 } else {
460                     appPath = DPL::ToUTF8String(*installedPath) +
461                         GetUserWidgetExecPath() + "/" + tzAppId;
462                 }
463
464                 LogDebug("set_app_privilege(" << appPath << ")");
465                 set_app_privilege(tzPkgId.c_str(), PRIVILEGE_APP_TYPE, appPath.c_str());
466             }
467
468             /* This type of message is received when widget is restarting
469              * (proably in other situation too). Widget restart can be
470              * called after system language change so language tags have to
471              * be recreated here.
472              * Do NOT MOVE LanguageTags reset before m_widgetHandle initialization
473              */
474             // reset language tags (create new tags based on system locales)
475             LanguageTagsProviderSingleton::Instance().resetLanguageTags();
476             DPL::OptionalString defaultLocale = dao.getDefaultlocale();
477             if (!defaultLocale.IsNull()) {
478                 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
479                     *defaultLocale);
480             }
481             LanguageTags tags =
482                 LanguageTagsProviderSingleton::Instance().getLanguageTags();
483             LogDebug("Current widget locales (language tags):");
484             FOREACH(it, tags) {
485                 LogDebug("Locale: " << *it);
486             }
487
488             m_widgetType = dao.getWidgetType();
489             LogDebug("m_widgetType : " << m_widgetType.getApptypeToString() <<
490                      "(m_widgetTizenId:" << m_widgetTizenId << ")");
491
492             LogDebug("Preload PluginLogicSingleton");
493             PluginModule::init(WrtDB::WidgetDAOReadOnly::getHandle(m_widgetTizenId));
494             LogDebug("Preload PluginLogicSingleton_end");
495
496             m_securityModelVersion = dao.getSecurityModelVersion();
497 #ifdef CORS_WHITELISTING_ENABLED
498             bypassCORSforWARPAccessList(dao);
499 #endif
500             m_decryptionSupport->initialize(m_widgetTizenId);
501             m_viewmodesSupport.reset(
502                 new InjectedBundle::ViewmodesSupport(m_widgetTizenId));
503             m_initialized = true;
504         } else {
505             LogDebug("already initalized");
506         }
507     } else if (WKStringIsEqualToUTF8CString(
508                    messageName,
509                    Message::ToInjectedBundle::SET_XWINDOW_HANDLE))
510     {
511             std::string msgString =
512                 toString(static_cast<WKStringRef>(messageBody));
513             LogDebug("set x window handle [" << msgString << "]");
514             IPCMessageSupport::setXwindowHandle(atoi(msgString.c_str()));
515     } else if (WKStringIsEqualToUTF8CString(
516                    messageName,
517                    Message::ToInjectedBundle::SET_VIEWMODES))
518     {
519         std::string msgBody =
520             toString(static_cast<WKStringRef>(messageBody));
521         LogDebug("set viewmode to [" << msgBody << "]");
522         if (msgBody == Message::ToInjectedBundle::SET_VIEWMODES_MSGBODY_EXIT) {
523             m_viewmodesSupport->exitViewmodesAllPages();
524         } else {
525             m_viewmodesSupport->enterViewmodesAllPages(msgBody);
526         }
527     }
528 }
529
530 WKURLRequestRef Bundle::willSendRequestForFrameCallback(
531     WKBundlePageRef /*page*/,
532     WKBundleFrameRef /*frame*/,
533     uint64_t /*resourceIdentifier*/,
534     WKURLRequestRef request,
535     WKURLResponseRef /*response*/,
536     const void *clientInfo)
537 {
538     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
539     WKURLRequestRef ret = This->willSendRequestForFrame(request);
540
541     return ret;
542 }
543
544 void Bundle::didStartProvisionalLoadForFrameCallback(
545     WKBundlePageRef page,
546     WKBundleFrameRef frame,
547     WKTypeRef* /*userData*/,
548     const void *clientInfo)
549 {
550     LogDebug("didStartProvisionalLoadForFrameCallback called");
551     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
552
553     if (This->m_pageGlobalContext.find(page) == This->m_pageGlobalContext.end()) {
554         return;
555     }
556     if (This->m_pageContext.count(page) == 0) {
557         return;
558     }
559
560     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
561
562     ContextSet::iterator i = This->m_pageContext[page].find(context);
563
564     if (i == This->m_pageContext[page].end()) {
565         LogDebug("Initially attached frame");
566         return;
567     }
568
569     This->m_pageContext[page].erase(i);
570     This->m_willRemoveContext = context;
571 }
572
573 void Bundle::didRemoveFrameFromHierarchyCallback(
574     WKBundlePageRef page,
575     WKBundleFrameRef frame,
576     WKTypeRef* /*userData*/,
577     const void *clientInfo)
578 {
579     LogDebug("didRemoveFrameFromHierarchyCallback called");
580     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
581
582     if (This->m_pageContext.count(page) == 0) {
583         LogDebug("his->m_pageContext.count(page) == 0");
584         return;
585     }
586
587     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
588
589     ContextSet::iterator i = This->m_pageContext[page].find(context);
590
591     if (i == This->m_pageContext[page].end()) {
592         LogWarning("Tried to unload frame which has never been loaded");
593         return;
594     }
595
596     This->m_pageContext[page].erase(i);
597
598     PluginModule::unloadFrame(context);
599 }
600
601 void Bundle::didFinishLoadForResourceCallback(
602     WKBundlePageRef /*page*/,
603     WKBundleFrameRef /*frame*/,
604     uint64_t /*resourceIdentifier*/,
605     const void* /*clientInfo*/)
606 {
607     LogDebug("didFinishLoadForResourceCallback called");
608 }
609
610 void Bundle::didCommitLoadForFrameCallback(
611     WKBundlePageRef page,
612     WKBundleFrameRef frame,
613     WKTypeRef* /*userData*/,
614     const void *clientInfo)
615 {
616     LogInfo("didCommitLoadForFrameCallback called");
617     LOG_PROFILE_START("didCommitLoadForFrameCallback");
618     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
619
620     WKURLRef url = WKBundleFrameCopyURL(frame);
621
622     if (url == NULL) {
623         LogInfo("url is NULL");
624         return;
625     }
626
627     if (This->m_willRemoveContext) {
628         PluginModule::unloadFrame(This->m_willRemoveContext);
629         This->m_willRemoveContext = NULL;
630     }
631
632     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
633
634     This->m_pageContext[page].insert(context);
635
636     if (!WKBundleFrameIsMainFrame(frame)) {
637         LogInfo("frame isn't main frame");
638         PluginModule::start(
639             WrtDB::WidgetDAOReadOnly::getHandle(This->m_widgetTizenId),
640             context,
641             This->m_scale,
642             This->m_encodedBundle.c_str(),
643             This->m_theme.c_str());
644         PluginModule::loadFrame(context);
645         return;
646     }
647
648     std::string urlStr = toString(url);
649     if (InjectedBundleURIHandling::processURIForPlugin(urlStr.c_str())) {
650         LogDebug("start plugin");
651         if(This->m_pageGlobalContext.find(page) != This->m_pageGlobalContext.end())
652         {
653             LogDebug("Previous context: " << This->m_pageGlobalContext.getContextForPage(page));
654             PluginModule::stop(This->m_pageGlobalContext.getContextForPage(page));
655         }
656         LogDebug("New context: " << context);
657         //note that since we need old context for unloading plugins it must be sotred
658         //custom container take care of increamenting and decrementing references
659         This->m_pageGlobalContext.insertContextForPage(page, context);
660         LOG_PROFILE_START("PluginModule start");
661         PluginModule::start(
662             WrtDB::WidgetDAOReadOnly::getHandle(This->m_widgetTizenId),
663             context,
664             This->m_scale,
665             This->m_encodedBundle.c_str(),
666             This->m_theme.c_str() );
667         LOG_PROFILE_STOP("PluginModule start");
668
669         PluginModule::loadFrame(context);
670     } else {
671         LogDebug("stop plugin");
672         if(This->m_pageGlobalContext.find(page) != This->m_pageGlobalContext.end())
673         {
674             LogDebug("Previous context: " << This->m_pageGlobalContext.getContextForPage(page));
675             PluginModule::stop(This->m_pageGlobalContext.getContextForPage(page));
676         }
677         LogDebug("New context: " << context);
678         This->m_pageGlobalContext.insertContextForPage(page, context);
679     }
680     LOG_PROFILE_STOP("didCommitLoadForFrameCallback");
681 }
682
683 WKBundlePagePolicyAction Bundle::decidePolicyForNavigationActionCallback(
684     WKBundlePageRef page,
685     WKBundleFrameRef frame,
686     WKBundleNavigationActionRef navigationAction,
687     WKURLRequestRef request,
688     WKTypeRef* userData,
689     const void* clientInfo)
690 {
691     LogDebug("decidePolicyForNavigationActionCallback called");
692
693     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
694     return This->decidePolicyForAction(false,
695                                        page,
696                                        frame,
697                                        navigationAction,
698                                        request,
699                                        userData);
700 }
701
702 WKBundlePagePolicyAction Bundle::decidePolicyForNewWindowActionCallback(
703     WKBundlePageRef page,
704     WKBundleFrameRef frame,
705     WKBundleNavigationActionRef navigationAction,
706     WKURLRequestRef request,
707     WKStringRef /*frameName*/,
708     WKTypeRef* userData,
709     const void* clientInfo)
710 {
711     LogDebug("decidePolicyForNewWindowActionCallback called");
712
713     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
714     return This->decidePolicyForAction(true,
715                                        page,
716                                        frame,
717                                        navigationAction,
718                                        request,
719                                        userData);
720 }
721
722 WKBundlePagePolicyAction Bundle::decidePolicyForResponseCallback(
723     WKBundlePageRef /* page */,
724     WKBundleFrameRef /* frame */,
725     WKURLResponseRef response,
726     WKURLRequestRef /* request */,
727     WKTypeRef*          /* userData */,
728     const void*         /* clientInfo */)
729 {
730     LogDebug("decidePolicyForResponseCallback called");
731
732     Assert(response);
733     WKStringRef contentTypeRef = WKURLResponseEflCopyContentType(response);
734
735     std::string contentType = toString(contentTypeRef);
736     LogDebug("contentTypeRef : " << contentType);
737     WKRelease(contentTypeRef);
738
739     if (contentType == HTML_MIME) {
740         LogDebug("Accepting HTML_MIME type");
741         return WKBundlePagePolicyActionUse;
742     }
743     if (contentType == PHP_MIME) {
744         LogDebug("Accepting php type");
745         return WKBundlePagePolicyActionUse;
746     }
747
748     return WKBundlePagePolicyActionPassThrough;
749 }
750
751 WKURLRequestRef Bundle::willSendRequestForFrame(WKURLRequestRef request)
752 {
753     static bool logEnable = (getenv("WRT_WILL_SEND_REQUEST_LOG_ENABLE") != NULL);
754
755     WKURLRef    wkUrl   = WKURLRequestCopyURL(request);
756     WKStringRef wkStr   = WKURLCopyString(wkUrl);
757
758     std::string stdUrl  = Bundle::toString(wkStr);
759     std::string localizedUrl;
760
761     WKRelease(wkStr);
762     WKRelease(wkUrl);
763
764     if (logEnable){ LogDebug("willSendRequestForFrame : " << stdUrl); }
765
766     localizedUrl = InjectedBundleURIHandling::localizeURI(stdUrl, DPL::ToUTF8String(m_widgetTizenId));
767     bool ret = InjectedBundleURIHandling::processURI(localizedUrl, m_widgetTizenId, m_securityModelVersion);
768
769     if (!ret)
770     {
771         LogDebug("Not permitted resource: " << localizedUrl);
772         return NULL;
773     }
774
775     // log disabled for performance
776     //LogDebug("URI processing result: " << result);
777     std::string scheme = localizedUrl.substr(0, localizedUrl.find_first_of(':'));
778
779 #ifdef APP_SCHEME_ENABLED
780     if (scheme == SCHEME_FILE)
781     {
782         LogError("File schema blocked for: " << stdUrl);
783         return NULL;
784     }
785 #endif
786
787     // Return value must contain details information of input
788     // WKURLRequestRef. Current webkit2 doesn't support api that
789     // copy WKURLRequestRef or change url only. Before webkit2
790     // support api, callback return original WKURLRequestRef in the
791     // case of external scheme
792
793     // external scheme also need to send message to UI process for
794     // checking roaming and security
795
796     if (scheme == SCHEME_HTTP || scheme == SCHEME_HTTPS)
797     {
798         if (logEnable){ LogDebug("external scheme return original WKURLRequestRef"); }
799         WKRetain(request);
800
801         return request;
802     }
803     else
804     {
805         std::string checkUrl = localizedUrl;
806
807         if (m_decryptionSupport->isNeedDecryption(checkUrl))
808         {
809             std::string decryptString =
810                 m_decryptionSupport->decryptResource(checkUrl);
811
812             if (logEnable){ LogDebug("return value : " << decryptString ); }
813
814             WKURLRef destUrl =
815                 WKURLCreateWithUTF8CString(decryptString.c_str());
816             WKURLRequestRef req = WKURLRequestCreateWithWKURL(destUrl);
817             WKRelease(destUrl);
818
819             return req;
820         }
821     }
822
823     WKURLRef newUrl = WKURLCreateWithUTF8CString(localizedUrl.c_str());
824     WKURLRequestRef req = WKURLRequestCreateWithWKURL(newUrl);
825     WKRelease(newUrl);
826
827     if (logEnable){ LogDebug("return value : " << localizedUrl); }
828
829     return req;
830 }
831
832 WKBundlePagePolicyAction Bundle::decidePolicyForAction(
833     bool isNewWindow,
834     WKBundlePageRef /* page */,
835     WKBundleFrameRef frame,
836     WKBundleNavigationActionRef /* navigationAction */,
837     WKURLRequestRef request,
838     WKTypeRef* /* userData */)
839 {
840     using namespace ViewModule;
841     using namespace ViewModule::SchemeActionMap;
842
843     char const * const TIZEN_SCHEME = "tizen";
844
845     std::string request_uri = toString(request);
846
847     LogInfo("Uri being checked: " << request_uri);
848
849     // exception uri
850     if (request_uri == BLANK_PAGE_URL) {
851         return WKBundlePagePolicyActionUse;
852     }
853
854     // in case of box scheme, unconditionally PassThrough should be returned
855     if (!request_uri.compare(0, 6, SCHEME_BOX_SLASH)) {
856         return WKBundlePagePolicyActionPassThrough;
857     }
858
859     DPL::String dplUrl = DPL::FromUTF8String(request_uri);
860     bool ret =
861         InjectedBundleURIHandling::processMainResource(dplUrl,
862                                                        m_widgetTizenId,
863                                                        m_securityModelVersion);
864     if (!ret) {
865         std::string blockedUrl = DPL::ToUTF8String(dplUrl);
866         LogDebug("URI is blocked: " << blockedUrl);
867
868         // Send information about blocked URI to UIProcess
869         WKStringRef urlStr = WKStringCreateWithUTF8CString(blockedUrl.c_str());
870         WKStringRef blockMessage =
871             WKStringCreateWithUTF8CString(Message::ToUIProcess::BLOCKED_URL);
872         WKBundlePostMessage(m_bundle, blockMessage, urlStr);
873         WKRelease(urlStr);
874         WKRelease(blockMessage);
875         return WKBundlePagePolicyActionPassThrough;
876     }
877
878     // get scheme string
879     std::string request_scheme = getScheme(request_uri);
880
881     // is tizen schem?
882     if (request_scheme == TIZEN_SCHEME) {
883         return WKBundlePagePolicyActionPassThrough;
884     }
885
886     // scheme action
887     Scheme scheme(request_scheme);
888     LogDebug("Scheme: " << request_scheme);
889
890     Scheme::Type type = scheme.GetType();
891     if (type < Scheme::FILE || type >= Scheme::COUNT) {
892         LogError("Invalid scheme: " << request_scheme);
893         return WKBundlePagePolicyActionPassThrough;
894     }
895
896     bool mainFrame = WKBundleFrameIsMainFrame(frame);
897     NavigationContext ctx = mainFrame ? TOP_LEVEL : FRAME_LEVEL;
898     if (isNewWindow) {
899         ctx = NEW_WINDOW;
900     }
901
902     LogDebug("Scheme type: " << type);
903     LogDebug("Navigation context: " << ctx);
904     LogDebug("Application type: " << m_widgetType.getApptypeToString());
905
906     UriAction action;
907
908     if (m_widgetType == WrtDB::APP_TYPE_TIZENWEBAPP) {
909         action = g_tizenActionMap[type][ctx];
910     } else {
911         LogError("Unsupported application type: " << type);
912         return WKBundlePagePolicyActionPassThrough;
913     }
914
915     LogDebug("Uri action: " << action);
916
917     if (action != URI_ACTION_WRT) {
918         return WKBundlePagePolicyActionPassThrough;
919     }
920
921     return WKBundlePagePolicyActionUse;
922 }
923
924 std::string Bundle::toString(WKStringRef str)
925 {
926     if (WKStringIsEmpty(str))
927     {
928         return "";
929     }
930     else
931     {
932         size_t size = WKStringGetMaximumUTF8CStringSize(str);
933
934         char buffer[size + 1];
935         WKStringGetUTF8CString(str, buffer, sizeof(buffer));
936
937         return buffer;
938     }
939 }
940
941 std::string Bundle::toString(WKURLRef url)
942 {
943     WKStringRef urlStr = WKURLCopyString(url);
944     std::string str = toString(urlStr);
945     WKRelease(urlStr);
946     return str;
947 }
948
949 std::string Bundle::toString(WKURLRequestRef req)
950 {
951     WKURLRef reqUrl = WKURLRequestCopyURL(req);
952     std::string str = toString(reqUrl);
953     WKRelease(reqUrl);
954     return str;
955 }
956
957 std::string Bundle::toString(WKErrorRef err)
958 {
959     WKStringRef domErr = WKErrorCopyDomain(err);
960     WKStringRef desc = WKErrorCopyLocalizedDescription(err);
961     std::string str = toString(domErr) + "\n" + toString(desc);
962     WKRelease(domErr);
963     WKRelease(desc);
964     return str;
965 }
966
967 std::string Bundle::getScheme(std::string uri)
968 {
969     std::size_t found = uri.find(':');
970     std::string str;
971
972     if (found != std::string::npos) {
973         str = uri.substr(0, found);
974     }
975
976     return str;
977 }
978
979 #ifdef MULTIPROCESS_SERVICE_SUPPORT_INLINE
980 void Bundle::sendWebProcessPid()
981 {
982     std::stringstream strPid;
983     strPid << getpid();
984     WKStringRef pidStr = WKStringCreateWithUTF8CString(strPid.str().c_str());
985     WKStringRef message =
986         WKStringCreateWithUTF8CString(
987             Message::ToUIProcess::SEND_WEBPROCESS_PID);
988     WKBundlePostMessage(m_bundle, message, pidStr);
989     WKRelease(pidStr);
990     WKRelease(message);
991 }
992 #endif
993
994 extern "C"
995 {
996 WK_EXPORT
997 void WKBundleInitialize(WKBundleRef bundle,
998                         WKTypeRef)
999 {
1000     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT-BUNDLE");
1001     LogDebug("Bundle initialized");
1002
1003     DPL::Event::GetMainEventDispatcherInstance().ResetCrossEventCallHandler();
1004     LogDebug("ResetCrossEventCallHandler()");
1005
1006     static Bundle s_bundle(bundle);
1007
1008     WKBundleClient client = {
1009         kWKBundleClientCurrentVersion,
1010         &s_bundle,
1011         &Bundle::didCreatePageCallback,
1012         &Bundle::willDestroyPageCallback,
1013         0,     /* didInitializePageGroup */
1014         &Bundle::didReceiveMessageCallback
1015     };
1016     WKBundleSetClient(bundle, &client);
1017
1018     // process pool - restore process priority
1019     if (UID_ROOT == getuid())
1020     {
1021         setpriority(PRIO_PROCESS, 0, DEFAULT_PRIORITY);
1022     }
1023     IPCMessageSupport::setWKBundleRef(bundle);
1024 }
1025 }