2e14aeea9574e6fb4d7616476b95449f909787bd
[WebKit-https.git] / Source / WebKit2 / Shared / API / Cocoa / _WKRemoteObjectRegistry.mm
1 /*
2  * Copyright (C) 2013 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 "_WKRemoteObjectRegistryInternal.h"
28
29 #if WK_API_ENABLED
30
31 #import "APIDictionary.h"
32 #import "Connection.h"
33 #import "RemoteObjectRegistry.h"
34 #import "UserData.h"
35 #import "WKConnectionRef.h"
36 #import "WKRemoteObject.h"
37 #import "WKRemoteObjectCoder.h"
38 #import "WKSharedAPICast.h"
39 #import "WebConnection.h"
40 #import "_WKRemoteObjectInterface.h"
41
42 const char* const encodedInvocationKey = "encodedInvocation";
43 const char* const interfaceIdentifierKey = "interfaceIdentifier";
44
45 NSString * const invocationKey = @"invocation";
46
47 using namespace WebKit;
48
49 @implementation _WKRemoteObjectRegistry {
50     std::unique_ptr<RemoteObjectRegistry> _remoteObjectRegistry;
51
52     RetainPtr<NSMapTable> _remoteObjectProxies;
53     HashMap<String, std::pair<RetainPtr<id>, RetainPtr<_WKRemoteObjectInterface>>> _exportedObjects;
54 }
55
56 - (void)registerExportedObject:(id)object interface:(_WKRemoteObjectInterface *)interface
57 {
58     ASSERT(!_exportedObjects.contains(interface.identifier));
59     _exportedObjects.add(interface.identifier, std::make_pair<RetainPtr<id>, RetainPtr<_WKRemoteObjectInterface>>(object, interface));
60 }
61
62 - (void)unregisterExportedObject:(id)object interface:(_WKRemoteObjectInterface *)interface
63 {
64     ASSERT(_exportedObjects.get(interface.identifier).first == object);
65     ASSERT(_exportedObjects.get(interface.identifier).second == interface);
66
67     _exportedObjects.remove(interface.identifier);
68 }
69
70 - (id)remoteObjectProxyWithInterface:(_WKRemoteObjectInterface *)interface
71 {
72     if (!_remoteObjectProxies)
73         _remoteObjectProxies = [NSMapTable strongToWeakObjectsMapTable];
74
75     if (id remoteObjectProxy = [_remoteObjectProxies objectForKey:interface.identifier])
76         return remoteObjectProxy;
77
78     RetainPtr<NSString> identifier = adoptNS([interface.identifier copy]);
79     auto remoteObject = adoptNS([[WKRemoteObject alloc] _initWithObjectRegistry:self interface:interface]);
80     [_remoteObjectProxies setObject:remoteObject.get() forKey:identifier.get()];
81
82     return remoteObject.autorelease();
83 }
84
85 - (id)_initWithMessageSender:(IPC::MessageSender&)messageSender
86 {
87     if (!(self = [super init]))
88         return nil;
89
90     _remoteObjectRegistry = std::make_unique<RemoteObjectRegistry>(self, messageSender);
91
92     return self;
93 }
94
95 - (void)_invalidate
96 {
97     _remoteObjectRegistry = nullptr;
98 }
99
100 - (void)_sendInvocation:(NSInvocation *)invocation interface:(_WKRemoteObjectInterface *)interface
101 {
102     RetainPtr<WKRemoteObjectEncoder> encoder = adoptNS([[WKRemoteObjectEncoder alloc] init]);
103     [encoder encodeObject:invocation forKey:invocationKey];
104
105     Ref<API::Dictionary> body = API::Dictionary::create();
106     body->set(interfaceIdentifierKey, API::String::create(interface.identifier));
107     body->set(encodedInvocationKey, [encoder rootObjectDictionary]);
108
109     if (!_remoteObjectRegistry)
110         return;
111
112     _remoteObjectRegistry->sendInvocation(UserData(body.ptr()));
113 }
114
115 - (WebKit::RemoteObjectRegistry&)remoteObjectRegistry
116 {
117     return *_remoteObjectRegistry;
118 }
119
120 - (BOOL)_invokeMethod:(const UserData&)invocation
121 {
122     if (!invocation.object() || invocation.object()->type() != API::Object::Type::Dictionary)
123         return NO;
124     
125     const API::Dictionary& dictionary = static_cast<const API::Dictionary&>(*invocation.object());
126
127     API::String* interfaceIdentifier = dictionary.get<API::String>(interfaceIdentifierKey);
128     if (!interfaceIdentifier)
129         return NO;
130
131     const API::Dictionary* encodedInvocation = dictionary.get<API::Dictionary>(encodedInvocationKey);
132     if (!encodedInvocationKey)
133         return NO;
134
135     [self _invokeMessageWithInterfaceIdentifier:interfaceIdentifier->string() encodedInvocation:encodedInvocation];
136
137     return YES;
138 }
139
140 - (void)_invokeMessageWithInterfaceIdentifier:(const String&)interfaceIdentifier encodedInvocation:(const API::Dictionary*)encodedInvocation
141 {
142     auto interfaceAndObject = _exportedObjects.get(interfaceIdentifier);
143     if (!interfaceAndObject.second) {
144         NSLog(@"Did not find a registered object for the interface \"%@\"", (NSString *)interfaceIdentifier);
145         return;
146     }
147
148     RetainPtr<WKRemoteObjectDecoder> decoder = adoptNS([[WKRemoteObjectDecoder alloc] initWithInterface:interfaceAndObject.second.get() rootObjectDictionary:encodedInvocation]);
149
150     NSInvocation *invocation = nil;
151
152     @try {
153         invocation = [decoder decodeObjectOfClass:[NSInvocation class] forKey:invocationKey];
154     } @catch (NSException *exception) {
155         NSLog(@"Exception caught during decoding of message: %@", exception);
156     }
157
158     invocation.target = interfaceAndObject.first.get();
159
160     @try {
161         [invocation invoke];
162     } @catch (NSException *exception) {
163         NSLog(@"%@: Warning: Exception caught during invocation of received message, dropping incoming message .\nException: %@", self, exception);
164     }
165 }
166
167 @end
168
169 #endif // WK_API_ENABLED