Web Inspector: Provide SPI to disallow remote inspection of a JSContext
[WebKit-https.git] / Source / JavaScriptCore / API / JSContext.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. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #import "APICast.h"
29 #import "JSCInlines.h"
30 #import "JSContextInternal.h"
31 #import "JSContextPrivate.h"
32 #import "JSContextRefPrivate.h"
33 #import "JSGlobalObject.h"
34 #import "JSValueInternal.h"
35 #import "JSVirtualMachineInternal.h"
36 #import "JSWrapperMap.h"
37 #import "JavaScriptCore.h"
38 #import "ObjcRuntimeExtras.h"
39 #import "StrongInlines.h"
40 #import <wtf/HashSet.h>
41
42 #if JSC_OBJC_API_ENABLED
43
44 @implementation JSContext {
45     JSVirtualMachine *m_virtualMachine;
46     JSGlobalContextRef m_context;
47     JSWrapperMap *m_wrapperMap;
48     JSC::Strong<JSC::JSObject> m_exception;
49 }
50
51 @synthesize exceptionHandler;
52
53 - (JSGlobalContextRef)JSGlobalContextRef
54 {
55     return m_context;
56 }
57
58 - (instancetype)init
59 {
60     return [self initWithVirtualMachine:[[[JSVirtualMachine alloc] init] autorelease]];
61 }
62
63 - (instancetype)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine
64 {
65     self = [super init];
66     if (!self)
67         return nil;
68
69     m_virtualMachine = [virtualMachine retain];
70     m_context = JSGlobalContextCreateInGroup(getGroupFromVirtualMachine(virtualMachine), 0);
71     m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self];
72
73     self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
74         context.exception = exceptionValue;
75     };
76
77     [m_virtualMachine addContext:self forGlobalContextRef:m_context];
78
79     return self;
80 }
81
82 - (void)dealloc
83 {
84     m_exception.clear();
85     [m_wrapperMap release];
86     JSGlobalContextRelease(m_context);
87     [m_virtualMachine release];
88     [self.exceptionHandler release];
89     [super dealloc];
90 }
91
92 - (JSValue *)evaluateScript:(NSString *)script
93 {
94     return [self evaluateScript:script withSourceURL:nil];
95 }
96
97 - (JSValue *)evaluateScript:(NSString *)script withSourceURL:(NSURL *)sourceURL
98 {
99     JSValueRef exceptionValue = nullptr;
100     JSStringRef scriptJS = JSStringCreateWithCFString((CFStringRef)script);
101     JSStringRef sourceURLJS = sourceURL ? JSStringCreateWithCFString((CFStringRef)[sourceURL absoluteString]) : nullptr;
102     JSValueRef result = JSEvaluateScript(m_context, scriptJS, nullptr, sourceURLJS, 0, &exceptionValue);
103     if (sourceURLJS)
104         JSStringRelease(sourceURLJS);
105     JSStringRelease(scriptJS);
106
107     if (exceptionValue)
108         return [self valueFromNotifyException:exceptionValue];
109
110     return [JSValue valueWithJSValueRef:result inContext:self];
111 }
112
113 - (void)setException:(JSValue *)value
114 {
115     JSC::JSLockHolder locker(toJS(m_context));
116     if (value)
117         m_exception.set(toJS(m_context)->vm(), toJS(JSValueToObject(m_context, valueInternalValue(value), 0)));
118     else
119         m_exception.clear();
120 }
121
122 - (JSValue *)exception
123 {
124     if (!m_exception)
125         return nil;
126     return [JSValue valueWithJSValueRef:toRef(m_exception.get()) inContext:self];
127 }
128
129 - (JSWrapperMap *)wrapperMap
130 {
131     return m_wrapperMap;
132 }
133
134 - (JSValue *)globalObject
135 {
136     return [JSValue valueWithJSValueRef:JSContextGetGlobalObject(m_context) inContext:self];
137 }
138
139 + (JSContext *)currentContext
140 {
141     WTFThreadData& threadData = wtfThreadData();
142     CallbackData *entry = (CallbackData *)threadData.m_apiData;
143     return entry ? entry->context : nil;
144 }
145
146 + (JSValue *)currentThis
147 {
148     WTFThreadData& threadData = wtfThreadData();
149     CallbackData *entry = (CallbackData *)threadData.m_apiData;
150     if (!entry)
151         return nil;
152     return [JSValue valueWithJSValueRef:entry->thisValue inContext:[JSContext currentContext]];
153 }
154
155 + (JSValue *)currentCallee
156 {
157     WTFThreadData& threadData = wtfThreadData();
158     CallbackData *entry = (CallbackData *)threadData.m_apiData;
159     if (!entry)
160         return nil;
161     return [JSValue valueWithJSValueRef:entry->calleeValue inContext:[JSContext currentContext]];
162 }
163
164 + (NSArray *)currentArguments
165 {
166     WTFThreadData& threadData = wtfThreadData();
167     CallbackData *entry = (CallbackData *)threadData.m_apiData;
168
169     if (!entry)
170         return nil;
171
172     if (!entry->currentArguments) {
173         JSContext *context = [JSContext currentContext];
174         size_t count = entry->argumentCount;
175         JSValue * argumentArray[count];
176         for (size_t i =0; i < count; ++i)
177             argumentArray[i] = [JSValue valueWithJSValueRef:entry->arguments[i] inContext:context];
178         entry->currentArguments = [[NSArray alloc] initWithObjects:argumentArray count:count];
179     }
180
181     return entry->currentArguments;
182 }
183
184 - (JSVirtualMachine *)virtualMachine
185 {
186     return m_virtualMachine;
187 }
188
189 - (NSString *)name
190 {
191     JSStringRef name = JSGlobalContextCopyName(m_context);
192     if (!name)
193         return nil;
194
195     return [(NSString *)JSStringCopyCFString(kCFAllocatorDefault, name) autorelease];
196 }
197
198 - (void)setName:(NSString *)name
199 {
200     JSStringRef nameJS = name ? JSStringCreateWithCFString((CFStringRef)[name copy]) : nullptr;
201     JSGlobalContextSetName(m_context, nameJS);
202     if (nameJS)
203         JSStringRelease(nameJS);
204 }
205
206 - (BOOL)_remoteInspectionEnabled
207 {
208     return JSGlobalContextGetRemoteInspectionEnabled(m_context);
209 }
210
211 - (void)_setRemoteInspectionEnabled:(BOOL)enabled
212 {
213     JSGlobalContextSetRemoteInspectionEnabled(m_context, enabled);
214 }
215
216 @end
217
218 @implementation JSContext(SubscriptSupport)
219
220 - (JSValue *)objectForKeyedSubscript:(id)key
221 {
222     return [self globalObject][key];
223 }
224
225 - (void)setObject:(id)object forKeyedSubscript:(NSObject <NSCopying> *)key
226 {
227     [self globalObject][key] = object;
228 }
229
230 @end
231
232 @implementation JSContext (Internal)
233
234 - (instancetype)initWithGlobalContextRef:(JSGlobalContextRef)context
235 {
236     self = [super init];
237     if (!self)
238         return nil;
239
240     JSC::JSGlobalObject* globalObject = toJS(context)->lexicalGlobalObject();
241     m_virtualMachine = [[JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&globalObject->vm())] retain];
242     ASSERT(m_virtualMachine);
243     m_context = JSGlobalContextRetain(context);
244     m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self];
245
246     self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {
247         context.exception = exceptionValue;
248     };
249
250     [m_virtualMachine addContext:self forGlobalContextRef:m_context];
251
252     return self;
253 }
254
255 - (void)notifyException:(JSValueRef)exceptionValue
256 {
257     self.exceptionHandler(self, [JSValue valueWithJSValueRef:exceptionValue inContext:self]);
258 }
259
260 - (JSValue *)valueFromNotifyException:(JSValueRef)exceptionValue
261 {
262     [self notifyException:exceptionValue];
263     return [JSValue valueWithUndefinedInContext:self];
264 }
265
266 - (BOOL)boolFromNotifyException:(JSValueRef)exceptionValue
267 {
268     [self notifyException:exceptionValue];
269     return NO;
270 }
271
272 - (void)beginCallbackWithData:(CallbackData *)callbackData calleeValue:(JSValueRef)calleeValue thisValue:(JSValueRef)thisValue argumentCount:(size_t)argumentCount arguments:(const JSValueRef *)arguments
273 {
274     WTFThreadData& threadData = wtfThreadData();
275     [self retain];
276     CallbackData *prevStack = (CallbackData *)threadData.m_apiData;
277     *callbackData = (CallbackData){ prevStack, self, [self.exception retain], calleeValue, thisValue, argumentCount, arguments, nil };
278     threadData.m_apiData = callbackData;
279     self.exception = nil;
280 }
281
282 - (void)endCallbackWithData:(CallbackData *)callbackData
283 {
284     WTFThreadData& threadData = wtfThreadData();
285     self.exception = callbackData->preservedException;
286     [callbackData->preservedException release];
287     [callbackData->currentArguments release];
288     threadData.m_apiData = callbackData->next;
289     [self release];
290 }
291
292 - (JSValue *)wrapperForObjCObject:(id)object
293 {
294     JSC::JSLockHolder locker(toJS(m_context));
295     return [m_wrapperMap jsWrapperForObject:object];
296 }
297
298 - (JSValue *)wrapperForJSObject:(JSValueRef)value
299 {
300     JSC::JSLockHolder locker(toJS(m_context));
301     return [m_wrapperMap objcWrapperForJSValueRef:value];
302 }
303
304 + (JSContext *)contextWithJSGlobalContextRef:(JSGlobalContextRef)globalContext
305 {
306     JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&toJS(globalContext)->vm())];
307     JSContext *context = [virtualMachine contextForGlobalContextRef:globalContext];
308     if (!context)
309         context = [[[JSContext alloc] initWithGlobalContextRef:globalContext] autorelease];
310     return context;
311 }
312
313 @end
314
315 WeakContextRef::WeakContextRef(JSContext *context)
316 {
317     objc_initWeak(&m_weakContext, context);
318 }
319
320 WeakContextRef::~WeakContextRef()
321 {
322     objc_destroyWeak(&m_weakContext);
323 }
324
325 JSContext * WeakContextRef::get()
326 {
327     return objc_loadWeak(&m_weakContext);
328 }
329
330 void WeakContextRef::set(JSContext *context)
331 {
332     objc_storeWeak(&m_weakContext, context);
333 }
334
335 #endif