void JSDOMWindow::setLocation(ExecState* exec, JSValue value) { Frame* lexicalFrame = toLexicalFrame(exec); if (!lexicalFrame) return; #if ENABLE(DASHBOARD_SUPPORT) // To avoid breaking old widgets, make "var location =" in a top-level frame create // a property named "location" instead of performing a navigation (<rdar://problem/5688039>). if (Settings* settings = lexicalFrame->settings()) { if (settings->usesDashboardBackwardCompatibilityMode() && !lexicalFrame->tree()->parent()) { if (allowsAccessFrom(exec)) putDirect(Identifier(exec, "location"), value); return; } } #endif Frame* frame = impl()->frame(); ASSERT(frame); KURL url = completeURL(exec, ustringToString(value.toString(exec))); if (url.isNull()) return; if (!shouldAllowNavigation(exec, frame)) return; if (!protocolIsJavaScript(url) || allowsAccessFrom(exec)) { // We want a new history item if this JS was called via a user gesture frame->redirectScheduler()->scheduleLocationChange(url, lexicalFrame->loader()->outgoingReferrer(), !lexicalFrame->script()->anyPageIsProcessingUserGesture(), false, processingUserGesture()); } }
void JSDOMWindowBase::put(ExecState* exec, const Identifier& propertyName, JSValuePtr value, PutPropertySlot& slot) { const HashEntry* entry = JSDOMWindowBaseTable.entry(exec, propertyName); if (entry) { if (entry->attributes() & Function) { if (allowsAccessFrom(exec)) Base::put(exec, propertyName, value, slot); return; } if (entry->attributes() & ReadOnly) return; } if (allowsAccessFrom(exec)) Base::put(exec, propertyName, value, slot); }
bool JSDOMWindow::defineOwnProperty(JSC::ExecState* exec, const JSC::Identifier& propertyName, JSC::PropertyDescriptor& descriptor, bool shouldThrow) { // Only allow defining properties in this way by frames in the same origin, as it allows setters to be introduced. if (!allowsAccessFrom(exec)) return false; return Base::defineOwnProperty(exec, propertyName, descriptor, shouldThrow); }
JSValue JSDOMWindow::lookupSetter(ExecState* exec, const Identifier& propertyName) { // Only allow looking-up setters by frames in the same origin. if (!allowsAccessFrom(exec)) return jsUndefined(); return Base::lookupSetter(exec, propertyName); }
bool JSDOMWindow::deleteProperty(ExecState* exec, const Identifier& propertyName) { // Only allow deleting properties by frames in the same origin. if (!allowsAccessFrom(exec)) return false; return Base::deleteProperty(exec, propertyName); }
void JSDOMWindow::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) { // Only allow defining setters by frames in the same origin. if (!allowsAccessFrom(exec)) return; Base::defineSetter(exec, propertyName, setterFunction, attributes); }
void JSDOMWindow::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode) { // Only allow the window to enumerated by frames in the same origin. if (!allowsAccessFrom(exec)) return; Base::getOwnPropertyNames(exec, propertyNames, mode); }
bool JSDOMWindow::getPropertyAttributes(JSC::ExecState* exec, const Identifier& propertyName, unsigned& attributes) const { // Only allow getting property attributes properties by frames in the same origin. if (!allowsAccessFrom(exec)) return false; return Base::getPropertyAttributes(exec, propertyName, attributes); }
bool JSDOMWindow::customGetPropertyNames(ExecState* exec, PropertyNameArray&) { // Only allow the window to enumerated by frames in the same origin. if (!allowsAccessFrom(exec)) return true; return false; }
void JSDOMWindow::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { if (!impl()->frame()) return; // Optimization: access JavaScript global variables directly before involving the DOM. if (JSGlobalObject::hasOwnPropertyForWrite(exec, propertyName)) { if (allowsAccessFrom(exec)) JSGlobalObject::put(exec, propertyName, value, slot); return; } if (lookupPut<JSDOMWindow>(exec, propertyName, value, s_info.propHashTable(exec), this)) return; if (allowsAccessFrom(exec)) Base::put(exec, propertyName, value, slot); }
void JSDOMWindow::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) { // Only allow defining getters by frames in the same origin. if (!allowsAccessFrom(exec)) return; // Don't allow shadowing location using defineGetter. if (propertyName == "location") return; Base::defineGetter(exec, propertyName, getterFunction, attributes); }
bool JSDOMWindowBase::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { // Check for child frames by name before built-in properties to // match Mozilla. This does not match IE, but some sites end up // naming frames things that conflict with window properties that // are in Moz but not IE. Since we have some of these, we have to do // it the Moz way. if (impl()->frame()->tree()->child(propertyName)) { slot.setCustom(this, childFrameGetter); return true; } const HashEntry* entry = JSDOMWindowBaseTable.entry(exec, propertyName); if (entry) { if (entry->attributes() & Function) { if (entry->function() == windowProtoFuncShowModalDialog) { if (!canShowModalDialog(impl()->frame())) return false; } if (allowsAccessFrom(exec)) setUpStaticFunctionSlot(exec, entry, this, propertyName, slot); else slot.setUndefined(); } else slot.setCustom(this, entry->propertyGetter()); return true; } // Do prototype lookup early so that functions and attributes in the prototype can have // precedence over the index and name getters. JSValuePtr proto = prototype(); if (proto->isObject()) { if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) { if (!allowsAccessFrom(exec)) slot.setUndefined(); return true; } } // FIXME: Search the whole frame hierachy somewhere around here. // We need to test the correct priority order. // allow window[1] or parent[1] etc. (#56983) bool ok; unsigned i = propertyName.toArrayIndex(&ok); if (ok && i < impl()->frame()->tree()->childCount()) { slot.setCustomIndex(this, i, indexGetter); return true; } if (!allowsAccessFrom(exec)) { slot.setUndefined(); return true; } // Allow shortcuts like 'Image1' instead of document.images.Image1 Document* document = impl()->frame()->document(); if (document && document->isHTMLDocument()) { AtomicStringImpl* atomicPropertyName = AtomicString::find(propertyName); if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) { slot.setCustom(this, namedItemGetter); return true; } } return Base::getOwnPropertySlot(exec, propertyName, slot); }
bool JSDOMWindow::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { // Never allow cross-domain getOwnPropertyDescriptor if (!allowsAccessFrom(exec)) return false; const HashEntry* entry; // We don't want any properties other than "close" and "closed" on a closed window. if (!impl()->frame()) { // The following code is safe for cross-domain and same domain use. // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype). entry = s_info.propHashTable(exec)->entry(exec, propertyName); if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) { descriptor.setDescriptor(jsBoolean(true), ReadOnly | DontDelete | DontEnum); return true; } entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) { PropertySlot slot; slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); return true; } descriptor.setUndefined(); return true; } entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName); if (entry) { PropertySlot slot; slot.setCustom(this, entry->propertyGetter()); descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); return true; } // Check for child frames by name before built-in properties to // match Mozilla. This does not match IE, but some sites end up // naming frames things that conflict with window properties that // are in Moz but not IE. Since we have some of these, we have to do // it the Moz way. if (impl()->frame()->tree()->child(identifierToAtomicString(propertyName))) { PropertySlot slot; slot.setCustom(this, childFrameGetter); descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); return true; } bool ok; unsigned i = propertyName.toArrayIndex(ok); if (ok && i < impl()->frame()->tree()->childCount()) { PropertySlot slot; slot.setCustomIndex(this, i, indexGetter); descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); return true; } // Allow shortcuts like 'Image1' instead of document.images.Image1 Document* document = impl()->frame()->document(); if (document->isHTMLDocument()) { AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) { PropertySlot slot; slot.setCustom(this, namedItemGetter); descriptor.setDescriptor(slot.getValue(exec, propertyName), ReadOnly | DontDelete | DontEnum); return true; } } return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); }
bool JSDOMWindow::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { // When accessing a Window cross-domain, functions are always the native built-in ones, and they // are not affected by properties changed on the Window or anything in its prototype chain. // This is consistent with the behavior of Firefox. const HashEntry* entry; // We don't want any properties other than "close" and "closed" on a closed window. if (!impl()->frame()) { // The following code is safe for cross-domain and same domain use. // It ignores any custom properties that might be set on the DOMWindow (including a custom prototype). entry = s_info.propHashTable(exec)->entry(exec, propertyName); if (entry && !(entry->attributes() & Function) && entry->propertyGetter() == jsDOMWindowClosed) { slot.setCustom(this, entry->propertyGetter()); return true; } entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); if (entry && (entry->attributes() & Function) && entry->function() == jsDOMWindowPrototypeFunctionClose) { slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); return true; } // FIXME: We should have a message here that explains why the property access/function call was // not allowed. slot.setUndefined(); return true; } // We need to check for cross-domain access here without printing the generic warning message // because we always allow access to some function, just different ones depending whether access // is allowed. String errorMessage; bool allowsAccess = allowsAccessFrom(exec, errorMessage); // Look for overrides before looking at any of our own properties, but ignore overrides completely // if this is cross-domain access. if (allowsAccess && JSGlobalObject::getOwnPropertySlot(exec, propertyName, slot)) return true; // We need this code here because otherwise JSDOMWindowBase will stop the search before we even get to the // prototype due to the blanket same origin (allowsAccessFrom) check at the end of getOwnPropertySlot. // Also, it's important to get the implementation straight out of the DOMWindow prototype regardless of // what prototype is actually set on this object. entry = JSDOMWindowPrototype::s_info.propHashTable(exec)->entry(exec, propertyName); if (entry) { if (entry->attributes() & Function) { if (entry->function() == jsDOMWindowPrototypeFunctionBlur) { if (!allowsAccess) { slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionBlur, 0>); return true; } } else if (entry->function() == jsDOMWindowPrototypeFunctionClose) { if (!allowsAccess) { slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionClose, 0>); return true; } } else if (entry->function() == jsDOMWindowPrototypeFunctionFocus) { if (!allowsAccess) { slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionFocus, 0>); return true; } } else if (entry->function() == jsDOMWindowPrototypeFunctionPostMessage) { if (!allowsAccess) { slot.setCustom(this, nonCachingStaticFunctionGetter<jsDOMWindowPrototypeFunctionPostMessage, 2>); return true; } } else if (entry->function() == jsDOMWindowPrototypeFunctionShowModalDialog) { if (!DOMWindow::canShowModalDialog(impl()->frame())) { slot.setUndefined(); return true; } } } } else { // Allow access to toString() cross-domain, but always Object.prototype.toString. if (propertyName == exec->propertyNames().toString) { if (!allowsAccess) { slot.setCustom(this, objectToStringFunctionGetter); return true; } } } entry = JSDOMWindow::s_info.propHashTable(exec)->entry(exec, propertyName); if (entry) { slot.setCustom(this, entry->propertyGetter()); return true; } // Check for child frames by name before built-in properties to // match Mozilla. This does not match IE, but some sites end up // naming frames things that conflict with window properties that // are in Moz but not IE. Since we have some of these, we have to do // it the Moz way. if (impl()->frame()->tree()->child(identifierToAtomicString(propertyName))) { slot.setCustom(this, childFrameGetter); return true; } // Do prototype lookup early so that functions and attributes in the prototype can have // precedence over the index and name getters. JSValue proto = prototype(); if (proto.isObject()) { if (asObject(proto)->getPropertySlot(exec, propertyName, slot)) { if (!allowsAccess) { printErrorMessage(errorMessage); slot.setUndefined(); } return true; } } // FIXME: Search the whole frame hierarchy somewhere around here. // We need to test the correct priority order. // allow window[1] or parent[1] etc. (#56983) bool ok; unsigned i = propertyName.toArrayIndex(ok); if (ok && i < impl()->frame()->tree()->childCount()) { slot.setCustomIndex(this, i, indexGetter); return true; } if (!allowsAccess) { printErrorMessage(errorMessage); slot.setUndefined(); return true; } // Allow shortcuts like 'Image1' instead of document.images.Image1 Document* document = impl()->frame()->document(); if (document->isHTMLDocument()) { AtomicStringImpl* atomicPropertyName = findAtomicString(propertyName); if (atomicPropertyName && (static_cast<HTMLDocument*>(document)->hasNamedItem(atomicPropertyName) || document->hasElementWithId(atomicPropertyName))) { slot.setCustom(this, namedItemGetter); return true; } } return Base::getOwnPropertySlot(exec, propertyName, slot); }