[Release] wrt_0.8.191
[platform/framework/web/wrt.git] / src / view / webkit / bundles / wrt-wk2-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-wk2-bundle.cpp
18  * @author  Lukasz Wrzosek (l.wrzosek@samsung.com)
19  * @brief   Implementation file for view logic for Webkit2
20  */
21 #include "wrt-wk2-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 <sys/stat.h>
40 #include <set>
41 #include <openssl/sha.h>
42 #include <openssl/hmac.h>
43 #include <openssl/evp.h>
44 #include <openssl/bio.h>
45 #include <openssl/buffer.h>
46
47 #include <dpl/log/log.h>
48 #include <dpl/foreach.h>
49 #include <dpl/assert.h>
50 #include <dpl/wrt-dao-ro/WrtDatabase.h>
51 #include <dpl/localization/localization_utils.h>
52 #include <dpl/string.h>
53 #include <dpl/wrt-dao-ro/global_config.h>
54 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
55 #include <dpl/wrt-dao-ro/common_dao_types.h>
56 #include <dpl/utils/mime_type_utils.h>
57 #include <dpl/localization/LanguageTagsProvider.h>
58 #include <dpl/event/main_event_dispatcher.h>
59 #include <FBaseByteBuffer.h>
60 #include <security/FSecCrypto_TrustZoneService.h>
61
62 #include <wrt_plugin_module.h>
63 #include <profiling_util.h>
64
65 #include <vconf.h>
66 #include <appcore-efl.h>
67
68 #include "messages_names.h"
69
70 #include <scheme.h>
71 #include <scheme_action_map_type.h>
72 #include <scheme_action_map_data.h>
73
74 #include <js_overlay_types.h>
75
76 #include <sys/time.h>
77 #include <sys/resource.h>
78 #include <privilege-control.h>
79
80 // URI localization on WebProcess side
81 #include "bundle_uri_handling.h"
82 extern "C" {
83 void InitWebAppInfo(const char* appId, const char* rootPath);
84 }
85
86 namespace {
87 const char * const uriChangedMessageName = "uri_changed_msg";
88 const char * const uriBlockedMessageName = "uri_blocked_msg";
89 #ifdef MULTIPROCESS_SERVICE_SUPPORT_INLINE
90 const char * const webProcessPidMessageName = "web_process_pid_msg";
91 #endif
92 const char * const URICHANGE_PLUGIN_STOP_ONLY = "plugin_stop_only";
93 const char * const URICHANGE_PLUGIN_RESTART = "plugin_restart";
94 const char * const URICHANGE_PLUGIN_NO_CHANGE = "plugin_no_change";
95 const char * const URICHANGE_BLOCKED_URL = "null";
96 const char * const SCHEME_HTTP = "http";
97 const char * const SCHEME_HTTPS = "https";
98 const char * const SCHEME_FILE = "file";
99 const char * const SCHEME_FILE_SLASH = "file://";
100 const char * const SCHEME_BOX_SLASH = "box://";
101 const char * const DATA_STRING = "data:";
102 const char * const BASE64_STRING = ";base64,";
103 const char * const BLANK_PAGE_URL = "about:blank";
104 const char * const HTML_MIME = "text/html";
105 const char * const PHP_MIME = "application/x-php";
106 const char * const VIEWMODE_TYPE_FULLSCREEN = "fullscreen";
107 const char * const VIEWMODE_TYPE_MAXIMIZED = "maximized";
108 const std::size_t FILE_BUF_MAX_SIZE = 1024; // bytes
109 const std::size_t PLAIN_CHUNK_SIZE = 1008; // bytes
110 const unsigned int UID_ROOT = 0;
111 const unsigned int DEFAULT_PRIORITY = 0;
112 const char * const PRIVILEGE_APP_TYPE = "wgt";
113 #ifdef CORS_WHITELISTING_ENABLED
114 const char * const warpAllowProtocolsForWildcard[] = { "http", "https" };
115 #endif
116
117 static bool m_initWebApp = false;
118
119 Tizen::Base::ByteBuffer *DecryptChunkByTrustZone(
120         Tizen::Base::ByteBuffer *appInfo,
121         const unsigned char *inBuffer,
122         int inBufSize)
123 {
124     using namespace Tizen::Base;
125
126     if (!m_initWebApp) {
127         char* pAppId = null;
128         pAppId = (char*)calloc(appInfo->GetRemaining()+1, 1);
129         memcpy(pAppId, appInfo->GetPointer(), appInfo->GetRemaining());
130
131         InitWebAppInfo(pAppId, "");
132         free (pAppId);
133         m_initWebApp = true;
134     }
135
136     Tizen::Security::Crypto::_TrustZoneService* pInstance;
137     pInstance = Tizen::Security::Crypto::_TrustZoneService::GetInstance();
138
139     ByteBuffer pBuf;
140     pBuf.Construct(inBufSize);
141     const byte *pByte = reinterpret_cast<const byte*>(inBuffer);
142
143     if (pBuf.SetArray(pByte, 0, inBufSize) != E_SUCCESS) {
144         LogDebug("Couldnot set pBuf");
145         return NULL;
146     }
147
148     pBuf.Flip();
149
150     return pInstance->_TrustZoneService::DecryptN(*appInfo, pBuf);
151 }
152
153 }
154
155 Bundle::Bundle(WKBundleRef bundle) :
156     m_bundle(bundle),
157     m_scale(0),
158     m_encodedBundle(""),
159     m_theme(""),
160     m_willRemoveContext(NULL),
161     m_encrypted(false),
162     m_widgetType(WrtDB::APP_TYPE_UNKNOWN),
163     m_securityModelVersion(
164         WrtDB::WidgetSecurityModelVersion::WIDGET_SECURITY_MODEL_V1),
165     m_initialized(false)
166 {
167     LOG_PROFILE_START("Bundle attachToThread");
168     WrtDB::WrtDatabase::attachToThreadRO();
169     m_uriChangedMessage = WKStringCreateWithUTF8CString(uriChangedMessageName);
170     LOG_PROFILE_STOP("Bundle attachToThread");
171 #ifdef MULTIPROCESS_SERVICE_SUPPORT_INLINE
172     sendWebProcessPid();
173 #endif
174 }
175
176 Bundle::~Bundle()
177 {
178     WrtDB::WrtDatabase::detachFromThread();
179
180     if (!m_pagesList.empty()) {
181         LogError("There are not closed pages!");
182     }
183
184     WKRelease(m_uriChangedMessage);
185     WKRelease(m_bundle);
186 }
187
188 void Bundle::didCreatePageCallback(
189     WKBundleRef /*bundle*/,
190     WKBundlePageRef page,
191     const void* clientInfo)
192 {
193     LOG_PROFILE_START("didCreatePageCallback");
194     LogDebug("didCreatePageCallback called");
195     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
196     This->didCreatePage(page);
197     LOG_PROFILE_STOP("didCreatePageCallback");
198 }
199
200 void Bundle::didReceiveMessageCallback(
201     WKBundleRef /*bundle*/,
202     WKStringRef messageName,
203     WKTypeRef messageBody,
204     const void *clientInfo)
205 {
206     LogDebug("didReceiveMessageCallback called");
207     Bundle* bundle = static_cast<Bundle*>(const_cast<void*>(clientInfo));
208     bundle->didReceiveMessage(messageName, messageBody);
209 }
210
211 void Bundle::willDestroyPageCallback(
212     WKBundleRef /*bundle*/,
213     WKBundlePageRef page,
214     const void* clientInfo)
215 {
216     LogDebug("willDestroyPageCallback called");
217     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
218     This->willDestroyPage(page);
219 }
220
221 void Bundle::didCreatePage(WKBundlePageRef page)
222 {
223     auto mainFrame = WKBundlePageGetMainFrame(page);
224     auto context = WKBundleFrameGetJavaScriptContext(mainFrame);
225     m_pagesList.push_back(page);
226     m_pageGlobalContext.insertContextForPage(page, context);
227     LogDebug("created Page : " << page << " created JSContext : " << context);
228
229     WKBundlePageResourceLoadClient resourceLoadClient = {
230         kWKBundlePageResourceLoadClientCurrentVersion,  /* version */
231         this, /* clientinfo */
232         0, /* didInitiateLoadForResource */
233         willSendRequestForFrameCallback, /* willSendRequestForFrame */
234         0, /* didReceiveResponseForResource */
235         0, /* didReceiveContentLengthForResource */
236         didFinishLoadForResourceCallback, /* didFinishLoadForResource */
237         0, /* didFailLoadForResource */
238         0, /* shouldCacheResponse */
239         0, /* shouldUseCredentialStorage */
240     };
241     WKBundlePageSetResourceLoadClient(page, &resourceLoadClient);
242
243     WKBundlePageLoaderClient loaderClient = {
244         kWKBundlePageLoaderClientCurrentVersion,
245         this, /* clientinfo */
246         didStartProvisionalLoadForFrameCallback, /* didStartProvisionalLoadForFrame */
247         0, /* didReceiveServerRedirectForProvisionalLoadForFrame */
248         0, /* didFailProvisionalLoadWithErrorForFrame */
249         didCommitLoadForFrameCallback, /* didCommitLoadForFrame */
250         0, /* didFinishDocumentLoadForFrame */
251         0, /* didFinishLoadForFrame */
252         0, /* didFailLoadWithErrorForFrame */
253         0, /* didSameDocumentNavigationForFrame */
254         0, /* didReceiveTitleForFrame */
255         0, /* didFirstLayoutForFrame */
256         0, /* didFirstVisuallyNonEmptyLayoutForFrame */
257         didRemoveFrameFromHierarchyCallback, /* didRemoveFrameFromHierarchy */
258         0, /* didDisplayInsecureContentForFrame */
259         0, /* didRunInsecureContentForFrame */
260         0, /* didClearWindowObjectForFrame */
261         0, /* didCancelClientRedirectForFrame */
262         0, /* willPerformClientRedirectForFrame */
263         0, /* didHandleOnloadEventsForFrame */
264         0, /* didLayoutForFrame */
265         0, /* didNewFirstVisuallyNonEmptyLayout */
266         0, /* didDetectXSSForFrame */
267         0, /* shouldGoToBackForwardListItem */
268         0, /* globalObjectIsAvailableForFrame */
269         0, /* willDisconnectDOMWindowExtensionFromGlobalObject */
270         0, /* didReconnectDOMWindowExtensionToGlobalObject */
271         0, /* willDestroyGlobalObjectForDOMWindowExtension */
272         0, /* didFinishProgress */
273         0, /* shouldForceUniversalAccessFromLocalURL */
274         0, /* didReceiveIntentForFrame */
275         0, /* registerIntentServiceForFrame */
276     };
277     WKBundlePageSetPageLoaderClient(page, &loaderClient);
278
279
280     WKBundlePagePolicyClient policyClient = {
281         kWKBundlePagePolicyClientCurrentVersion, /* version */
282         this,                                    /* clientInfo */
283         decidePolicyForNavigationActionCallback, /* decidePolicyForNavigationAction */
284         decidePolicyForNewWindowActionCallback,  /* decidePolicyForNavigationAction */
285         decidePolicyForResponseCallback,         /* decidePolicyForResponse */
286         0,                                       /* unableToImplementPolicy */
287     };
288     WKBundlePageSetPolicyClient(page, &policyClient);
289 }
290
291 void Bundle::willDestroyPage(WKBundlePageRef page)
292 {
293     LogDebug("Destroyed page : " << page);
294
295     auto context = m_pageGlobalContext.getContextForPage(page);
296     m_pagesList.remove(page);
297     m_pageGlobalContext.removeContextForPage(page);
298     m_pageContext[page].erase(context);
299
300     PluginModule::unloadFrame(context);
301     PluginModule::stop(context);
302 }
303
304 void Bundle::fixWKMessageArgs(std::string & argScale,
305                               std::string & argEncodedBundle,
306                               std::string & argTheme)
307 {
308     if (argScale != "null" && argScale[0] == '_') {
309         argScale.erase(0, 1);
310
311         std::stringstream ssScale(argScale);
312         ssScale >> m_scale;
313     }
314
315     if (argEncodedBundle != "null" && argEncodedBundle[0] == '_') {
316         argEncodedBundle.erase(0, 1);
317
318         m_encodedBundle = argEncodedBundle;
319     }
320
321     if (argTheme != "null" && argTheme[0] == '_') {
322         argTheme.erase(0, 1);
323
324         m_theme = argTheme;
325     }
326 }
327
328 #ifdef CORS_WHITELISTING_ENABLED
329 void Bundle::bypassCORSforWARPAccessList(WrtDB::WidgetDAOReadOnly & dao)
330 {
331     // bypassing CORS using origin whitelist
332     WrtDB::WidgetAccessInfoList WAList;
333     dao.getWidgetAccessInfo(WAList);
334     FOREACH(it, WAList)
335     {
336         const WrtDB::WidgetAccessInfo & access = *it;
337         WKURLRef url = WKURLCreateWithUTF8CString(DPL::ToUTF8String(access.strIRI).c_str());
338
339 #ifdef APP_SCHEME_ENABLED
340         std::string source = std::string("app://") + DPL::ToUTF8String(m_widgetTizenId) + "/";
341 #else
342         std::string source = DPL::ToUTF8String(dao.getFullPath());
343 #endif
344
345         LogDebug("WARP to WK whitelist position: " << source << " for "
346             << access.strIRI << " subDomains: " << access.bSubDomains);
347
348         WKStringRef wkSource = WKStringCreateWithUTF8CString(source.c_str());
349         WKStringRef wkHost;
350         WKStringRef wkProtocol;
351         if(access.strIRI == L"*")
352         {
353             //wildcard force to explicitly say which protocol is used
354             // passed wkHost if empty means wildcard -> allow everything but protocol has to be set.
355             for(unsigned i = 0; i < sizeof(warpAllowProtocolsForWildcard) / sizeof(char*); i++)
356             {
357                 wkHost = WKStringCreateWithUTF8CString("");
358                 wkProtocol = WKStringCreateWithUTF8CString(warpAllowProtocolsForWildcard[i]);
359                 WKBundleAddOriginAccessWhitelistEntry(m_bundle,
360                     wkSource, wkProtocol, wkHost, access.bSubDomains);
361             }
362         }
363         else
364         {
365             wkHost = WKURLCopyHostName(url);
366             wkProtocol = WKURLCopyScheme(url);
367             WKBundleAddOriginAccessWhitelistEntry(m_bundle,
368                 wkSource, wkProtocol, wkHost, access.bSubDomains);
369         }
370
371         WKRelease(wkHost);
372         WKRelease(wkProtocol);
373         WKRelease(wkSource);
374     }
375 }
376 #endif
377
378 void Bundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody)
379 {
380     LogDebug("got message type: " << toString(messageName).c_str());
381     if (WKStringIsEqualToUTF8CString(messageName,
382                                      BundleMessages::START))
383     {
384         if (!messageBody || WKStringGetTypeID() != WKGetTypeID(messageBody)) {
385             LogError("Wrong message format received, ignoring");
386             return;
387         }
388
389         auto msgString = toString(static_cast<WKStringRef>(messageBody));
390         LogDebug("Got message text: " << msgString);
391         LogDebug("loading Page : " << m_pagesList.back() <<
392                  " loading JSContext : " <<
393                  m_pageGlobalContext.getContextForPage(m_pagesList.back()));
394         // set information from ui process
395         std::stringstream ssMsg(msgString);
396         std::string argScale;
397         std::string argEncodedBundle;
398         std::string argTheme;
399
400         std::string id;
401         ssMsg >> id;
402         m_widgetTizenId = DPL::FromASCIIString(id);
403
404         ssMsg >> argScale;
405         ssMsg >> argEncodedBundle;
406         ssMsg >> argTheme;
407         ssMsg >> m_encrypted;
408         LogWarning("m_encrypted : " << m_encrypted);
409
410         // ** Language tags setting completed **
411         fixWKMessageArgs(argScale, argEncodedBundle, argTheme);
412     } else if (WKStringIsEqualToUTF8CString(messageName,
413                                             BundleMessages::SHUTDOWN))
414     {
415         LogDebug("shutdown plugins");
416
417         if (m_pagesList.empty()) {
418             PluginModule::shutdown();
419         } else {
420             LogInfo(
421                 "PluginModule shutdown ignored, there are still alive pages!");
422         }
423     }
424     else if (WKStringIsEqualToUTF8CString(messageName,
425                                           BundleMessages::SET_CUSTOM_PROPERTIES))
426     {
427         LogDebug("reset custom properties of window objects");
428         // set information from ui process
429         auto msgString = toString(static_cast<WKStringRef>(messageBody));
430
431         std::string argScale;
432         std::string argEncodedBundle;
433         std::string argTheme;
434
435         std::stringstream ssMsg(msgString);
436         ssMsg >> argScale;
437         ssMsg >> argEncodedBundle;
438         ssMsg >> argTheme;
439
440         fixWKMessageArgs(argScale, argEncodedBundle, argTheme);
441
442         //apply for each context
443         PageGlobalContextContainer::const_iterator it = m_pageGlobalContext.begin();
444         for (; it != m_pageGlobalContext.end(); ++it) {
445             PluginModule::setCustomProperties(it->second,
446                                               m_scale,
447                                               m_encodedBundle.c_str(),
448                                               m_theme.c_str());
449         }
450     } else if (WKStringIsEqualToUTF8CString(
451                    messageName,
452                    BundleMessages::DISPATCH_JAVASCRIPT_EVENT))
453     {
454         LogDebug("dispatch javascript event to created frames");
455         // set information from ui process
456         auto text = toString(static_cast<WKStringRef>(messageBody));
457         int eventType;
458         void *args = NULL;
459         std::stringstream ss(text);
460         ss >> eventType;
461
462         using namespace WrtPlugins::W3C;
463         // set arguments to be sent to js handler of this custom event
464         if (eventType == SoftKeyboardChangeCustomEvent) {
465             args = new SoftKeyboardChangeArgs;
466             ss >> static_cast<SoftKeyboardChangeArgs *>(args)->state;
467             ss >> static_cast<SoftKeyboardChangeArgs *>(args)->width;
468             ss >> static_cast<SoftKeyboardChangeArgs *>(args)->height;
469         }
470
471         //apply for each context
472         PageGlobalContextContainer::const_iterator it = m_pageGlobalContext.begin();
473         for (; it != m_pageGlobalContext.end(); ++it) {
474             PluginModule::dispatchJavaScriptEvent(
475                 it->second,
476                 static_cast<WrtPlugins::W3C::CustomEventType>(eventType),
477                 args);
478         }
479
480         if (args) {
481             delete static_cast<SoftKeyboardChangeArgs *>(args);
482         }
483     } else if (WKStringIsEqualToUTF8CString(
484                    messageName,
485                    BundleMessages::INIT))
486     {
487         LogDebug("initializing plugins");
488
489         if (!m_initialized)
490         {
491             auto msgString = toString(static_cast<WKStringRef>(messageBody));
492
493             m_widgetTizenId = DPL::FromASCIIString(msgString);
494
495             WrtDB::WidgetDAOReadOnly dao(m_widgetTizenId);
496
497             // process pool - set app_privilige
498             if (UID_ROOT == getuid())
499             {
500                 using namespace WrtDB::GlobalConfig;
501
502                 std::string appPath;
503                 std::string tzAppId = DPL::ToUTF8String(dao.getTzAppId());
504                 std::string tzPkgId = DPL::ToUTF8String(dao.getTizenPkgId());
505                 DPL::OptionalString installedPath = dao.getWidgetInstalledPath();
506                 if (installedPath.IsNull()) {
507                     appPath = std::string(GetUserInstalledWidgetPath()) + "/" +
508                         tzPkgId + GetUserWidgetExecPath() + "/" + tzAppId;
509                 } else {
510                     appPath = DPL::ToUTF8String(*installedPath) +
511                         GetUserWidgetExecPath() + "/" + tzAppId;
512                 }
513
514                 LogDebug("set_app_privilege(" << appPath << ")");
515                 set_app_privilege(tzPkgId.c_str(), PRIVILEGE_APP_TYPE, appPath.c_str());
516             }
517
518             /* This type of message is received when widget is restarting
519              * (proably in other situation too). Widget restart can be
520              * called after system language change so language tags have to
521              * be recreated here.
522              * Do NOT MOVE LanguageTags reset before m_widgetHandle initialization
523              */
524             // reset language tags (create new tags based on system locales)
525             LanguageTagsProviderSingleton::Instance().resetLanguageTags();
526             DPL::OptionalString defaultLocale = dao.getDefaultlocale();
527             if (!defaultLocale.IsNull()) {
528                 LanguageTagsProviderSingleton::Instance().addWidgetDefaultLocales(
529                     *defaultLocale);
530             }
531             LanguageTags tags =
532                 LanguageTagsProviderSingleton::Instance().getLanguageTags();
533             LogDebug("Current widget locales (language tags):");
534             FOREACH(it, tags) {
535                 LogDebug("Locale: " << *it);
536             }
537
538             m_widgetType = dao.getWidgetType();
539             LogDebug("m_widgetType : " << m_widgetType.getApptypeToString() <<
540                      "(m_widgetTizenId:" << m_widgetTizenId << ")");
541
542             LogDebug("Preload PluginLogicSingleton");
543             PluginModule::init(WrtDB::WidgetDAOReadOnly::getHandle(m_widgetTizenId));
544             LogDebug("Preload PluginLogicSingleton_end");
545
546             m_securityModelVersion = dao.getSecurityModelVersion();
547 #ifdef CORS_WHITELISTING_ENABLED
548             bypassCORSforWARPAccessList(dao);
549 #endif
550             m_initialized = true;
551         }
552         else
553         {
554             LogDebug("already initalized");
555         }
556     }
557 }
558
559 WKURLRequestRef Bundle::willSendRequestForFrameCallback(
560     WKBundlePageRef /*page*/,
561     WKBundleFrameRef /*frame*/,
562     uint64_t /*resourceIdentifier*/,
563     WKURLRequestRef request,
564     WKURLResponseRef /*response*/,
565     const void *clientInfo)
566 {
567     LogDebug("willSendRequestForFrameCallback called");
568     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
569     return This->willSendRequestForFrame(request);
570 }
571
572 void Bundle::didStartProvisionalLoadForFrameCallback(
573     WKBundlePageRef page,
574     WKBundleFrameRef frame,
575     WKTypeRef* /*userData*/,
576     const void *clientInfo)
577 {
578     LogDebug("didStartProvisionalLoadForFrameCallback called");
579     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
580
581     // set viewmode
582     WrtDB::WidgetDAOReadOnly dao(This->m_widgetTizenId);
583     WrtDB::WindowModeList modeList = dao.getWindowModes();
584     FOREACH(it, modeList) {
585         std::string viewMode = DPL::ToUTF8String(*it);
586         if (viewMode == VIEWMODE_TYPE_FULLSCREEN
587             || viewMode == VIEWMODE_TYPE_MAXIMIZED)
588         {
589             WKBundlePageSetViewMode(
590                 page,
591                 WKStringCreateWithUTF8CString(viewMode.c_str()));
592             break;
593         }
594     }
595
596     if (This->m_pageGlobalContext.find(page) == This->m_pageGlobalContext.end()) {
597         return;
598     }
599     if (This->m_pageContext.count(page) == 0) {
600         return;
601     }
602
603     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
604
605     ContextSet::iterator i = This->m_pageContext[page].find(context);
606
607     if (i == This->m_pageContext[page].end()) {
608         LogDebug("Initially attached frame");
609         return;
610     }
611
612     This->m_pageContext[page].erase(i);
613     This->m_willRemoveContext = context;
614 }
615
616 void Bundle::didRemoveFrameFromHierarchyCallback(
617     WKBundlePageRef page,
618     WKBundleFrameRef frame,
619     WKTypeRef* /*userData*/,
620     const void *clientInfo)
621 {
622     LogDebug("didRemoveFrameFromHierarchyCallback called");
623     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
624
625     if (This->m_pageContext.count(page) == 0) {
626         LogDebug("his->m_pageContext.count(page) == 0");
627         return;
628     }
629
630     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
631
632     ContextSet::iterator i = This->m_pageContext[page].find(context);
633
634     if (i == This->m_pageContext[page].end()) {
635         LogWarning("Tried to unload frame which has never been loaded");
636         return;
637     }
638
639     This->m_pageContext[page].erase(i);
640
641     PluginModule::unloadFrame(context);
642 }
643
644 void Bundle::didFinishLoadForResourceCallback(
645     WKBundlePageRef /*page*/,
646     WKBundleFrameRef /*frame*/,
647     uint64_t /*resourceIdentifier*/,
648     const void* /*clientInfo*/)
649 {
650     LogDebug("didFinishLoadForResourceCallback called");
651 }
652
653 void Bundle::didCommitLoadForFrameCallback(
654     WKBundlePageRef page,
655     WKBundleFrameRef frame,
656     WKTypeRef* /*userData*/,
657     const void *clientInfo)
658 {
659     LogInfo("didCommitLoadForFrameCallback called");
660     LOG_PROFILE_START("didCommitLoadForFrameCallback");
661     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
662
663     WKURLRef url = WKBundleFrameCopyURL(frame);
664     WKTypeRef retVal = NULL;
665
666     if (url == NULL) {
667         LogInfo("url is NULL");
668         return;
669     }
670
671     if (This->m_willRemoveContext) {
672         PluginModule::unloadFrame(This->m_willRemoveContext);
673         This->m_willRemoveContext = NULL;
674     }
675
676     JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
677
678     This->m_pageContext[page].insert(context);
679
680     if (!WKBundleFrameIsMainFrame(frame)) {
681         LogInfo("frame isn't main frame");
682         PluginModule::start(
683             WrtDB::WidgetDAOReadOnly::getHandle(This->m_widgetTizenId),
684             context,
685             This->m_scale,
686             This->m_encodedBundle.c_str(),
687             This->m_theme.c_str());
688         PluginModule::loadFrame(context);
689         return;
690     }
691
692     std::string scheme = getScheme(toString(url));
693     std::string result = URICHANGE_PLUGIN_RESTART;
694
695     if (scheme == SCHEME_HTTP || scheme == SCHEME_HTTPS) {
696         WKStringRef urlStr = WKURLCopyString(url);
697         WKBundlePostSynchronousMessage(This->m_bundle,
698                                        This->m_uriChangedMessage,
699                                        urlStr,
700                                        &retVal);
701         WKRelease(url);
702         WKRelease(urlStr);
703
704         result = toString(static_cast<WKStringRef>(retVal));
705     }
706     LogInfo("result from UI process : " << result);
707
708     if (result == URICHANGE_PLUGIN_STOP_ONLY) {
709         if(This->m_pageGlobalContext.find(page) != This->m_pageGlobalContext.end())
710         {
711             LogDebug("Previous context: " << This->m_pageGlobalContext.getContextForPage(page));
712             PluginModule::stop(This->m_pageGlobalContext.getContextForPage(page));
713         }
714         LogDebug("New context: " << context);
715         This->m_pageGlobalContext.insertContextForPage(page, context);
716     } else if (result == URICHANGE_PLUGIN_RESTART) {
717         if(This->m_pageGlobalContext.find(page) != This->m_pageGlobalContext.end())
718         {
719             LogDebug("Previous context: " << This->m_pageGlobalContext.getContextForPage(page));
720             PluginModule::stop(This->m_pageGlobalContext.getContextForPage(page));
721         }
722         LogDebug("New context: " << context);
723         //note that since we need old context for unloading plugins it must be sotred
724         //custom container take care of increamenting and decrementing references
725         This->m_pageGlobalContext.insertContextForPage(page, context);
726         LOG_PROFILE_START("PluginModule start");
727         PluginModule::start(
728             WrtDB::WidgetDAOReadOnly::getHandle(This->m_widgetTizenId),
729             context,
730             This->m_scale,
731             This->m_encodedBundle.c_str(),
732             This->m_theme.c_str() );
733         LOG_PROFILE_STOP("PluginModule start");
734
735         PluginModule::loadFrame(context);
736     }
737     LOG_PROFILE_STOP("didCommitLoadForFrameCallback");
738 }
739
740 WKBundlePagePolicyAction Bundle::decidePolicyForNavigationActionCallback(
741     WKBundlePageRef page,
742     WKBundleFrameRef frame,
743     WKBundleNavigationActionRef navigationAction,
744     WKURLRequestRef request,
745     WKTypeRef* userData,
746     const void* clientInfo)
747 {
748     LogDebug("decidePolicyForNavigationActionCallback called");
749
750     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
751     return This->decidePolicyForAction(false,
752                                        page,
753                                        frame,
754                                        navigationAction,
755                                        request,
756                                        userData);
757 }
758
759 WKBundlePagePolicyAction Bundle::decidePolicyForNewWindowActionCallback(
760     WKBundlePageRef page,
761     WKBundleFrameRef frame,
762     WKBundleNavigationActionRef navigationAction,
763     WKURLRequestRef request,
764     WKStringRef /*frameName*/,
765     WKTypeRef* userData,
766     const void* clientInfo)
767 {
768     LogDebug("decidePolicyForNewWindowActionCallback called");
769
770     Bundle* This = static_cast<Bundle*>(const_cast<void*>(clientInfo));
771     return This->decidePolicyForAction(true,
772                                        page,
773                                        frame,
774                                        navigationAction,
775                                        request,
776                                        userData);
777 }
778
779 WKBundlePagePolicyAction Bundle::decidePolicyForResponseCallback(
780     WKBundlePageRef /* page */,
781     WKBundleFrameRef /* frame */,
782     WKURLResponseRef response,
783     WKURLRequestRef /* request */,
784     WKTypeRef*          /* userData */,
785     const void*         /* clientInfo */)
786 {
787     LogDebug("decidePolicyForResponseCallback called");
788
789     Assert(response);
790     WKStringRef contentTypeRef = WKURLResponseEflCopyContentType(response);
791
792     std::string contentType = toString(contentTypeRef);
793     LogDebug("contentTypeRef : " << contentType);
794     WKRelease(contentTypeRef);
795
796     if (contentType == HTML_MIME) {
797         LogDebug("Accepting HTML_MIME type");
798         return WKBundlePagePolicyActionUse;
799     }
800     if (contentType == PHP_MIME) {
801         LogDebug("Accepting php type");
802         return WKBundlePagePolicyActionUse;
803     }
804
805     return WKBundlePagePolicyActionPassThrough;
806 }
807
808 WKURLRequestRef Bundle::willSendRequestForFrame(WKURLRequestRef request)
809 {
810     LogDebug("willSendReq got " << toString(request).c_str());
811     WKURLRef url = WKURLRequestCopyURL(request);
812     WKStringRef urlStr = WKURLCopyString(url);
813
814     DPL::String dplurl = DPL::FromUTF8String(toString(urlStr));
815     WKRelease(urlStr);
816
817     DPL::Optional<DPL::String> localizedUrl =
818         BundleURIHandling::localizeURI(dplurl, m_widgetTizenId);
819     bool ret =
820         BundleURIHandling::processURI(*localizedUrl,
821                                       m_widgetTizenId,
822                                       m_securityModelVersion);
823
824     if (!ret) {
825         LogDebug("Not permitted resource: " << *localizedUrl);
826         return NULL;
827     }
828
829     LogDebug("URI processing result: " << *localizedUrl);
830     std::string tmpUrlStr = DPL::ToUTF8String(*localizedUrl);
831     WKURLRef tmpUrl = WKURLCreateWithUTF8CString(tmpUrlStr.c_str());
832     std::string scheme = toString(WKURLCopyScheme(url)); //scheme of original request
833     WKRelease(url);
834
835 #ifdef APP_SCHEME_ENABLED
836     if(scheme == SCHEME_FILE) {
837         LogError("File schema blocked for: " << dplurl);
838         return NULL;
839     }
840 #endif
841
842     // Return value must contain details information of input
843     // WKURLRequestRef. Current webkit2 doesn't support api that
844     // copy WKURLRequestRef or change url only. Before webkit2
845     // support api, callback return original WKURLRequestRef in the
846     // case of external scheme
847
848     // external scheme also need to send message to UI process for
849     // checking roaming and security
850     if (scheme == SCHEME_HTTP || scheme == SCHEME_HTTPS) {
851         LogDebug("external scheme return original WKURLRequestRef");
852         WKRelease(tmpUrl);
853         WKRetain(request);
854         return request;
855     } else {
856         std::string checkUrl = toString(tmpUrl);
857
858         if (m_encrypted) {
859             int getFileSize;
860             if (isEncryptedResource(checkUrl, getFileSize)) {
861                 std::string decryptString = DecryptResource(checkUrl,
862                                                             getFileSize);
863                 if (!decryptString.empty()) {
864                     std::string destString = DATA_STRING;
865
866                     std::string mimeString =
867                         DPL::ToUTF8String(
868                             MimeTypeUtils::identifyFileMimeType(
869                                 DPL::FromUTF8String(checkUrl)));
870
871                     destString += mimeString;
872                     destString += BASE64_STRING;
873
874                     decryptString.insert(0, destString);
875
876                     WKURLRef destUrl =
877                         WKURLCreateWithUTF8CString(decryptString.c_str());
878
879                     WKURLRequestRef req = WKURLRequestCreateWithWKURL(
880                             destUrl);
881                     WKRelease(destUrl);
882                     LogDebug("return value " << decryptString << "]]");
883                     return req;
884                 }
885             }
886         }
887         WKURLRequestRef req = WKURLRequestCreateWithWKURL(tmpUrl);
888         WKRelease(tmpUrl);
889         LogDebug("return value " << toString(req).c_str());
890         return req;
891     }
892 }
893
894 WKBundlePagePolicyAction Bundle::decidePolicyForAction(
895     bool isNewWindow,
896     WKBundlePageRef /* page */,
897     WKBundleFrameRef frame,
898     WKBundleNavigationActionRef /* navigationAction */,
899     WKURLRequestRef request,
900     WKTypeRef* /* userData */)
901 {
902     using namespace ViewModule;
903     using namespace ViewModule::SchemeActionMap;
904
905     char const * const TIZEN_SCHEME = "tizen";
906
907     std::string request_uri = toString(request);
908
909     LogInfo("Uri being checked: " << request_uri);
910
911     // exception uri
912     if (request_uri == BLANK_PAGE_URL) {
913         return WKBundlePagePolicyActionUse;
914     }
915
916     // in case of box scheme, unconditionally PassThrough should be returned
917     if (!request_uri.compare(0, 6, SCHEME_BOX_SLASH)) {
918         return WKBundlePagePolicyActionPassThrough;
919     }
920
921     DPL::String dplUrl = DPL::FromUTF8String(request_uri);
922     bool ret =
923         BundleURIHandling::processMainResource(dplUrl,
924                                                m_widgetTizenId,
925                                                m_securityModelVersion);
926     if (!ret) {
927         std::string blockedUrl = DPL::ToUTF8String(dplUrl);
928         LogDebug("URI is blocked: " << blockedUrl);
929
930         // Send information about blocked URI to UIProcess
931         WKStringRef urlStr = WKStringCreateWithUTF8CString(blockedUrl.c_str());
932         WKTypeRef retVal = NULL;
933         WKStringRef blockMessage = WKStringCreateWithUTF8CString(uriBlockedMessageName);
934         WKBundlePostSynchronousMessage(m_bundle, blockMessage, urlStr, &retVal);
935         WKRelease(urlStr);
936         WKRelease(retVal);
937         WKRelease(blockMessage);
938         return WKBundlePagePolicyActionPassThrough;
939     }
940
941     // get scheme string
942     std::string request_scheme = getScheme(request_uri);
943
944     // is tizen schem?
945     if (request_scheme == TIZEN_SCHEME) {
946         return WKBundlePagePolicyActionPassThrough;
947     }
948
949     // scheme action
950     Scheme scheme(request_scheme);
951     LogDebug("Scheme: " << request_scheme);
952
953     Scheme::Type type = scheme.GetType();
954     if (type < Scheme::FILE || type >= Scheme::COUNT) {
955         LogError("Invalid scheme: " << request_scheme);
956         return WKBundlePagePolicyActionPassThrough;
957     }
958
959     bool mainFrame = WKBundleFrameIsMainFrame(frame);
960     NavigationContext ctx = mainFrame ? TOP_LEVEL : FRAME_LEVEL;
961     if (isNewWindow) {
962         ctx = NEW_WINDOW;
963     }
964
965     LogDebug("Scheme type: " << type);
966     LogDebug("Navigation context: " << ctx);
967     LogDebug("Application type: " << m_widgetType.getApptypeToString());
968
969     UriAction action;
970
971     if (m_widgetType == WrtDB::APP_TYPE_TIZENWEBAPP) {
972         action = g_tizenActionMap[type][ctx];
973     } else {
974         LogError("Unsupported application type: " << type);
975         return WKBundlePagePolicyActionPassThrough;
976     }
977
978     LogDebug("Uri action: " << action);
979
980     if (action != URI_ACTION_WRT) {
981         return WKBundlePagePolicyActionPassThrough;
982     }
983
984     return WKBundlePagePolicyActionUse;
985 }
986
987 std::string Bundle::toString(WKStringRef str)
988 {
989     if (WKStringIsEmpty(str)) {
990         return std::string();
991     }
992     size_t size = WKStringGetMaximumUTF8CStringSize(str);
993     char buffer[size + 1];
994     WKStringGetUTF8CString(str, buffer, size + 1);
995     return buffer;
996 }
997
998 std::string Bundle::toString(WKURLRef url)
999 {
1000     WKStringRef urlStr = WKURLCopyString(url);
1001     std::string str = toString(urlStr);
1002     WKRelease(urlStr);
1003     return str;
1004 }
1005
1006 std::string Bundle::toString(WKURLRequestRef req)
1007 {
1008     WKURLRef reqUrl = WKURLRequestCopyURL(req);
1009     std::string str = toString(reqUrl);
1010     WKRelease(reqUrl);
1011     return str;
1012 }
1013
1014 std::string Bundle::toString(WKErrorRef err)
1015 {
1016     WKStringRef domErr = WKErrorCopyDomain(err);
1017     WKStringRef desc = WKErrorCopyLocalizedDescription(err);
1018     std::string str = toString(domErr) + "\n" + toString(desc);
1019     WKRelease(domErr);
1020     WKRelease(desc);
1021     return str;
1022 }
1023
1024 std::string Bundle::getScheme(std::string uri)
1025 {
1026     std::size_t found = uri.find(':');
1027     std::string str;
1028
1029     if (found != std::string::npos) {
1030         str = uri.substr(0, found);
1031     }
1032
1033     return str;
1034 }
1035
1036 bool Bundle::isEncryptedResource(std::string Url, int &size)
1037 {
1038     if (m_encryptedFiles.empty()) {
1039         WrtDB::WidgetDAOReadOnly(m_widgetTizenId).
1040             getEncryptedFileList(m_encryptedFiles);
1041     }
1042
1043     std::set<WrtDB::EncryptedFileInfo>::iterator it;
1044     WrtDB::EncryptedFileInfo info;
1045     std::string filePath;
1046
1047     if (0 != strncmp(Url.c_str(), SCHEME_FILE_SLASH, strlen(SCHEME_FILE_SLASH))) {
1048         return false;
1049     }
1050
1051     filePath = Url.substr(strlen(SCHEME_FILE_SLASH));
1052     info.fileName = DPL::FromUTF8String(filePath);
1053
1054     if (m_encryptedFiles.end() != (it = m_encryptedFiles.find(info)))
1055     {
1056         LogDebug(" info file name : " << it->fileName);
1057         LogDebug(" info file size : " << it->fileSize);
1058         size = it->fileSize;
1059         return true;
1060     }
1061     return false;
1062 }
1063
1064 std::string Bundle::DecryptResource(std::string resource, int size)
1065 {
1066     std::string filePath;
1067
1068     size_t pos = resource.find_first_not_of(SCHEME_FILE_SLASH);
1069     if (std::string::npos != pos) {
1070         filePath = resource.substr(pos - 1);
1071     }
1072
1073     struct stat buf;
1074     if (0 == stat(filePath.c_str(), &buf)) {
1075         const std::size_t fileSize = buf.st_size;
1076         std::unique_ptr<unsigned char[]> inChunk;
1077
1078         FILE* fp = fopen(filePath.c_str(), "rb");
1079         if (NULL == fp) {
1080             LogDebug("Couldnot open file : " << filePath);
1081             return std::string();
1082         }
1083
1084         std::unique_ptr<unsigned char[]> DecryptedString(new unsigned
1085                 char[fileSize]);
1086         std::string pkgid(DPL::ToUTF8String(m_widgetTizenId));
1087
1088         using namespace Tizen::Base;
1089         const byte *b_pkgid = reinterpret_cast<const byte*>(pkgid.c_str());
1090         ByteBuffer appInfo;
1091         appInfo.Construct(pkgid.length());
1092         if (appInfo.SetArray(b_pkgid, 0, pkgid.length()) != E_SUCCESS) {
1093             LogDebug("Couldnot set appInfo");
1094             fclose(fp);
1095             return std::string();
1096         }
1097         appInfo.Flip();
1098
1099         int writeCount = 0;
1100         do {
1101             unsigned char getDecSize[4];
1102             memset(getDecSize, 0x00, sizeof(getDecSize));
1103
1104             size_t readSize = fread(getDecSize, sizeof(unsigned char),
1105                     sizeof(getDecSize), fp);
1106             if (0 != readSize) {
1107                 int readBufSize = 0;
1108                 std::istringstream(std::string((char*)getDecSize)) >> readBufSize;
1109                 inChunk.reset(new unsigned char[readBufSize]);
1110
1111                 size_t decReadSize = fread(inChunk.get(), sizeof(unsigned char),
1112                         readBufSize, fp);
1113                 if (0 != decReadSize) {
1114                     ByteBuffer *getBuffer =
1115                         DecryptChunkByTrustZone(&appInfo, inChunk.get(),
1116                                 decReadSize);
1117                     memcpy(DecryptedString.get() + writeCount,
1118                             getBuffer->GetPointer(), getBuffer->GetRemaining());
1119                     writeCount += getBuffer->GetRemaining();
1120                     getBuffer->Reset();
1121                 }
1122             }
1123
1124         } while( 0 == std::feof(fp));
1125         fclose(fp);
1126
1127         memset(DecryptedString.get() + size, '\n', fileSize - size);
1128         LogDebug("resource need to encoding base64");
1129         BIO *bmem, *b64;
1130         BUF_MEM *bptr;
1131
1132         b64 = BIO_new(BIO_f_base64());
1133         bmem = BIO_new(BIO_s_mem());
1134         b64 = BIO_push(b64, bmem);
1135         BIO_write(b64, DecryptedString.get(), fileSize);
1136         BIO_flush(b64);
1137         BIO_get_mem_ptr(b64, &bptr);
1138
1139         std::string base64Enc((char *)bptr->data, bptr->length - 1);
1140         BIO_free_all(b64);
1141
1142         return base64Enc;
1143     }
1144     return std::string();
1145 }
1146
1147 #ifdef MULTIPROCESS_SERVICE_SUPPORT_INLINE
1148 void Bundle::sendWebProcessPid()
1149 {
1150     std::stringstream strPid;
1151     strPid << getpid();
1152     WKStringRef pidStr = WKStringCreateWithUTF8CString(strPid.str().c_str());
1153     WKTypeRef retVal = NULL;
1154     WKStringRef message = WKStringCreateWithUTF8CString(webProcessPidMessageName);
1155     WKBundlePostSynchronousMessage(m_bundle, message, pidStr, &retVal);
1156     WKRelease(pidStr);
1157     WKRelease(retVal);
1158     WKRelease(message);
1159 }
1160 #endif
1161
1162 extern "C"
1163 {
1164 WK_EXPORT
1165 void WKBundleInitialize(WKBundleRef bundle,
1166                         WKTypeRef)
1167 {
1168     DPL::Log::LogSystemSingleton::Instance().SetTag("WRT-BUNDLE");
1169     LogDebug("Bundle initialized");
1170
1171     DPL::Event::GetMainEventDispatcherInstance().ResetCrossEventCallHandler();
1172     LogDebug("ResetCrossEventCallHandler()");
1173
1174     static Bundle s_bundle(bundle);
1175
1176     WKBundleClient client = {
1177         kWKBundleClientCurrentVersion,
1178         &s_bundle,
1179         &Bundle::didCreatePageCallback,
1180         &Bundle::willDestroyPageCallback,
1181         0,     /* didInitializePageGroup */
1182         &Bundle::didReceiveMessageCallback
1183     };
1184     WKBundleSetClient(bundle, &client);
1185
1186     // process pool - restore process priority
1187     if (UID_ROOT == getuid())
1188     {
1189         setpriority(PRIO_PROCESS, 0, DEFAULT_PRIORITY);
1190     }
1191 }
1192 }