1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "InjectedBundle.h" 28 29#import "APIData.h" 30#import "ObjCObjectGraph.h" 31#import "WKBundleAPICast.h" 32#import "WKBundleInitialize.h" 33#import "WKWebProcessBundleParameters.h" 34#import "WKWebProcessPlugInInternal.h" 35#import "WebProcessCreationParameters.h" 36#import <Foundation/NSBundle.h> 37#import <stdio.h> 38#import <wtf/RetainPtr.h> 39#import <wtf/text/CString.h> 40#import <wtf/text/WTFString.h> 41 42using namespace WebCore; 43 44@interface NSBundle (WKAppDetails) 45- (CFBundleRef)_cfBundle; 46@end 47 48namespace WebKit { 49 50bool InjectedBundle::initialize(const WebProcessCreationParameters& parameters, API::Object* initializationUserData) 51{ 52 if (m_sandboxExtension) { 53 if (!m_sandboxExtension->consumePermanently()) { 54 WTFLogAlways("InjectedBundle::load failed - Could not consume bundle sandbox extension for [%s].\n", m_path.utf8().data()); 55 return false; 56 } 57 58 m_sandboxExtension = 0; 59 } 60 61 RetainPtr<CFStringRef> injectedBundlePathStr = m_path.createCFString(); 62 if (!injectedBundlePathStr) { 63 WTFLogAlways("InjectedBundle::load failed - Could not create the path string.\n"); 64 return false; 65 } 66 67 RetainPtr<CFURLRef> bundleURL = adoptCF(CFURLCreateWithFileSystemPath(0, injectedBundlePathStr.get(), kCFURLPOSIXPathStyle, false)); 68 if (!bundleURL) { 69 WTFLogAlways("InjectedBundle::load failed - Could not create the url from the path string.\n"); 70 return false; 71 } 72 73 m_platformBundle = [[NSBundle alloc] initWithURL:(NSURL *)bundleURL.get()]; 74 if (!m_platformBundle) { 75 WTFLogAlways("InjectedBundle::load failed - Could not create the bundle.\n"); 76 return false; 77 } 78 79 if (![m_platformBundle load]) { 80 WTFLogAlways("InjectedBundle::load failed - Could not load the executable from the bundle.\n"); 81 return false; 82 } 83 84 // First check to see if the bundle has a WKBundleInitialize function. 85 WKBundleInitializeFunctionPtr initializeFunction = reinterpret_cast<WKBundleInitializeFunctionPtr>(CFBundleGetFunctionPointerForName([m_platformBundle _cfBundle], CFSTR("WKBundleInitialize"))); 86 if (initializeFunction) { 87 initializeFunction(toAPI(this), toAPI(initializationUserData)); 88 return true; 89 } 90 91#if WK_API_ENABLED 92 if (parameters.bundleParameterData) { 93 auto bundleParameterData = adoptNS([[NSData alloc] initWithBytesNoCopy:const_cast<void*>(static_cast<const void*>(parameters.bundleParameterData->bytes())) length:parameters.bundleParameterData->size() freeWhenDone:NO]); 94 95 auto unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:bundleParameterData.get()]); 96 [unarchiver setRequiresSecureCoding:YES]; 97 98 NSDictionary *dictionary = nil; 99 @try { 100 dictionary = [unarchiver.get() decodeObjectOfClass:[NSObject class] forKey:@"parameters"]; 101 ASSERT([dictionary isKindOfClass:[NSDictionary class]]); 102 } @catch (NSException *exception) { 103 LOG_ERROR("Failed to decode bundle parameters: %@", exception); 104 } 105 106 m_bundleParameters = adoptNS([[WKWebProcessBundleParameters alloc] initWithDictionary:dictionary]); 107 } 108 109 // Otherwise, look to see if the bundle has a principal class 110 Class principalClass = [m_platformBundle principalClass]; 111 if (!principalClass) { 112 WTFLogAlways("InjectedBundle::load failed - No initialize function or principal class found in the bundle executable.\n"); 113 return false; 114 } 115 116 if (![principalClass conformsToProtocol:@protocol(WKWebProcessPlugIn)]) { 117 WTFLogAlways("InjectedBundle::load failed - Principal class does not conform to the WKWebProcessPlugIn protocol.\n"); 118 return false; 119 } 120 121 id <WKWebProcessPlugIn> instance = (id <WKWebProcessPlugIn>)[[principalClass alloc] init]; 122 if (!instance) { 123 WTFLogAlways("InjectedBundle::load failed - Could not initialize an instance of the principal class.\n"); 124 return false; 125 } 126 127 WKWebProcessPlugInController* plugInController = WebKit::wrapper(*this); 128 [plugInController _setPrincipalClassInstance:instance]; 129 130 if ([instance respondsToSelector:@selector(webProcessPlugIn:initializeWithObject:)]) { 131 RetainPtr<id> objCInitializationUserData; 132 if (initializationUserData && initializationUserData->type() == API::Object::Type::ObjCObjectGraph) 133 objCInitializationUserData = static_cast<ObjCObjectGraph*>(initializationUserData)->rootObject(); 134 [instance webProcessPlugIn:plugInController initializeWithObject:objCInitializationUserData.get()]; 135 } 136 137 return true; 138#else 139 return false; 140#endif 141} 142 143#if WK_API_ENABLED 144WKWebProcessBundleParameters *InjectedBundle::bundleParameters() 145{ 146 // We must not return nil even if no parameters are currently set, in order to allow the client 147 // to use KVO. 148 if (!m_bundleParameters) 149 m_bundleParameters = adoptNS([[WKWebProcessBundleParameters alloc] initWithDictionary:@{ }]); 150 151 return m_bundleParameters.get(); 152} 153#endif 154 155void InjectedBundle::setBundleParameter(const String& key, const IPC::DataReference& value) 156{ 157#if WK_API_ENABLED 158 auto bundleParameterData = adoptNS([[NSData alloc] initWithBytesNoCopy:const_cast<void*>(static_cast<const void*>(value.data())) length:value.size() freeWhenDone:NO]); 159 160 auto unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:bundleParameterData.get()]); 161 [unarchiver setRequiresSecureCoding:YES]; 162 163 id parameter = nil; 164 @try { 165 parameter = [unarchiver decodeObjectOfClass:[NSObject class] forKey:@"parameter"]; 166 } @catch (NSException *exception) { 167 LOG_ERROR("Failed to decode bundle parameter: %@", exception); 168 } 169 170 if (!m_bundleParameters && parameter) 171 m_bundleParameters = adoptNS([[WKWebProcessBundleParameters alloc] initWithDictionary:[NSDictionary dictionary]]); 172 173 [m_bundleParameters setParameter:parameter forKey:key]; 174#endif 175} 176 177} // namespace WebKit 178