1/* 2 * Copyright (C) 2012 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 "ObjCObjectGraphCoders.h" 28 29#import "ArgumentCodersMac.h" 30#import "WKTypeRefWrapper.h" 31 32// For UIProcess side encoding/decoding 33#import "WKAPICast.h" 34#import "WKBrowsingContextControllerInternal.h" 35#import "WKBrowsingContextControllerPrivate.h" 36#import "WebContextUserMessageCoders.h" 37#import "WebPageProxy.h" 38#import "WebProcessProxy.h" 39 40// For WebProcess side encoding/decoding 41#import "InjectedBundleUserMessageCoders.h" 42#import "WKBundleAPICast.h" 43#import "WKWebProcessPlugInBrowserContextControllerInternal.h" 44#import "WKWebProcessPlugInBrowserContextControllerPrivate.h" 45#import "WKWebProcessPlugInInternal.h" 46#import "WebPage.h" 47#import "WebProcess.h" 48 49namespace WebKit { 50 51enum WebKitNSType { 52 NullType, 53 NSDictionaryType, 54 NSArrayType, 55 NSStringType, 56 NSNumberType, 57 NSDateType, 58 NSDataType, 59#if defined(__LP64__) && defined(__clang__) 60 WKBrowsingContextControllerType, 61 WKTypeRefWrapperType, 62#endif 63 UnknownType, 64}; 65 66static WebKitNSType typeFromObject(id object) 67{ 68 ASSERT(object); 69 70 if ([object isKindOfClass:[NSDictionary class]]) 71 return NSDictionaryType; 72 if ([object isKindOfClass:[NSString class]]) 73 return NSStringType; 74 if ([object isKindOfClass:[NSArray class]]) 75 return NSArrayType; 76 if ([object isKindOfClass:[NSNumber class]]) 77 return NSNumberType; 78 if ([object isKindOfClass:[NSDate class]]) 79 return NSDateType; 80 if ([object isKindOfClass:[NSData class]]) 81 return NSDataType; 82#if defined(__LP64__) && defined(__clang__) 83 if ([object isKindOfClass:[WKBrowsingContextController class]] || [object isKindOfClass:[WKWebProcessPlugInBrowserContextController class]]) 84 return WKBrowsingContextControllerType; 85 if ([object isKindOfClass:[WKTypeRefWrapper class]]) 86 return WKTypeRefWrapperType; 87#endif 88 89 return UnknownType; 90} 91 92template<typename Owner> 93class ObjCObjectGraphEncoder { 94public: 95 bool baseEncode(CoreIPC::ArgumentEncoder& encoder, WebKitNSType& type) const 96 { 97 if (!m_root) { 98 encoder << static_cast<uint32_t>(NullType); 99 return true; 100 } 101 102 type = typeFromObject(m_root); 103 if (type == UnknownType) { 104 [NSException raise:NSInvalidArgumentException format:@"Can not encode objects of class type '%@'", static_cast<NSString *>(NSStringFromClass([m_root class]))]; 105 } 106 107 encoder << static_cast<uint32_t>(type); 108 109 switch (type) { 110 case NSStringType: { 111 CoreIPC::encode(encoder, static_cast<NSString *>(m_root)); 112 return true; 113 } 114 case NSArrayType: { 115 NSArray *array = static_cast<NSArray *>(m_root); 116 117 NSUInteger size = [array count]; 118 encoder << static_cast<uint64_t>(size); 119 120 for (NSUInteger i = 0; i < size; ++i) 121 encoder << Owner([array objectAtIndex:i]); 122 return true; 123 } 124 case NSDictionaryType: { 125 NSDictionary* dictionary = static_cast<NSDictionary *>(m_root); 126 127 NSUInteger size = [dictionary count]; 128 encoder << static_cast<uint64_t>(size); 129 130 NSArray *keys = [dictionary allKeys]; 131 NSArray *values = [dictionary allValues]; 132 for (NSUInteger i = 0; i < size; ++i) { 133 encoder << Owner([keys objectAtIndex:i]); 134 encoder << Owner([values objectAtIndex:i]); 135 } 136 137 return true; 138 } 139 case NSNumberType: { 140 CoreIPC::encode(encoder, static_cast<NSNumber *>(m_root)); 141 return true; 142 } 143 case NSDateType: { 144 CoreIPC::encode(encoder, static_cast<NSDate *>(m_root)); 145 return true; 146 } 147 case NSDataType: { 148 CoreIPC::encode(encoder, static_cast<NSData *>(m_root)); 149 return true; 150 } 151 default: 152 break; 153 } 154 155 return false; 156 } 157 158protected: 159 ObjCObjectGraphEncoder(id root) 160 : m_root(root) 161 { 162 } 163 164 id m_root; 165}; 166 167template<typename Owner> 168class ObjCObjectGraphDecoder { 169public: 170 static bool baseDecode(CoreIPC::ArgumentDecoder& decoder, Owner& coder, WebKitNSType& type) 171 { 172 uint32_t typeAsUInt32; 173 if (!decoder.decode(typeAsUInt32)) 174 return false; 175 176 type = static_cast<WebKitNSType>(typeAsUInt32); 177 178 switch (type) { 179 case NSStringType: { 180 RetainPtr<NSString> string; 181 if (!CoreIPC::decode(decoder, string)) 182 return false; 183 coder.m_root = string; 184 break; 185 } 186 case NSArrayType: { 187 uint64_t size; 188 if (!decoder.decode(size)) 189 return false; 190 191 RetainPtr<NSMutableArray> array = adoptNS([[NSMutableArray alloc] initWithCapacity:size]); 192 for (uint64_t i = 0; i < size; ++i) { 193 RetainPtr<id> value; 194 Owner messageCoder(coder, value); 195 if (!decoder.decode(messageCoder)) 196 return false; 197 198 [array.get() addObject:value.get()]; 199 } 200 201 coder.m_root = array; 202 break; 203 } 204 case NSDictionaryType: { 205 uint64_t size; 206 if (!decoder.decode(size)) 207 return false; 208 209 RetainPtr<NSMutableDictionary> dictionary = adoptNS([[NSMutableDictionary alloc] initWithCapacity:size]); 210 for (uint64_t i = 0; i < size; ++i) { 211 // Try to decode the key name. 212 RetainPtr<id> key; 213 Owner keyMessageCoder(coder, key); 214 if (!decoder.decode(keyMessageCoder)) 215 return false; 216 217 RetainPtr<id> value; 218 Owner valueMessageCoder(coder, value); 219 if (!decoder.decode(valueMessageCoder)) 220 return false; 221 222 [dictionary.get() setObject:value.get() forKey:key.get()]; 223 } 224 225 coder.m_root = dictionary; 226 break; 227 } 228 case NSNumberType: { 229 RetainPtr<NSNumber> number; 230 if (!CoreIPC::decode(decoder, number)) 231 return false; 232 coder.m_root = number; 233 break; 234 } 235 case NSDateType: { 236 RetainPtr<NSDate> date; 237 if (!CoreIPC::decode(decoder, date)) 238 return false; 239 coder.m_root = date; 240 break; 241 } 242 case NSDataType: { 243 RetainPtr<NSData> data; 244 if (!CoreIPC::decode(decoder, data)) 245 return false; 246 coder.m_root = data; 247 break; 248 } 249 default: 250 break; 251 } 252 253 return true; 254 } 255 256protected: 257 ObjCObjectGraphDecoder(RetainPtr<id>& root) 258 : m_root(root) 259 { 260 } 261 262 RetainPtr<id>& m_root; 263}; 264 265 266// WebContext Additions 267 268class WebContextObjCObjectGraphEncoderImpl : public ObjCObjectGraphEncoder<WebContextObjCObjectGraphEncoderImpl> { 269public: 270 typedef ObjCObjectGraphEncoder<WebContextObjCObjectGraphEncoderImpl> Base; 271 272 explicit WebContextObjCObjectGraphEncoderImpl(id root) 273 : Base(root) 274 { 275 } 276 277 void encode(CoreIPC::ArgumentEncoder& encoder) const 278 { 279 WebKitNSType type = NullType; 280 if (baseEncode(encoder, type)) 281 return; 282 283 switch (type) { 284#if defined(__LP64__) && defined(__clang__) 285 case WKBrowsingContextControllerType: { 286 WKBrowsingContextController *browsingContextController = static_cast<WKBrowsingContextController *>(m_root); 287 288 encoder << toImpl(browsingContextController._pageRef)->pageID(); 289 break; 290 } 291 case WKTypeRefWrapperType: { 292 WKTypeRefWrapper *wrapper = static_cast<WKTypeRefWrapper *>(m_root); 293 encoder << WebContextUserMessageEncoder(toImpl(wrapper.object)); 294 break; 295 } 296#endif 297 default: 298 ASSERT_NOT_REACHED(); 299 break; 300 } 301 } 302}; 303 304 305class WebContextObjCObjectGraphDecoderImpl : public ObjCObjectGraphDecoder<WebContextObjCObjectGraphDecoderImpl> { 306public: 307 typedef ObjCObjectGraphDecoder<WebContextObjCObjectGraphDecoderImpl> Base; 308 309 WebContextObjCObjectGraphDecoderImpl(RetainPtr<id>& root, WebProcessProxy* process) 310 : Base(root) 311 , m_process(process) 312 { 313 } 314 315 WebContextObjCObjectGraphDecoderImpl(WebContextObjCObjectGraphDecoderImpl& userMessageDecoder, RetainPtr<id>& root) 316 : Base(root) 317 , m_process(userMessageDecoder.m_process) 318 { 319 } 320 321 static bool decode(CoreIPC::ArgumentDecoder& decoder, WebContextObjCObjectGraphDecoderImpl& coder) 322 { 323 WebKitNSType type = NullType; 324 if (!Base::baseDecode(decoder, coder, type)) 325 return false; 326 327 if (coder.m_root) 328 return true; 329 330 if (type == NullType || type == UnknownType) { 331 coder.m_root = [NSNull null]; 332 return true; 333 } 334 335 switch (type) { 336#if defined(__LP64__) && defined(__clang__) 337 case WKBrowsingContextControllerType: { 338 uint64_t pageID; 339 if (!decoder.decode(pageID)) 340 return false; 341 342 WebPageProxy* webPage = coder.m_process->webPage(pageID); 343 if (!webPage) 344 coder.m_root = [NSNull null]; 345 else 346 coder.m_root = [WKBrowsingContextController _browsingContextControllerForPageRef:toAPI(webPage)]; 347 break; 348 } 349 case WKTypeRefWrapperType: { 350 RefPtr<APIObject> object; 351 WebContextUserMessageDecoder objectDecoder(object, coder.m_process); 352 if (!decoder.decode(objectDecoder)) 353 return false; 354 coder.m_root = adoptNS([[WKTypeRefWrapper alloc] initWithObject:toAPI(object.get())]); 355 break; 356 } 357#endif 358 default: 359 return false; 360 } 361 362 return true; 363 } 364 365private: 366 WebProcessProxy* m_process; 367}; 368 369 370// InjectedBundle Additions 371 372class InjectedBundleObjCObjectGraphEncoderImpl : public ObjCObjectGraphEncoder<InjectedBundleObjCObjectGraphEncoderImpl> { 373public: 374 typedef ObjCObjectGraphEncoder<InjectedBundleObjCObjectGraphEncoderImpl> Base; 375 376 explicit InjectedBundleObjCObjectGraphEncoderImpl(id root) 377 : Base(root) 378 { 379 } 380 381 void encode(CoreIPC::ArgumentEncoder& encoder) const 382 { 383 WebKitNSType type = NullType; 384 if (baseEncode(encoder, type)) 385 return; 386 387 switch (type) { 388#if defined(__LP64__) && defined(__clang__) 389 case WKBrowsingContextControllerType: { 390 WKWebProcessPlugInBrowserContextController *browserContextController = static_cast<WKWebProcessPlugInBrowserContextController *>(m_root); 391 392 encoder << toImpl(browserContextController._bundlePageRef)->pageID(); 393 break; 394 } 395 case WKTypeRefWrapperType: { 396 WKTypeRefWrapper *wrapper = static_cast<WKTypeRefWrapper *>(m_root); 397 encoder << InjectedBundleUserMessageEncoder(toImpl(wrapper.object)); 398 } 399#endif 400 default: 401 ASSERT_NOT_REACHED(); 402 break; 403 } 404 } 405}; 406 407class InjectedBundleObjCObjectGraphDecoderImpl : public ObjCObjectGraphDecoder<InjectedBundleObjCObjectGraphDecoderImpl> { 408public: 409 typedef ObjCObjectGraphDecoder<InjectedBundleObjCObjectGraphDecoderImpl> Base; 410 411 InjectedBundleObjCObjectGraphDecoderImpl(RetainPtr<id>& root, WebProcess* process) 412 : Base(root) 413 , m_process(process) 414 { 415 } 416 417 InjectedBundleObjCObjectGraphDecoderImpl(InjectedBundleObjCObjectGraphDecoderImpl& userMessageDecoder, RetainPtr<id>& root) 418 : Base(root) 419 , m_process(userMessageDecoder.m_process) 420 { 421 } 422 423 static bool decode(CoreIPC::ArgumentDecoder& decoder, InjectedBundleObjCObjectGraphDecoderImpl& coder) 424 { 425 WebKitNSType type = NullType; 426 if (!Base::baseDecode(decoder, coder, type)) 427 return false; 428 429 if (coder.m_root) 430 return true; 431 432 if (type == NullType || type == UnknownType) { 433 coder.m_root = [NSNull null]; 434 return true; 435 } 436 437 switch (type) { 438#if defined(__LP64__) && defined(__clang__) 439 case WKBrowsingContextControllerType: { 440 uint64_t pageID; 441 if (!decoder.decode(pageID)) 442 return false; 443 444 WebPage* webPage = coder.m_process->webPage(pageID); 445 if (!webPage) 446 coder.m_root = [NSNull null]; 447 else 448 coder.m_root = [[WKWebProcessPlugInController _shared] _browserContextControllerForBundlePageRef:toAPI(webPage)]; 449 break; 450 } 451 case WKTypeRefWrapperType: { 452 RefPtr<APIObject> object; 453 InjectedBundleUserMessageDecoder objectDecoder(object); 454 if (!decoder.decode(objectDecoder)) 455 return false; 456 coder.m_root = adoptNS([[WKTypeRefWrapper alloc] initWithObject:toAPI(object.get())]); 457 break; 458 } 459#endif 460 default: 461 return false; 462 } 463 464 return true; 465 } 466 467private: 468 WebProcess* m_process; 469}; 470 471 472// Adaptors 473 474WebContextObjCObjectGraphEncoder::WebContextObjCObjectGraphEncoder(ObjCObjectGraph* objectGraph) 475 : m_objectGraph(objectGraph) 476{ 477} 478 479void WebContextObjCObjectGraphEncoder::encode(CoreIPC::ArgumentEncoder& encoder) const 480{ 481 encoder << WebContextObjCObjectGraphEncoderImpl(m_objectGraph->rootObject()); 482} 483 484WebContextObjCObjectGraphDecoder::WebContextObjCObjectGraphDecoder(RefPtr<ObjCObjectGraph>& objectGraph, WebProcessProxy* process) 485 : m_objectGraph(objectGraph) 486 , m_process(process) 487{ 488} 489 490bool WebContextObjCObjectGraphDecoder::decode(CoreIPC::ArgumentDecoder& decoder, WebContextObjCObjectGraphDecoder& coder) 491{ 492 RetainPtr<id> root; 493 WebContextObjCObjectGraphDecoderImpl coderImpl(root, coder.m_process); 494 if (!decoder.decode(coderImpl)) 495 return false; 496 497 coder.m_objectGraph = ObjCObjectGraph::create(root.get()); 498 return true; 499} 500 501InjectedBundleObjCObjectGraphEncoder::InjectedBundleObjCObjectGraphEncoder(ObjCObjectGraph* objectGraph) 502 : m_objectGraph(objectGraph) 503{ 504} 505 506void InjectedBundleObjCObjectGraphEncoder::encode(CoreIPC::ArgumentEncoder& encoder) const 507{ 508 encoder << InjectedBundleObjCObjectGraphEncoderImpl(m_objectGraph->rootObject()); 509} 510 511InjectedBundleObjCObjectGraphDecoder::InjectedBundleObjCObjectGraphDecoder(RefPtr<ObjCObjectGraph>& objectGraph, WebProcess* process) 512 : m_objectGraph(objectGraph) 513 , m_process(process) 514{ 515} 516 517bool InjectedBundleObjCObjectGraphDecoder::decode(CoreIPC::ArgumentDecoder& decoder, InjectedBundleObjCObjectGraphDecoder& coder) 518{ 519 RetainPtr<id> root; 520 InjectedBundleObjCObjectGraphDecoderImpl coderImpl(root, coder.m_process); 521 if (!decoder.decode(coderImpl)) 522 return false; 523 524 coder.m_objectGraph = ObjCObjectGraph::create(root.get()); 525 return true; 526} 527 528} // namespace WebKit 529