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