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 "WebCoreArgumentCoders.h"
28
29#import "ArgumentCodersCF.h"
30#import "PlatformCertificateInfo.h"
31#import "WebKitSystemInterface.h"
32#import <WebCore/KeyboardEvent.h>
33#import <WebCore/ResourceError.h>
34#import <WebCore/ResourceRequest.h>
35
36using namespace WebCore;
37using namespace WebKit;
38
39namespace CoreIPC {
40
41void ArgumentCoder<ResourceRequest>::encodePlatformData(ArgumentEncoder& encoder, const ResourceRequest& resourceRequest)
42{
43    RetainPtr<NSURLRequest> requestToSerialize = resourceRequest.nsURLRequest(DoNotUpdateHTTPBody);
44
45    bool requestIsPresent = requestToSerialize;
46    encoder << requestIsPresent;
47
48    if (!requestIsPresent)
49        return;
50
51    // We don't send HTTP body over IPC for better performance.
52    // Also, it's not always possible to do, as streams can only be created in process that does networking.
53    if ([requestToSerialize.get() HTTPBody] || [requestToSerialize.get() HTTPBodyStream]) {
54        requestToSerialize = adoptNS([requestToSerialize.get() mutableCopy]);
55        [(NSMutableURLRequest *)requestToSerialize.get() setHTTPBody:nil];
56        [(NSMutableURLRequest *)requestToSerialize.get() setHTTPBodyStream:nil];
57    }
58
59    RetainPtr<CFDictionaryRef> dictionary = adoptCF(WKNSURLRequestCreateSerializableRepresentation(requestToSerialize.get(), CoreIPC::tokenNullTypeRef()));
60    CoreIPC::encode(encoder, dictionary.get());
61
62    // The fallback array is part of NSURLRequest, but it is not encoded by WKNSURLRequestCreateSerializableRepresentation.
63    encoder << resourceRequest.responseContentDispositionEncodingFallbackArray();
64}
65
66bool ArgumentCoder<ResourceRequest>::decodePlatformData(ArgumentDecoder& decoder, ResourceRequest& resourceRequest)
67{
68    bool requestIsPresent;
69    if (!decoder.decode(requestIsPresent))
70        return false;
71
72    if (!requestIsPresent) {
73        resourceRequest = ResourceRequest();
74        return true;
75    }
76
77    RetainPtr<CFDictionaryRef> dictionary;
78    if (!CoreIPC::decode(decoder, dictionary))
79        return false;
80
81    NSURLRequest *nsURLRequest = WKNSURLRequestFromSerializableRepresentation(dictionary.get(), CoreIPC::tokenNullTypeRef());
82    if (!nsURLRequest)
83        return false;
84
85    resourceRequest = ResourceRequest(nsURLRequest);
86
87    Vector<String> responseContentDispositionEncodingFallbackArray;
88    if (!decoder.decode(responseContentDispositionEncodingFallbackArray))
89        return false;
90
91    resourceRequest.setResponseContentDispositionEncodingFallbackArray(
92        responseContentDispositionEncodingFallbackArray.size() > 0 ? responseContentDispositionEncodingFallbackArray[0] : String(),
93        responseContentDispositionEncodingFallbackArray.size() > 1 ? responseContentDispositionEncodingFallbackArray[1] : String(),
94        responseContentDispositionEncodingFallbackArray.size() > 2 ? responseContentDispositionEncodingFallbackArray[2] : String()
95    );
96
97    return true;
98}
99
100void ArgumentCoder<ResourceResponse>::encodePlatformData(ArgumentEncoder& encoder, const ResourceResponse& resourceResponse)
101{
102    bool responseIsPresent = resourceResponse.platformResponseIsUpToDate() && resourceResponse.nsURLResponse();
103    encoder << responseIsPresent;
104
105    if (!responseIsPresent)
106        return;
107
108    RetainPtr<CFDictionaryRef> dictionary = adoptCF(WKNSURLResponseCreateSerializableRepresentation(resourceResponse.nsURLResponse(), CoreIPC::tokenNullTypeRef()));
109    CoreIPC::encode(encoder, dictionary.get());
110}
111
112bool ArgumentCoder<ResourceResponse>::decodePlatformData(ArgumentDecoder& decoder, ResourceResponse& resourceResponse)
113{
114    bool responseIsPresent;
115    if (!decoder.decode(responseIsPresent))
116        return false;
117
118    if (!responseIsPresent) {
119        resourceResponse = ResourceResponse();
120        return true;
121    }
122
123    RetainPtr<CFDictionaryRef> dictionary;
124    if (!CoreIPC::decode(decoder, dictionary))
125        return false;
126
127    NSURLResponse* nsURLResponse = WKNSURLResponseFromSerializableRepresentation(dictionary.get(), CoreIPC::tokenNullTypeRef());
128    if (!nsURLResponse)
129        return false;
130
131    resourceResponse = ResourceResponse(nsURLResponse);
132    return true;
133}
134
135static NSString* nsString(const String& string)
136{
137    return string.impl() ? [NSString stringWithCharacters:reinterpret_cast<const UniChar*>(string.characters()) length:string.length()] : @"";
138}
139
140void ArgumentCoder<ResourceError>::encodePlatformData(ArgumentEncoder& encoder, const ResourceError& resourceError)
141{
142    bool errorIsNull = resourceError.isNull();
143    encoder << errorIsNull;
144
145    if (errorIsNull)
146        return;
147
148    NSError *nsError = resourceError.nsError();
149
150    String domain = [nsError domain];
151    encoder << domain;
152
153    int64_t code = [nsError code];
154    encoder << code;
155
156    HashMap<String, String> stringUserInfoMap;
157
158    NSDictionary* userInfo = [nsError userInfo];
159    for (NSString *key in userInfo) {
160        id value = [userInfo objectForKey:key];
161        if (![value isKindOfClass:[NSString class]])
162            continue;
163
164        stringUserInfoMap.set(key, (NSString *)value);
165        continue;
166    }
167    encoder << stringUserInfoMap;
168
169    id peerCertificateChain = [userInfo objectForKey:@"NSErrorPeerCertificateChainKey"];
170    ASSERT(!peerCertificateChain || [peerCertificateChain isKindOfClass:[NSArray class]]);
171    encoder << PlatformCertificateInfo((CFArrayRef)peerCertificateChain);
172}
173
174bool ArgumentCoder<ResourceError>::decodePlatformData(ArgumentDecoder& decoder, ResourceError& resourceError)
175{
176    bool errorIsNull;
177    if (!decoder.decode(errorIsNull))
178        return false;
179
180    if (errorIsNull) {
181        resourceError = ResourceError();
182        return true;
183    }
184
185    String domain;
186    if (!decoder.decode(domain))
187        return false;
188
189    int64_t code;
190    if (!decoder.decode(code))
191        return false;
192
193    HashMap<String, String> stringUserInfoMap;
194    if (!decoder.decode(stringUserInfoMap))
195        return false;
196
197    PlatformCertificateInfo certificate;
198    if (!decoder.decode(certificate))
199        return false;
200
201    NSUInteger userInfoSize = stringUserInfoMap.size();
202    if (certificate.certificateChain())
203        userInfoSize++;
204
205    NSMutableDictionary* userInfo = [NSMutableDictionary dictionaryWithCapacity:userInfoSize];
206
207    HashMap<String, String>::const_iterator it = stringUserInfoMap.begin();
208    HashMap<String, String>::const_iterator end = stringUserInfoMap.end();
209    for (; it != end; ++it)
210        [userInfo setObject:nsString(it->value) forKey:nsString(it->key)];
211
212    if (certificate.certificateChain())
213        [userInfo setObject:(NSArray *)certificate.certificateChain() forKey:@"NSErrorPeerCertificateChainKey"];
214
215    RetainPtr<NSError> nsError = adoptNS([[NSError alloc] initWithDomain:nsString(domain) code:code userInfo:userInfo]);
216
217    resourceError = ResourceError(nsError.get());
218    return true;
219}
220
221void ArgumentCoder<KeypressCommand>::encode(ArgumentEncoder& encoder, const KeypressCommand& keypressCommand)
222{
223    encoder << keypressCommand.commandName << keypressCommand.text;
224}
225
226bool ArgumentCoder<KeypressCommand>::decode(ArgumentDecoder& decoder, KeypressCommand& keypressCommand)
227{
228    if (!decoder.decode(keypressCommand.commandName))
229        return false;
230
231    if (!decoder.decode(keypressCommand.text))
232        return false;
233
234    return true;
235}
236
237} // namespace CoreIPC
238