[Mac] Update AirPlay handling
[WebKit-https.git] / Source / WebKit2 / Shared / mac / WebCoreArgumentCodersMac.mm
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/ContentFilterUnblockHandler.h>
35 #import <WebCore/Credential.h>
36 #import <WebCore/KeyboardEvent.h>
37 #import <WebCore/MachSendRight.h>
38 #import <WebCore/ProtectionSpace.h>
39 #import <WebCore/ResourceError.h>
40 #import <WebCore/ResourceRequest.h>
41 #import <WebCore/SoftLinking.h>
42 #import <objc/runtime.h>
43
44 #if USE(CFNETWORK)
45 #import <CFNetwork/CFURLRequest.h>
46 #endif
47
48 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
49 #import <WebCore/MediaPlaybackTarget.h>
50 #endif
51
52 using namespace WebCore;
53
54 namespace IPC {
55
56 #if USE(CFNETWORK)
57 void ArgumentCoder<ResourceRequest>::encodePlatformData(ArgumentEncoder& encoder, const ResourceRequest& resourceRequest)
58 {
59     RetainPtr<CFURLRequestRef> requestToSerialize = resourceRequest.cfURLRequest(DoNotUpdateHTTPBody);
60
61     bool requestIsPresent = requestToSerialize;
62     encoder << requestIsPresent;
63
64     if (!requestIsPresent)
65         return;
66
67     // We don't send HTTP body over IPC for better performance.
68     // Also, it's not always possible to do, as streams can only be created in process that does networking.
69     RetainPtr<CFDataRef> requestHTTPBody = adoptCF(CFURLRequestCopyHTTPRequestBody(requestToSerialize.get()));
70     RetainPtr<CFReadStreamRef> requestHTTPBodyStream = adoptCF(CFURLRequestCopyHTTPRequestBodyStream(requestToSerialize.get()));
71     if (requestHTTPBody || requestHTTPBodyStream) {
72         CFMutableURLRequestRef mutableRequest = CFURLRequestCreateMutableCopy(0, requestToSerialize.get());
73         requestToSerialize = adoptCF(mutableRequest);
74         CFURLRequestSetHTTPRequestBody(mutableRequest, nil);
75         CFURLRequestSetHTTPRequestBodyStream(mutableRequest, nil);
76     }
77
78     RetainPtr<CFDictionaryRef> dictionary = adoptCF(WKCFURLRequestCreateSerializableRepresentation(requestToSerialize.get(), IPC::tokenNullTypeRef()));
79     IPC::encode(encoder, dictionary.get());
80
81     // The fallback array is part of CFURLRequest, but it is not encoded by WKCFURLRequestCreateSerializableRepresentation.
82     encoder << resourceRequest.responseContentDispositionEncodingFallbackArray();
83 }
84 #else
85 void ArgumentCoder<ResourceRequest>::encodePlatformData(ArgumentEncoder& encoder, const ResourceRequest& resourceRequest)
86 {
87     RetainPtr<NSURLRequest> requestToSerialize = resourceRequest.nsURLRequest(DoNotUpdateHTTPBody);
88
89     bool requestIsPresent = requestToSerialize;
90     encoder << requestIsPresent;
91
92     if (!requestIsPresent)
93         return;
94
95     // We don't send HTTP body over IPC for better performance.
96     // Also, it's not always possible to do, as streams can only be created in process that does networking.
97     if ([requestToSerialize HTTPBody] || [requestToSerialize HTTPBodyStream]) {
98         requestToSerialize = adoptNS([requestToSerialize mutableCopy]);
99         [(NSMutableURLRequest *)requestToSerialize setHTTPBody:nil];
100         [(NSMutableURLRequest *)requestToSerialize setHTTPBodyStream:nil];
101     }
102
103     RetainPtr<CFDictionaryRef> dictionary = adoptCF(WKNSURLRequestCreateSerializableRepresentation(requestToSerialize.get(), IPC::tokenNullTypeRef()));
104     IPC::encode(encoder, dictionary.get());
105
106     // The fallback array is part of NSURLRequest, but it is not encoded by WKNSURLRequestCreateSerializableRepresentation.
107     encoder << resourceRequest.responseContentDispositionEncodingFallbackArray();
108 }
109 #endif
110
111 bool ArgumentCoder<ResourceRequest>::decodePlatformData(ArgumentDecoder& decoder, ResourceRequest& resourceRequest)
112 {
113     bool requestIsPresent;
114     if (!decoder.decode(requestIsPresent))
115         return false;
116
117     if (!requestIsPresent) {
118         resourceRequest = ResourceRequest();
119         return true;
120     }
121
122     RetainPtr<CFDictionaryRef> dictionary;
123     if (!IPC::decode(decoder, dictionary))
124         return false;
125
126 #if USE(CFNETWORK)
127     RetainPtr<CFURLRequestRef> cfURLRequest = adoptCF(WKCreateCFURLRequestFromSerializableRepresentation(dictionary.get(), IPC::tokenNullTypeRef()));
128     if (!cfURLRequest)
129         return false;
130
131     resourceRequest = ResourceRequest(cfURLRequest.get());
132 #else
133     RetainPtr<NSURLRequest> nsURLRequest = WKNSURLRequestFromSerializableRepresentation(dictionary.get(), IPC::tokenNullTypeRef());
134     if (!nsURLRequest)
135         return false;
136
137     resourceRequest = ResourceRequest(nsURLRequest.get());
138 #endif
139     
140     Vector<String> responseContentDispositionEncodingFallbackArray;
141     if (!decoder.decode(responseContentDispositionEncodingFallbackArray))
142         return false;
143
144     resourceRequest.setResponseContentDispositionEncodingFallbackArray(
145         responseContentDispositionEncodingFallbackArray.size() > 0 ? responseContentDispositionEncodingFallbackArray[0] : String(),
146         responseContentDispositionEncodingFallbackArray.size() > 1 ? responseContentDispositionEncodingFallbackArray[1] : String(),
147         responseContentDispositionEncodingFallbackArray.size() > 2 ? responseContentDispositionEncodingFallbackArray[2] : String()
148     );
149
150     return true;
151 }
152
153 void ArgumentCoder<CertificateInfo>::encode(ArgumentEncoder& encoder, const CertificateInfo& certificateInfo)
154 {
155     CFArrayRef certificateChain = certificateInfo.certificateChain();
156     if (!certificateChain) {
157         encoder << false;
158         return;
159     }
160
161     encoder << true;
162     IPC::encode(encoder, certificateChain);
163 }
164
165 bool ArgumentCoder<CertificateInfo>::decode(ArgumentDecoder& decoder, CertificateInfo& certificateInfo)
166 {
167     bool hasCertificateChain;
168     if (!decoder.decode(hasCertificateChain))
169         return false;
170
171     if (!hasCertificateChain)
172         return true;
173
174     RetainPtr<CFArrayRef> certificateChain;
175     if (!IPC::decode(decoder, certificateChain))
176         return false;
177
178     certificateInfo.setCertificateChain(certificateChain.get());
179
180     return true;
181 }
182
183 void ArgumentCoder<ResourceError>::encodePlatformData(ArgumentEncoder& encoder, const ResourceError& resourceError)
184 {
185     bool errorIsNull = resourceError.isNull();
186     encoder << errorIsNull;
187
188     if (errorIsNull)
189         return;
190
191     NSError *nsError = resourceError.nsError();
192
193     String domain = [nsError domain];
194     encoder << domain;
195
196     int64_t code = [nsError code];
197     encoder << code;
198
199     NSDictionary *userInfo = [nsError userInfo];
200
201     RetainPtr<CFMutableDictionaryRef> filteredUserInfo = adoptCF(CFDictionaryCreateMutable(kCFAllocatorDefault, userInfo.count, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
202
203     [userInfo enumerateKeysAndObjectsUsingBlock:^(id key, id value, BOOL*) {
204         if ([value isKindOfClass:[NSString class]] || [value isKindOfClass:[NSURL class]])
205             CFDictionarySetValue(filteredUserInfo.get(), key, value);
206     }];
207
208     if (NSArray *clientIdentityAndCertificates = [userInfo objectForKey:@"NSErrorClientCertificateChainKey"]) {
209         ASSERT([clientIdentityAndCertificates isKindOfClass:[NSArray class]]);
210         ASSERT(^{
211             for (id object in clientIdentityAndCertificates) {
212                 if (CFGetTypeID(object) != SecIdentityGetTypeID() && CFGetTypeID(object) != SecCertificateGetTypeID())
213                     return false;
214             }
215             return true;
216         }());
217
218         CFDictionarySetValue(filteredUserInfo.get(), @"NSErrorClientCertificateChainKey", clientIdentityAndCertificates);
219     };
220
221     IPC::encode(encoder, filteredUserInfo.get());
222
223     id peerCertificateChain = [userInfo objectForKey:@"NSErrorPeerCertificateChainKey"];
224     if (!peerCertificateChain) {
225         if (SecTrustRef peerTrust = (SecTrustRef)[userInfo objectForKey:NSURLErrorFailingURLPeerTrustErrorKey]) {
226             CFIndex count = SecTrustGetCertificateCount(peerTrust);
227             peerCertificateChain = [NSMutableArray arrayWithCapacity:count];
228             for (CFIndex i = 0; i < count; ++i)
229                 [peerCertificateChain addObject:(id)SecTrustGetCertificateAtIndex(peerTrust, i)];
230         }
231     }
232     ASSERT(!peerCertificateChain || [peerCertificateChain isKindOfClass:[NSArray class]]);
233     encoder << CertificateInfo((CFArrayRef)peerCertificateChain);
234 }
235
236 bool ArgumentCoder<ResourceError>::decodePlatformData(ArgumentDecoder& decoder, ResourceError& resourceError)
237 {
238     bool errorIsNull;
239     if (!decoder.decode(errorIsNull))
240         return false;
241     
242     if (errorIsNull) {
243         resourceError = ResourceError();
244         return true;
245     }
246
247     String domain;
248     if (!decoder.decode(domain))
249         return false;
250
251     int64_t code;
252     if (!decoder.decode(code))
253         return false;
254
255     RetainPtr<CFDictionaryRef> userInfo;
256     if (!IPC::decode(decoder, userInfo))
257         return false;
258
259     CertificateInfo certificate;
260     if (!decoder.decode(certificate))
261         return false;
262
263     if (certificate.certificateChain()) {
264         userInfo = adoptCF(CFDictionaryCreateMutableCopy(kCFAllocatorDefault, CFDictionaryGetCount(userInfo.get()) + 1, userInfo.get()));
265         CFDictionarySetValue((CFMutableDictionaryRef)userInfo.get(), CFSTR("NSErrorPeerCertificateChainKey"), (CFArrayRef)certificate.certificateChain());
266     }
267
268     RetainPtr<NSError> nsError = adoptNS([[NSError alloc] initWithDomain:domain code:code userInfo:(NSDictionary *)userInfo.get()]);
269
270     resourceError = ResourceError(nsError.get());
271     return true;
272 }
273
274 void ArgumentCoder<ProtectionSpace>::encodePlatformData(ArgumentEncoder& encoder, const ProtectionSpace& space)
275 {
276     RetainPtr<NSMutableData> data = adoptNS([[NSMutableData alloc] init]);
277     RetainPtr<NSKeyedArchiver> archiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
278     [archiver setRequiresSecureCoding:YES];
279     [archiver encodeObject:space.nsSpace() forKey:@"protectionSpace"];
280     [archiver finishEncoding];
281     IPC::encode(encoder, reinterpret_cast<CFDataRef>(data.get()));
282 }
283
284 bool ArgumentCoder<ProtectionSpace>::decodePlatformData(ArgumentDecoder& decoder, ProtectionSpace& space)
285 {
286     RetainPtr<CFDataRef> data;
287     if (!IPC::decode(decoder, data))
288         return false;
289
290     RetainPtr<NSKeyedUnarchiver> unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)data.get()]);
291     [unarchiver setRequiresSecureCoding:YES];
292     @try {
293         if (RetainPtr<NSURLProtectionSpace> nsSpace = [unarchiver decodeObjectOfClass:[NSURLProtectionSpace class] forKey:@"protectionSpace"])
294             space = ProtectionSpace(nsSpace.get());
295     } @catch (NSException *exception) {
296         LOG_ERROR("Failed to decode NSURLProtectionSpace: %@", exception);
297     }
298
299     [unarchiver finishDecoding];
300     return true;
301 }
302
303 void ArgumentCoder<Credential>::encodePlatformData(ArgumentEncoder& encoder, const Credential& credential)
304 {
305     NSURLCredential *nsCredential = credential.nsCredential();
306     // NSURLCredential doesn't serialize identities correctly, so we encode the pieces individually
307     // in the identity case. See <rdar://problem/18802434>.
308     if (SecIdentityRef identity = nsCredential.identity) {
309         encoder << true;
310         IPC::encode(encoder, identity);
311
312         if (NSArray *certificates = nsCredential.certificates) {
313             encoder << true;
314             IPC::encode(encoder, reinterpret_cast<CFArrayRef>(certificates));
315         } else
316             encoder << false;
317
318         encoder << static_cast<uint64_t>(nsCredential.persistence);
319         return;
320     }
321
322     encoder << false;
323     RetainPtr<NSMutableData> data = adoptNS([[NSMutableData alloc] init]);
324     RetainPtr<NSKeyedArchiver> archiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
325     [archiver setRequiresSecureCoding:YES];
326     [archiver encodeObject:nsCredential forKey:@"credential"];
327     [archiver finishEncoding];
328     IPC::encode(encoder, reinterpret_cast<CFDataRef>(data.get()));
329 }
330
331 bool ArgumentCoder<Credential>::decodePlatformData(ArgumentDecoder& decoder, Credential& credential)
332 {
333     bool hasIdentity;
334     if (!decoder.decode(hasIdentity))
335         return false;
336
337     if (hasIdentity) {
338         RetainPtr<SecIdentityRef> identity;
339         if (!IPC::decode(decoder, identity))
340             return false;
341
342         RetainPtr<CFArrayRef> certificates;
343         bool hasCertificates;
344         if (!decoder.decode(hasCertificates))
345             return false;
346
347         if (hasCertificates) {
348             if (!IPC::decode(decoder, certificates))
349                 return false;
350         }
351
352         uint64_t persistence;
353         if (!decoder.decode(persistence))
354             return false;
355
356         credential = Credential(adoptNS([[NSURLCredential alloc] initWithIdentity:identity.get() certificates:(NSArray *)certificates.get() persistence:(NSURLCredentialPersistence)persistence]).get());
357         return true;
358     }
359
360     RetainPtr<CFDataRef> data;
361     if (!IPC::decode(decoder, data))
362         return false;
363
364     RetainPtr<NSKeyedUnarchiver> unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)data.get()]);
365     [unarchiver setRequiresSecureCoding:YES];
366     @try {
367         if (RetainPtr<NSURLCredential> nsCredential = [unarchiver decodeObjectOfClass:[NSURLCredential class] forKey:@"credential"])
368             credential = Credential(nsCredential.get());
369     } @catch (NSException *exception) {
370         LOG_ERROR("Failed to decode NSURLCredential: %@", exception);
371     }
372
373     [unarchiver finishDecoding];
374     return true;
375 }
376
377 void ArgumentCoder<MachSendRight>::encode(ArgumentEncoder& encoder, const MachSendRight& sendRight)
378 {
379     encoder << Attachment(sendRight.copySendRight().leakSendRight(), MACH_MSG_TYPE_MOVE_SEND);
380 }
381
382 void ArgumentCoder<MachSendRight>::encode(ArgumentEncoder& encoder, MachSendRight&& sendRight)
383 {
384     encoder << Attachment(sendRight.leakSendRight(), MACH_MSG_TYPE_MOVE_SEND);
385 }
386
387 bool ArgumentCoder<MachSendRight>::decode(ArgumentDecoder& decoder, MachSendRight& sendRight)
388 {
389     Attachment attachment;
390     if (!decoder.decode(attachment))
391         return false;
392
393     if (attachment.disposition() != MACH_MSG_TYPE_MOVE_SEND)
394         return false;
395
396     sendRight = MachSendRight::adopt(attachment.port());
397     return true;
398 }
399
400 void ArgumentCoder<KeypressCommand>::encode(ArgumentEncoder& encoder, const KeypressCommand& keypressCommand)
401 {
402     encoder << keypressCommand.commandName << keypressCommand.text;
403 }
404     
405 bool ArgumentCoder<KeypressCommand>::decode(ArgumentDecoder& decoder, KeypressCommand& keypressCommand)
406 {
407     if (!decoder.decode(keypressCommand.commandName))
408         return false;
409
410     if (!decoder.decode(keypressCommand.text))
411         return false;
412
413     return true;
414 }
415
416 void ArgumentCoder<ContentFilterUnblockHandler>::encode(ArgumentEncoder& encoder, const ContentFilterUnblockHandler& contentFilterUnblockHandler)
417 {
418     RetainPtr<NSMutableData> data = adoptNS([[NSMutableData alloc] init]);
419     RetainPtr<NSKeyedArchiver> archiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
420     [archiver setRequiresSecureCoding:YES];
421     contentFilterUnblockHandler.encode(archiver.get());
422     [archiver finishEncoding];
423     IPC::encode(encoder, reinterpret_cast<CFDataRef>(data.get()));
424 }
425
426 bool ArgumentCoder<ContentFilterUnblockHandler>::decode(ArgumentDecoder& decoder, ContentFilterUnblockHandler& contentFilterUnblockHandler)
427 {
428     RetainPtr<CFDataRef> data;
429     if (!IPC::decode(decoder, data))
430         return false;
431
432     RetainPtr<NSKeyedUnarchiver> unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)data.get()]);
433     [unarchiver setRequiresSecureCoding:YES];
434     if (!ContentFilterUnblockHandler::decode(unarchiver.get(), contentFilterUnblockHandler))
435         return false;
436
437     [unarchiver finishDecoding];
438     return true;
439 }
440
441 #if ENABLE(WIRELESS_PLAYBACK_TARGET)
442 void ArgumentCoder<MediaPlaybackTarget>::encode(ArgumentEncoder& encoder, const MediaPlaybackTarget& target)
443 {
444     RetainPtr<NSMutableData> data = adoptNS([[NSMutableData alloc] init]);
445     RetainPtr<NSKeyedArchiver> archiver = adoptNS([[NSKeyedArchiver alloc] initForWritingWithMutableData:data.get()]);
446     [archiver setRequiresSecureCoding:YES];
447     target.encode(archiver.get());
448     [archiver finishEncoding];
449     IPC::encode(encoder, reinterpret_cast<CFDataRef>(data.get()));
450 }
451
452 bool ArgumentCoder<MediaPlaybackTarget>::decode(ArgumentDecoder& decoder, MediaPlaybackTarget& target)
453 {
454     RetainPtr<CFDataRef> data;
455     if (!IPC::decode(decoder, data))
456         return false;
457
458     RetainPtr<NSKeyedUnarchiver> unarchiver = adoptNS([[NSKeyedUnarchiver alloc] initForReadingWithData:(NSData *)data.get()]);
459     [unarchiver setRequiresSecureCoding:YES];
460     if (!MediaPlaybackTarget::decode(unarchiver.get(), target))
461         return false;
462     
463     [unarchiver finishDecoding];
464     return true;
465 }
466 #endif
467
468 } // namespace IPC