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