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