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