1/* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2013 Company 100 Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 18 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 24 * THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#import "config.h" 28#import "WebCoreArgumentCoders.h" 29 30#import "ArgumentCodersCF.h" 31#import "DataReference.h" 32#import "WebKitSystemInterface.h" 33#import <WebCore/CertificateInfo.h> 34#import <WebCore/ContentFilter.h> 35#import <WebCore/KeyboardEvent.h> 36#import <WebCore/ProtectionSpace.h> 37#import <WebCore/ResourceError.h> 38#import <WebCore/ResourceRequest.h> 39 40#if USE(CFNETWORK) 41#import <CFNetwork/CFURLRequest.h> 42#endif 43 44using namespace WebCore; 45 46namespace IPC { 47 48#if USE(CFNETWORK) 49void ArgumentCoder<ResourceRequest>::encodePlatformData(ArgumentEncoder& encoder, const ResourceRequest& resourceRequest) 50{ 51 RetainPtr<CFURLRequestRef> requestToSerialize = resourceRequest.cfURLRequest(DoNotUpdateHTTPBody); 52 53 bool requestIsPresent = requestToSerialize; 54 encoder << requestIsPresent; 55 56 if (!requestIsPresent) 57 return; 58 59 // We don't send HTTP body over IPC for better performance. 60 // Also, it's not always possible to do, as streams can only be created in process that does networking. 61 RetainPtr<CFDataRef> requestHTTPBody = adoptCF(CFURLRequestCopyHTTPRequestBody(requestToSerialize.get())); 62 RetainPtr<CFReadStreamRef> requestHTTPBodyStream = adoptCF(CFURLRequestCopyHTTPRequestBodyStream(requestToSerialize.get())); 63 if (requestHTTPBody || requestHTTPBodyStream) { 64 CFMutableURLRequestRef mutableRequest = CFURLRequestCreateMutableCopy(0, requestToSerialize.get()); 65 requestToSerialize = adoptCF(mutableRequest); 66 CFURLRequestSetHTTPRequestBody(mutableRequest, nil); 67 CFURLRequestSetHTTPRequestBodyStream(mutableRequest, nil); 68 } 69 70 RetainPtr<CFDictionaryRef> dictionary = adoptCF(WKCFURLRequestCreateSerializableRepresentation(requestToSerialize.get(), IPC::tokenNullTypeRef())); 71 IPC::encode(encoder, dictionary.get()); 72 73 // The fallback array is part of CFURLRequest, but it is not encoded by WKCFURLRequestCreateSerializableRepresentation. 74 encoder << resourceRequest.responseContentDispositionEncodingFallbackArray(); 75} 76#else 77void ArgumentCoder<ResourceRequest>::encodePlatformData(ArgumentEncoder& encoder, const ResourceRequest& resourceRequest) 78{ 79 RetainPtr<NSURLRequest> requestToSerialize = resourceRequest.nsURLRequest(DoNotUpdateHTTPBody); 80 81 bool requestIsPresent = requestToSerialize; 82 encoder << requestIsPresent; 83 84 if (!requestIsPresent) 85 return; 86 87 // We don't send HTTP body over IPC for better performance. 88 // Also, it's not always possible to do, as streams can only be created in process that does networking. 89 if ([requestToSerialize HTTPBody] || [requestToSerialize HTTPBodyStream]) { 90 requestToSerialize = adoptNS([requestToSerialize mutableCopy]); 91 [(NSMutableURLRequest *)requestToSerialize setHTTPBody:nil]; 92 [(NSMutableURLRequest *)requestToSerialize setHTTPBodyStream:nil]; 93 } 94 95 RetainPtr<CFDictionaryRef> dictionary = adoptCF(WKNSURLRequestCreateSerializableRepresentation(requestToSerialize.get(), IPC::tokenNullTypeRef())); 96 IPC::encode(encoder, dictionary.get()); 97 98 // The fallback array is part of NSURLRequest, but it is not encoded by WKNSURLRequestCreateSerializableRepresentation. 99 encoder << resourceRequest.responseContentDispositionEncodingFallbackArray(); 100} 101#endif 102 103bool ArgumentCoder<ResourceRequest>::decodePlatformData(ArgumentDecoder& decoder, ResourceRequest& resourceRequest) 104{ 105 bool requestIsPresent; 106 if (!decoder.decode(requestIsPresent)) 107 return false; 108 109 if (!requestIsPresent) { 110 resourceRequest = ResourceRequest(); 111 return true; 112 } 113 114 RetainPtr<CFDictionaryRef> dictionary; 115 if (!IPC::decode(decoder, dictionary)) 116 return false; 117 118#if USE(CFNETWORK) 119 RetainPtr<CFURLRequestRef> cfURLRequest = adoptCF(WKCreateCFURLRequestFromSerializableRepresentation(dictionary.get(), IPC::tokenNullTypeRef())); 120 if (!cfURLRequest) 121 return false; 122 123 resourceRequest = ResourceRequest(cfURLRequest.get()); 124#else 125 RetainPtr<NSURLRequest> nsURLRequest = WKNSURLRequestFromSerializableRepresentation(dictionary.get(), IPC::tokenNullTypeRef()); 126 if (!nsURLRequest) 127 return false; 128 129 resourceRequest = ResourceRequest(nsURLRequest.get()); 130#endif 131 132 Vector<String> responseContentDispositionEncodingFallbackArray; 133 if (!decoder.decode(responseContentDispositionEncodingFallbackArray)) 134 return false; 135 136 resourceRequest.setResponseContentDispositionEncodingFallbackArray( 137 responseContentDispositionEncodingFallbackArray.size() > 0 ? responseContentDispositionEncodingFallbackArray[0] : String(), 138 responseContentDispositionEncodingFallbackArray.size() > 1 ? responseContentDispositionEncodingFallbackArray[1] : String(), 139 responseContentDispositionEncodingFallbackArray.size() > 2 ? responseContentDispositionEncodingFallbackArray[2] : String() 140 ); 141 142 return true; 143} 144 145void ArgumentCoder<ResourceResponse>::encodePlatformData(ArgumentEncoder& encoder, const ResourceResponse& resourceResponse) 146{ 147 bool responseIsPresent = resourceResponse.platformResponseIsUpToDate() && resourceResponse.nsURLResponse(); 148 encoder << responseIsPresent; 149 150 if (!responseIsPresent) 151 return; 152 153 RetainPtr<CFDictionaryRef> dictionary = adoptCF(WKNSURLResponseCreateSerializableRepresentation(resourceResponse.nsURLResponse(), IPC::tokenNullTypeRef())); 154 IPC::encode(encoder, dictionary.get()); 155} 156 157bool ArgumentCoder<ResourceResponse>::decodePlatformData(ArgumentDecoder& decoder, ResourceResponse& resourceResponse) 158{ 159 bool responseIsPresent; 160 if (!decoder.decode(responseIsPresent)) 161 return false; 162 163 if (!responseIsPresent) { 164 resourceResponse = ResourceResponse(); 165 return true; 166 } 167 168 RetainPtr<CFDictionaryRef> dictionary; 169 if (!IPC::decode(decoder, dictionary)) 170 return false; 171 172 RetainPtr<NSURLResponse> nsURLResponse = WKNSURLResponseFromSerializableRepresentation(dictionary.get(), IPC::tokenNullTypeRef()); 173 174 if (!nsURLResponse) 175 return false; 176 177 resourceResponse = ResourceResponse(nsURLResponse.get()); 178 return true; 179} 180 181void ArgumentCoder<CertificateInfo>::encode(ArgumentEncoder& encoder, const CertificateInfo& certificateInfo) 182{ 183 CFArrayRef certificateChain = certificateInfo.certificateChain(); 184 if (!certificateChain) { 185 encoder << false; 186 return; 187 } 188 189 encoder << true; 190 IPC::encode(encoder, certificateChain); 191} 192 193bool ArgumentCoder<CertificateInfo>::decode(ArgumentDecoder& decoder, CertificateInfo& certificateInfo) 194{ 195 bool hasCertificateChain; 196 if (!decoder.decode(hasCertificateChain)) 197 return false; 198 199 if (!hasCertificateChain) 200 return true; 201 202 RetainPtr<CFArrayRef> certificateChain; 203 if (!IPC::decode(decoder, certificateChain)) 204 return false; 205 206 certificateInfo.setCertificateChain(certificateChain.get()); 207 208 return true; 209} 210 211void ArgumentCoder<ResourceError>::encodePlatformData(ArgumentEncoder& encoder, const ResourceError& resourceError) 212{ 213 bool errorIsNull = resourceError.isNull(); 214 encoder << errorIsNull; 215 216 if (errorIsNull) 217 return; 218 219 NSError *nsError = resourceError.nsError(); 220 221 String domain = [nsError domain]; 222 encoder << domain; 223 224 int64_t code = [nsError code]; 225 encoder << code; 226 227 NSDictionary *userInfo = [nsError userInfo]; 228 229 RetainPtr<CFMutableDictionaryRef> filteredUserInfo = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, userInfo.count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); 230 231 [userInfo enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL*) { 232 if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSURL class]]) 233 CFDictionarySetValue(filteredUserInfo.get(), key, value); 234 }]; 235 236 IPC::encode(encoder, filteredUserInfo.get()); 237 238 id peerCertificateChain = [userInfo objectForKey:@"NSErrorPeerCertificateChainKey"]; 239 if (!peerCertificateChain) { 240 if (SecTrustRef peerTrust = (SecTrustRef)[userInfo objectForKey:NSURLErrorFailingURLPeerTrustErrorKey]) { 241 CFIndex count = SecTrustGetCertificateCount(peerTrust); 242 peerCertificateChain = [NSMutableArray arrayWithCapacity:count]; 243 for (CFIndex i = 0; i < count; ++i) 244 [peerCertificateChain addObject:(id)SecTrustGetCertificateAtIndex(peerTrust, i)]; 245 } 246 } 247 ASSERT(!peerCertificateChain || [peerCertificateChain isKindOfClass:[NSArray class]]); 248 encoder << CertificateInfo((CFArrayRef)peerCertificateChain); 249} 250 251bool ArgumentCoder<ResourceError>::decodePlatformData(ArgumentDecoder& decoder, ResourceError& resourceError) 252{ 253 bool errorIsNull; 254 if (!decoder.decode(errorIsNull)) 255 return false; 256 257 if (errorIsNull) { 258 resourceError = ResourceError(); 259 return true; 260 } 261 262 String domain; 263 if (!decoder.decode(domain)) 264 return false; 265 266 int64_t code; 267 if (!decoder.decode(code)) 268 return false; 269 270 RetainPtr<CFDictionaryRef> userInfo; 271 if (!IPC::decode(decoder, userInfo)) 272 return false; 273 274 CertificateInfo certificate; 275 if (!decoder.decode(certificate)) 276 return false; 277 278 if (certificate.certificateChain()) { 279 userInfo = adoptCF(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(userInfo.get()) + 1, userInfo.get())); 280 CFDictionarySetValue((CFMutableDictionaryRef)userInfo.get(), CFSTR("NSErrorPeerCertificateChainKey"), (CFArrayRef)certificate.certificateChain()); 281 } 282 283 RetainPtr<NSError> nsError = adoptNS([[NSError alloc] initWithDomain:domain code:code userInfo:(NSDictionary *)userInfo.get()]); 284 285 resourceError = ResourceError(nsError.get()); 286 return true; 287} 288 289void ArgumentCoder<ProtectionSpace>::encodePlatformData(ArgumentEncoder& encoder, const ProtectionSpace& space) 290{ 291 RetainPtr<NSMutableData> data = adoptNS([[NSMutableData alloc] init]); 292 RetainPtr<NSKeyedArchiver> archiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]); 293 [archiver setRequiresSecureCoding:YES]; 294 [archiver encodeObject:space.nsSpace() forKey:@"protectionSpace"]; 295 [archiver finishEncoding]; 296 IPC::encode(encoder, reinterpret_cast<CFDataRef>(data.get())); 297} 298 299bool ArgumentCoder<ProtectionSpace>::decodePlatformData(ArgumentDecoder& decoder, ProtectionSpace& space) 300{ 301 RetainPtr<CFDataRef> data; 302 if (!IPC::decode(decoder, data)) 303 return false; 304 305 RetainPtr<NSKeyedUnarchiver> unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)data.get()]); 306 [unarchiver setRequiresSecureCoding:YES]; 307 @try { 308 if (RetainPtr<NSURLProtectionSpace> nsSpace = [unarchiver decodeObjectOfClass:[NSURLProtectionSpace class] forKey:@"protectionSpace"]) 309 space = ProtectionSpace(nsSpace.get()); 310 } @catch (NSException *exception) { 311 LOG_ERROR("Failed to decode NSURLProtectionSpace: %@", exception); 312 } 313 314 [unarchiver finishDecoding]; 315 return true; 316} 317 318void ArgumentCoder<KeypressCommand>::encode(ArgumentEncoder& encoder, const KeypressCommand& keypressCommand) 319{ 320 encoder << keypressCommand.commandName << keypressCommand.text; 321} 322 323bool ArgumentCoder<KeypressCommand>::decode(ArgumentDecoder& decoder, KeypressCommand& keypressCommand) 324{ 325 if (!decoder.decode(keypressCommand.commandName)) 326 return false; 327 328 if (!decoder.decode(keypressCommand.text)) 329 return false; 330 331 return true; 332} 333 334void ArgumentCoder<ContentFilter>::encode(ArgumentEncoder& encoder, const ContentFilter& contentFilter) 335{ 336 RetainPtr<NSMutableData> data = adoptNS([[NSMutableData alloc] init]); 337 RetainPtr<NSKeyedArchiver> archiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]); 338 [archiver setRequiresSecureCoding:YES]; 339 contentFilter.encode(archiver.get()); 340 [archiver finishEncoding]; 341 IPC::encode(encoder, reinterpret_cast<CFDataRef>(data.get())); 342} 343 344bool ArgumentCoder<ContentFilter>::decode(ArgumentDecoder& decoder, ContentFilter& contentFilter) 345{ 346 RetainPtr<CFDataRef> data; 347 if (!IPC::decode(decoder, data)) 348 return false; 349 350 RetainPtr<NSKeyedUnarchiver> unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)data.get()]); 351 [unarchiver setRequiresSecureCoding:YES]; 352 if (!ContentFilter::decode(unarchiver.get(), contentFilter)) 353 return false; 354 355 [unarchiver finishDecoding]; 356 return true; 357} 358 359} // namespace IPC 360