summaryrefslogtreecommitdiff
path: root/Source/WebCore/bindings/js/JSLocationCustom.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/bindings/js/JSLocationCustom.cpp')
-rw-r--r--Source/WebCore/bindings/js/JSLocationCustom.cpp228
1 files changed, 90 insertions, 138 deletions
diff --git a/Source/WebCore/bindings/js/JSLocationCustom.cpp b/Source/WebCore/bindings/js/JSLocationCustom.cpp
index c99f904d8..57eb752da 100644
--- a/Source/WebCore/bindings/js/JSLocationCustom.cpp
+++ b/Source/WebCore/bindings/js/JSLocationCustom.cpp
@@ -23,31 +23,23 @@
#include "config.h"
#include "JSLocation.h"
-#include "Location.h"
+#include "JSDOMBinding.h"
+#include "JSDOMBindingSecurity.h"
+#include "JSDOMExceptionHandling.h"
+#include "RuntimeApplicationChecks.h"
#include <runtime/JSFunction.h>
+#include <runtime/Lookup.h>
using namespace JSC;
namespace WebCore {
-static EncodedJSValue nonCachingStaticReplaceFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName)
+bool JSLocation::getOwnPropertySlotDelegate(ExecState* state, PropertyName propertyName, PropertySlot& slot)
{
- return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 1, propertyName.publicName(), jsLocationPrototypeFunctionReplace));
-}
-
-static EncodedJSValue nonCachingStaticReloadFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName)
-{
- return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 0, propertyName.publicName(), jsLocationPrototypeFunctionReload));
-}
+ VM& vm = state->vm();
+ auto scope = DECLARE_THROW_SCOPE(vm);
-static EncodedJSValue nonCachingStaticAssignFunctionGetter(ExecState* exec, EncodedJSValue, EncodedJSValue, PropertyName propertyName)
-{
- return JSValue::encode(JSFunction::create(exec->vm(), exec->lexicalGlobalObject(), 1, propertyName.publicName(), jsLocationPrototypeFunctionAssign));
-}
-
-bool JSLocation::getOwnPropertySlotDelegate(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
-{
- Frame* frame = impl().frame();
+ Frame* frame = wrapped().frame();
if (!frame) {
slot.setUndefined();
return true;
@@ -59,56 +51,55 @@ bool JSLocation::getOwnPropertySlotDelegate(ExecState* exec, PropertyName proper
// Our custom code is only needed to implement the Window cross-domain scheme, so if access is
// allowed, return false so the normal lookup will take place.
String message;
- if (shouldAllowAccessToFrame(exec, frame, message))
+ if (BindingSecurity::shouldAllowAccessToFrame(*state, *frame, message))
return false;
- // Check for the few functions that we allow, even when called cross-domain.
- // Make these read-only / non-configurable to prevent writes via defineProperty.
- const HashEntry* entry = JSLocationPrototype::info()->propHashTable(exec)->entry(exec, propertyName);
- if (entry && (entry->attributes() & JSC::Function)) {
- if (entry->function() == jsLocationPrototypeFunctionReplace) {
- slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticReplaceFunctionGetter);
- return true;
- } else if (entry->function() == jsLocationPrototypeFunctionReload) {
- slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticReloadFunctionGetter);
- return true;
- } else if (entry->function() == jsLocationPrototypeFunctionAssign) {
- slot.setCustom(this, ReadOnly | DontDelete | DontEnum, nonCachingStaticAssignFunctionGetter);
- return true;
- }
+ // https://html.spec.whatwg.org/#crossorigingetownpropertyhelper-(-o,-p-)
+ if (propertyName == state->propertyNames().toStringTagSymbol || propertyName == state->propertyNames().hasInstanceSymbol || propertyName == state->propertyNames().isConcatSpreadableSymbol) {
+ slot.setValue(this, ReadOnly | DontEnum, jsUndefined());
+ return true;
}
- // FIXME: Other implementers of the Window cross-domain scheme (Window, History) allow toString,
- // but for now we have decided not to, partly because it seems silly to return "[Object Location]" in
- // such cases when normally the string form of Location would be the URL.
+ // We only allow access to Location.replace() cross origin.
+ if (propertyName == state->propertyNames().replace) {
+ slot.setCustom(this, ReadOnly | DontEnum, nonCachingStaticFunctionGetter<jsLocationInstanceFunctionReplace, 1>);
+ return true;
+ }
- printErrorMessageForFrame(frame, message);
+ // Getting location.href cross origin needs to throw. However, getOwnPropertyDescriptor() needs to return
+ // a descriptor that has a setter but no getter.
+ if (slot.internalMethodType() == PropertySlot::InternalMethodType::GetOwnProperty && propertyName == state->propertyNames().href) {
+ auto* entry = JSLocation::info()->staticPropHashTable->entry(propertyName);
+ CustomGetterSetter* customGetterSetter = CustomGetterSetter::create(vm, nullptr, entry->propertyPutter());
+ slot.setCustomGetterSetter(this, DontEnum | CustomAccessor, customGetterSetter);
+ return true;
+ }
+
+ throwSecurityError(*state, scope, message);
slot.setUndefined();
return true;
}
-bool JSLocation::putDelegate(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
+bool JSLocation::putDelegate(ExecState* state, PropertyName propertyName, JSValue, PutPropertySlot&, bool& putResult)
{
- Frame* frame = impl().frame();
+ putResult = false;
+
+ Frame* frame = wrapped().frame();
if (!frame)
return true;
- if (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf)
+ // Silently block access to toString and valueOf.
+ if (propertyName == state->propertyNames().toString || propertyName == state->propertyNames().valueOf)
return true;
- bool sameDomainAccess = shouldAllowAccessToFrame(exec, frame);
-
- const HashEntry* entry = JSLocation::info()->propHashTable(exec)->entry(exec, propertyName);
- if (!entry) {
- if (sameDomainAccess)
- JSObject::put(this, exec, propertyName, value, slot);
- return true;
- }
+ // Always allow assigning to the whole location.
+ // However, alllowing assigning of pieces might inadvertently disclose parts of the original location.
+ // So fall through to the access check for those.
+ if (propertyName == state->propertyNames().href)
+ return false;
- // Cross-domain access to the location is allowed when assigning the whole location,
- // but not when assigning the individual pieces, since that might inadvertently
- // disclose other parts of the original location.
- if (entry->propertyPutter() != setJSLocationHref && !sameDomainAccess)
+ // Block access and throw if there is a security error.
+ if (!BindingSecurity::shouldAllowAccessToFrame(state, frame, ThrowSecurityError))
return true;
return false;
@@ -118,7 +109,7 @@ bool JSLocation::deleteProperty(JSCell* cell, ExecState* exec, PropertyName prop
{
JSLocation* thisObject = jsCast<JSLocation*>(cell);
// Only allow deleting by frames in the same origin.
- if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame()))
+ if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), ThrowSecurityError))
return false;
return Base::deleteProperty(thisObject, exec, propertyName);
}
@@ -127,128 +118,89 @@ bool JSLocation::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned p
{
JSLocation* thisObject = jsCast<JSLocation*>(cell);
// Only allow deleting by frames in the same origin.
- if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame()))
+ if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), ThrowSecurityError))
return false;
return Base::deletePropertyByIndex(thisObject, exec, propertyName);
}
-void JSLocation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+// https://html.spec.whatwg.org/#crossoriginproperties-(-o-)
+static void addCrossOriginPropertyNames(ExecState& state, PropertyNameArray& propertyNames)
{
- JSLocation* thisObject = jsCast<JSLocation*>(object);
- // Only allow the location object to enumerated by frames in the same origin.
- if (!shouldAllowAccessToFrame(exec, thisObject->impl().frame()))
- return;
- Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+ static const Identifier* const properties[] = { &state.propertyNames().href, &state.propertyNames().replace };
+ for (auto* property : properties)
+ propertyNames.add(*property);
}
-bool JSLocation::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
+// https://html.spec.whatwg.org/#crossoriginownpropertykeys-(-o-)
+static void addCrossOriginOwnPropertyNames(ExecState& state, PropertyNameArray& propertyNames)
{
- if (descriptor.isAccessorDescriptor() && (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf))
- return false;
- return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
-}
+ addCrossOriginPropertyNames(state, propertyNames);
-void JSLocation::setHref(ExecState* exec, JSValue value)
-{
- String href = value.toString(exec)->value(exec);
- if (exec->hadException())
- return;
- impl().setHref(href, activeDOMWindow(exec), firstDOMWindow(exec));
+ propertyNames.add(state.propertyNames().toStringTagSymbol);
+ propertyNames.add(state.propertyNames().hasInstanceSymbol);
+ propertyNames.add(state.propertyNames().isConcatSpreadableSymbol);
}
-void JSLocation::setProtocol(ExecState* exec, JSValue value)
+void JSLocation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
{
- String protocol = value.toString(exec)->value(exec);
- if (exec->hadException())
+ JSLocation* thisObject = jsCast<JSLocation*>(object);
+ if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), DoNotReportSecurityError)) {
+ if (mode.includeDontEnumProperties())
+ addCrossOriginOwnPropertyNames(*exec, propertyNames);
return;
- ExceptionCode ec = 0;
- impl().setProtocol(protocol, activeDOMWindow(exec), firstDOMWindow(exec), ec);
- setDOMException(exec, ec);
+ }
+ Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
}
-void JSLocation::setHost(ExecState* exec, JSValue value)
+bool JSLocation::defineOwnProperty(JSObject* object, ExecState* exec, PropertyName propertyName, const PropertyDescriptor& descriptor, bool throwException)
{
- String host = value.toString(exec)->value(exec);
- if (exec->hadException())
- return;
- impl().setHost(host, activeDOMWindow(exec), firstDOMWindow(exec));
-}
+ JSLocation* thisObject = jsCast<JSLocation*>(object);
+ if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), ThrowSecurityError))
+ return false;
-void JSLocation::setHostname(ExecState* exec, JSValue value)
-{
- String hostname = value.toString(exec)->value(exec);
- if (exec->hadException())
- return;
- impl().setHostname(hostname, activeDOMWindow(exec), firstDOMWindow(exec));
+ if (descriptor.isAccessorDescriptor() && (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf))
+ return false;
+ return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
-void JSLocation::setPort(ExecState* exec, JSValue value)
+bool JSLocation::setPrototype(JSObject*, ExecState* exec, JSValue, bool shouldThrowIfCantSet)
{
- String port = value.toWTFString(exec);
- if (exec->hadException())
- return;
- impl().setPort(port, activeDOMWindow(exec), firstDOMWindow(exec));
-}
+ auto scope = DECLARE_THROW_SCOPE(exec->vm());
-void JSLocation::setPathname(ExecState* exec, JSValue value)
-{
- String pathname = value.toString(exec)->value(exec);
- if (exec->hadException())
- return;
- impl().setPathname(pathname, activeDOMWindow(exec), firstDOMWindow(exec));
-}
+ if (shouldThrowIfCantSet)
+ throwTypeError(exec, scope, ASCIILiteral("Cannot set prototype of this object"));
-void JSLocation::setSearch(ExecState* exec, JSValue value)
-{
- String pathname = value.toString(exec)->value(exec);
- if (exec->hadException())
- return;
- impl().setSearch(pathname, activeDOMWindow(exec), firstDOMWindow(exec));
+ return false;
}
-void JSLocation::setHash(ExecState* exec, JSValue value)
+JSValue JSLocation::getPrototype(JSObject* object, ExecState* exec)
{
- String hash = value.toString(exec)->value(exec);
- if (exec->hadException())
- return;
- impl().setHash(hash, activeDOMWindow(exec), firstDOMWindow(exec));
-}
+ JSLocation* thisObject = jsCast<JSLocation*>(object);
+ if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), DoNotReportSecurityError))
+ return jsNull();
-JSValue JSLocation::replace(ExecState* exec)
-{
- String urlString = exec->argument(0).toString(exec)->value(exec);
- if (exec->hadException())
- return jsUndefined();
- impl().replace(urlString, activeDOMWindow(exec), firstDOMWindow(exec));
- return jsUndefined();
+ return Base::getPrototype(object, exec);
}
-JSValue JSLocation::reload(ExecState* exec)
+bool JSLocation::preventExtensions(JSObject*, ExecState* exec)
{
- impl().reload(activeDOMWindow(exec));
- return jsUndefined();
-}
+ auto scope = DECLARE_THROW_SCOPE(exec->vm());
-JSValue JSLocation::assign(ExecState* exec)
-{
- String urlString = exec->argument(0).toString(exec)->value(exec);
- if (exec->hadException())
- return jsUndefined();
- impl().assign(urlString, activeDOMWindow(exec), firstDOMWindow(exec));
- return jsUndefined();
+ throwTypeError(exec, scope, ASCIILiteral("Cannot prevent extensions on this object"));
+ return false;
}
-JSValue JSLocation::toStringFunction(ExecState* exec)
+String JSLocation::toStringName(const JSObject* object, ExecState* exec)
{
- Frame* frame = impl().frame();
- if (!frame || !shouldAllowAccessToFrame(exec, frame))
- return jsUndefined();
-
- return jsStringWithCache(exec, impl().toString());
+ auto* thisObject = jsCast<const JSLocation*>(object);
+ if (!BindingSecurity::shouldAllowAccessToFrame(exec, thisObject->wrapped().frame(), DoNotReportSecurityError))
+ return ASCIILiteral("Object");
+ return ASCIILiteral("Location");
}
-bool JSLocationPrototype::putDelegate(ExecState* exec, PropertyName propertyName, JSValue, PutPropertySlot&)
+bool JSLocationPrototype::putDelegate(ExecState* exec, PropertyName propertyName, JSValue, PutPropertySlot&, bool& putResult)
{
+ putResult = false;
return (propertyName == exec->propertyNames().toString || propertyName == exec->propertyNames().valueOf);
}