1 /*
2  *  Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
4  *  Copyright (C) 2007 Samuel Weinig <sam@webkit.org>
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Lesser General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Lesser General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Lesser General Public
17  *  License along with this library; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20 
21 #include "config.h"
22 #include "JSDOMBinding.h"
23 
24 #include "DOMCoreException.h"
25 #include "DOMObjectHashTableMap.h"
26 #include "EventException.h"
27 #include "ExceptionBase.h"
28 #include "FileException.h"
29 #include "Frame.h"
30 #include "IDBDatabaseException.h"
31 #include "JSDOMCoreException.h"
32 #include "JSDOMWindowCustom.h"
33 #include "JSEventException.h"
34 #include "JSExceptionBase.h"
35 #if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)
36 #include "JSFileException.h"
37 #endif
38 #include "JSRangeException.h"
39 #include "JSSQLException.h"
40 #if ENABLE(SVG)
41 #include "JSSVGException.h"
42 #endif
43 #include "JSXMLHttpRequestException.h"
44 #if ENABLE(XPATH)
45 #include "JSXPathException.h"
46 #endif
47 #include "RangeException.h"
48 #include "SQLException.h"
49 #include "SVGException.h"
50 #include "ScriptCallStack.h"
51 #include "XMLHttpRequestException.h"
52 #include "XPathException.h"
53 #include <runtime/DateInstance.h>
54 #include <runtime/Error.h>
55 #include <runtime/JSFunction.h>
56 
57 using namespace JSC;
58 
59 namespace WebCore {
60 
getHashTableForGlobalData(JSGlobalData & globalData,const JSC::HashTable * staticTable)61 const JSC::HashTable* getHashTableForGlobalData(JSGlobalData& globalData, const JSC::HashTable* staticTable)
62 {
63     return DOMObjectHashTableMap::mapFor(globalData).get(staticTable);
64 }
65 
jsStringSlowCase(ExecState * exec,JSStringCache & stringCache,StringImpl * stringImpl)66 JSValue jsStringSlowCase(ExecState* exec, JSStringCache& stringCache, StringImpl* stringImpl)
67 {
68     JSString* wrapper = jsString(exec, UString(stringImpl));
69     stringCache.add(stringImpl, Weak<JSString>(exec->globalData(), wrapper, currentWorld(exec)->stringWrapperOwner(), stringImpl));
70     return wrapper;
71 }
72 
jsStringOrNull(ExecState * exec,const String & s)73 JSValue jsStringOrNull(ExecState* exec, const String& s)
74 {
75     if (s.isNull())
76         return jsNull();
77     return jsString(exec, s);
78 }
79 
jsOwnedStringOrNull(ExecState * exec,const String & s)80 JSValue jsOwnedStringOrNull(ExecState* exec, const String& s)
81 {
82     if (s.isNull())
83         return jsNull();
84     return jsOwnedString(exec, stringToUString(s));
85 }
86 
jsStringOrUndefined(ExecState * exec,const String & s)87 JSValue jsStringOrUndefined(ExecState* exec, const String& s)
88 {
89     if (s.isNull())
90         return jsUndefined();
91     return jsString(exec, s);
92 }
93 
jsStringOrFalse(ExecState * exec,const String & s)94 JSValue jsStringOrFalse(ExecState* exec, const String& s)
95 {
96     if (s.isNull())
97         return jsBoolean(false);
98     return jsString(exec, s);
99 }
100 
jsString(ExecState * exec,const KURL & url)101 JSValue jsString(ExecState* exec, const KURL& url)
102 {
103     return jsString(exec, url.string());
104 }
105 
jsStringOrNull(ExecState * exec,const KURL & url)106 JSValue jsStringOrNull(ExecState* exec, const KURL& url)
107 {
108     if (url.isNull())
109         return jsNull();
110     return jsString(exec, url.string());
111 }
112 
jsStringOrUndefined(ExecState * exec,const KURL & url)113 JSValue jsStringOrUndefined(ExecState* exec, const KURL& url)
114 {
115     if (url.isNull())
116         return jsUndefined();
117     return jsString(exec, url.string());
118 }
119 
jsStringOrFalse(ExecState * exec,const KURL & url)120 JSValue jsStringOrFalse(ExecState* exec, const KURL& url)
121 {
122     if (url.isNull())
123         return jsBoolean(false);
124     return jsString(exec, url.string());
125 }
126 
findAtomicString(const Identifier & identifier)127 AtomicStringImpl* findAtomicString(const Identifier& identifier)
128 {
129     if (identifier.isNull())
130         return 0;
131     StringImpl* impl = identifier.impl();
132     ASSERT(impl->existingHash());
133     return AtomicString::find(impl->characters(), impl->length(), impl->existingHash());
134 }
135 
valueToStringWithNullCheck(ExecState * exec,JSValue value)136 String valueToStringWithNullCheck(ExecState* exec, JSValue value)
137 {
138     if (value.isNull())
139         return String();
140     return ustringToString(value.toString(exec));
141 }
142 
valueToStringWithUndefinedOrNullCheck(ExecState * exec,JSValue value)143 String valueToStringWithUndefinedOrNullCheck(ExecState* exec, JSValue value)
144 {
145     if (value.isUndefinedOrNull())
146         return String();
147     return ustringToString(value.toString(exec));
148 }
149 
jsDateOrNull(ExecState * exec,double value)150 JSValue jsDateOrNull(ExecState* exec, double value)
151 {
152     if (!isfinite(value))
153         return jsNull();
154     return new (exec) DateInstance(exec, exec->lexicalGlobalObject()->dateStructure(), value);
155 }
156 
valueToDate(ExecState * exec,JSValue value)157 double valueToDate(ExecState* exec, JSValue value)
158 {
159     if (value.isNumber())
160         return value.uncheckedGetNumber();
161     if (!value.inherits(&DateInstance::s_info))
162         return std::numeric_limits<double>::quiet_NaN();
163     return static_cast<DateInstance*>(value.toObject(exec))->internalNumber();
164 }
165 
reportException(ExecState * exec,JSValue exception)166 void reportException(ExecState* exec, JSValue exception)
167 {
168     if (exception.isObject() && asObject(exception)->exceptionType() == Terminated)
169         return;
170 
171     UString errorMessage = exception.toString(exec);
172     JSObject* exceptionObject = exception.toObject(exec);
173     int lineNumber = exceptionObject->get(exec, Identifier(exec, "line")).toInt32(exec);
174     UString exceptionSourceURL = exceptionObject->get(exec, Identifier(exec, "sourceURL")).toString(exec);
175     exec->clearException();
176 
177     if (ExceptionBase* exceptionBase = toExceptionBase(exception))
178         errorMessage = stringToUString(exceptionBase->message() + ": "  + exceptionBase->description());
179 
180     ScriptExecutionContext* scriptExecutionContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();
181     ASSERT(scriptExecutionContext);
182 
183     // Crash data indicates null-dereference crashes at this point in the Safari 4 Public Beta.
184     // It's harmless to return here without reporting the exception to the log and the debugger in this case.
185     if (!scriptExecutionContext)
186         return;
187 
188     scriptExecutionContext->reportException(ustringToString(errorMessage), lineNumber, ustringToString(exceptionSourceURL), 0);
189 }
190 
reportCurrentException(ExecState * exec)191 void reportCurrentException(ExecState* exec)
192 {
193     JSValue exception = exec->exception();
194     exec->clearException();
195     reportException(exec, exception);
196 }
197 
setDOMException(ExecState * exec,ExceptionCode ec)198 void setDOMException(ExecState* exec, ExceptionCode ec)
199 {
200     if (!ec || exec->hadException())
201         return;
202 
203     // FIXME: All callers to setDOMException need to pass in the right global object
204     // for now, we're going to assume the lexicalGlobalObject.  Which is wrong in cases like this:
205     // frames[0].document.createElement(null, null); // throws an exception which should have the subframes prototypes.
206     JSDOMGlobalObject* globalObject = deprecatedGlobalObjectForPrototype(exec);
207 
208     ExceptionCodeDescription description;
209     getExceptionCodeDescription(ec, description);
210 
211     JSValue errorObject;
212     switch (description.type) {
213         case DOMExceptionType:
214             errorObject = toJS(exec, globalObject, DOMCoreException::create(description));
215             break;
216         case RangeExceptionType:
217             errorObject = toJS(exec, globalObject, RangeException::create(description));
218             break;
219         case EventExceptionType:
220             errorObject = toJS(exec, globalObject, EventException::create(description));
221             break;
222         case XMLHttpRequestExceptionType:
223             errorObject = toJS(exec, globalObject, XMLHttpRequestException::create(description));
224             break;
225 #if ENABLE(SVG)
226         case SVGExceptionType:
227             errorObject = toJS(exec, globalObject, SVGException::create(description).get());
228             break;
229 #endif
230 #if ENABLE(XPATH)
231         case XPathExceptionType:
232             errorObject = toJS(exec, globalObject, XPathException::create(description));
233             break;
234 #endif
235 #if ENABLE(DATABASE)
236         case SQLExceptionType:
237             errorObject = toJS(exec, globalObject, SQLException::create(description));
238             break;
239 #endif
240 #if ENABLE(BLOB) || ENABLE(FILE_SYSTEM)
241         case FileExceptionType:
242             errorObject = toJS(exec, globalObject, FileException::create(description));
243             break;
244 #endif
245 #if ENABLE(INDEXED_DATABASE)
246         case IDBDatabaseExceptionType:
247             errorObject = toJS(exec, globalObject, IDBDatabaseException::create(description));
248             break;
249 #endif
250     }
251 
252     ASSERT(errorObject);
253     throwError(exec, errorObject);
254 }
255 
activeDOMWindow(ExecState * exec)256 DOMWindow* activeDOMWindow(ExecState* exec)
257 {
258     return asJSDOMWindow(exec->lexicalGlobalObject())->impl();
259 }
260 
firstDOMWindow(ExecState * exec)261 DOMWindow* firstDOMWindow(ExecState* exec)
262 {
263     return asJSDOMWindow(exec->dynamicGlobalObject())->impl();
264 }
265 
checkNodeSecurity(ExecState * exec,Node * node)266 bool checkNodeSecurity(ExecState* exec, Node* node)
267 {
268     return node && allowsAccessFromFrame(exec, node->document()->frame());
269 }
270 
allowsAccessFromFrame(ExecState * exec,Frame * frame)271 bool allowsAccessFromFrame(ExecState* exec, Frame* frame)
272 {
273     if (!frame)
274         return false;
275     JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
276     return window && window->allowsAccessFrom(exec);
277 }
278 
allowsAccessFromFrame(ExecState * exec,Frame * frame,String & message)279 bool allowsAccessFromFrame(ExecState* exec, Frame* frame, String& message)
280 {
281     if (!frame)
282         return false;
283     JSDOMWindow* window = toJSDOMWindow(frame, currentWorld(exec));
284     return window && window->allowsAccessFrom(exec, message);
285 }
286 
printErrorMessageForFrame(Frame * frame,const String & message)287 void printErrorMessageForFrame(Frame* frame, const String& message)
288 {
289     if (!frame)
290         return;
291     frame->domWindow()->printErrorMessage(message);
292 }
293 
294 // FIXME: We should remove or at least deprecate this function. Callers can use firstDOMWindow directly.
toDynamicFrame(ExecState * exec)295 Frame* toDynamicFrame(ExecState* exec)
296 {
297     return firstDOMWindow(exec)->frame();
298 }
299 
300 // FIXME: We should remove this function. Callers can use ScriptController directly.
processingUserGesture()301 bool processingUserGesture()
302 {
303     return ScriptController::processingUserGesture();
304 }
305 
objectToStringFunctionGetter(ExecState * exec,JSValue,const Identifier & propertyName)306 JSValue objectToStringFunctionGetter(ExecState* exec, JSValue, const Identifier& propertyName)
307 {
308     return new (exec) JSFunction(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->functionStructure(), 0, propertyName, objectProtoFuncToString);
309 }
310 
getCachedDOMStructure(JSDOMGlobalObject * globalObject,const ClassInfo * classInfo)311 Structure* getCachedDOMStructure(JSDOMGlobalObject* globalObject, const ClassInfo* classInfo)
312 {
313     JSDOMStructureMap& structures = globalObject->structures();
314     return structures.get(classInfo).get();
315 }
316 
cacheDOMStructure(JSDOMGlobalObject * globalObject,Structure * structure,const ClassInfo * classInfo)317 Structure* cacheDOMStructure(JSDOMGlobalObject* globalObject, Structure* structure, const ClassInfo* classInfo)
318 {
319     JSDOMStructureMap& structures = globalObject->structures();
320     ASSERT(!structures.contains(classInfo));
321     return structures.set(classInfo, WriteBarrier<Structure>(globalObject->globalData(), globalObject, structure)).first->second.get();
322 }
323 
toJSSequence(ExecState * exec,JSValue value,unsigned & length)324 JSC::JSObject* toJSSequence(ExecState* exec, JSValue value, unsigned& length)
325 {
326     JSObject* object = value.getObject();
327     if (!object) {
328         throwTypeError(exec);
329         return 0;
330     }
331     JSValue lengthValue = object->get(exec, exec->propertyNames().length);
332     if (exec->hadException())
333         return 0;
334 
335     if (lengthValue.isUndefinedOrNull()) {
336         throwTypeError(exec);
337         return 0;
338     }
339 
340     length = lengthValue.toUInt32(exec);
341     if (exec->hadException())
342         return 0;
343 
344     return object;
345 }
346 
347 } // namespace WebCore
348