mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 19:02:48 +00:00
192 lines
6.7 KiB
C++
192 lines
6.7 KiB
C++
![]() |
/*
|
||
|
* This file is part of the KDE libraries
|
||
|
* Copyright (C) 2010 Maksim Orlovich <maksim@kde.org>
|
||
|
*
|
||
|
* This library is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU Lesser General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 2 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* This library is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public
|
||
|
* License along with this library; if not, write to the Free Software
|
||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
#include "khtml_part.h"
|
||
|
#include "kjs_data.h"
|
||
|
#include <dom/dom_exception.h>
|
||
|
#include <kjs/array_instance.h>
|
||
|
|
||
|
#include <QSet>
|
||
|
|
||
|
using namespace DOM;
|
||
|
using namespace khtml;
|
||
|
|
||
|
namespace KJS {
|
||
|
|
||
|
// HTML5 deep copy algorithm, as described in "2.7.5 Safe passing of structured data"
|
||
|
static JSValue* cloneInternal(ExecState* exec, Interpreter* ctx, JSValue* in, QSet<JSObject*>& path)
|
||
|
{
|
||
|
if (exec->hadException()) // e.g. OOM or DATA_CLONE_ERR
|
||
|
return jsUndefined();
|
||
|
|
||
|
switch (in->type()) {
|
||
|
case NumberType:
|
||
|
case BooleanType:
|
||
|
case UndefinedType:
|
||
|
case NullType:
|
||
|
case StringType:
|
||
|
// Values -> can pass straight through.
|
||
|
return in;
|
||
|
|
||
|
case ObjectType: {
|
||
|
JSObject* obj = in->getObject();
|
||
|
|
||
|
// Some things are handled by creating a new wrapper for their value;
|
||
|
// this includes both JS-builtin types like autoboxing wrappers, and
|
||
|
// those of HTML5 types we support that have deep cloning specified.
|
||
|
// This goes through valueClone.
|
||
|
if (JSObject* copy = obj->valueClone(ctx))
|
||
|
return copy;
|
||
|
|
||
|
// Otherwise, we can only clone if it it's an array or plain object
|
||
|
// that isn't already on our path from the root
|
||
|
if (path.contains(obj)) {
|
||
|
setDOMException(exec, DOM::DOMException::DATA_CLONE_ERR);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
path.insert(obj);
|
||
|
|
||
|
JSObject* clone = 0;
|
||
|
if (obj->inherits(&ArrayInstance::info)) {
|
||
|
clone = new ArrayInstance(ctx->builtinArrayPrototype(), 0);
|
||
|
} else if (!obj->classInfo()) { // plain object
|
||
|
clone = new JSObject(ctx->builtinObjectPrototype());
|
||
|
} else {
|
||
|
// Something complicated and native -> error out
|
||
|
setDOMException(exec, DOM::DOMException::DATA_CLONE_ERR);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Copy over clones of properties
|
||
|
PropertyNameArray props;
|
||
|
obj->getOwnPropertyNames(exec, props, PropertyMap::ExcludeDontEnumProperties);
|
||
|
for (PropertyNameArrayIterator i = props.begin(); i != props.end(); ++i) {
|
||
|
JSValue* propVal = obj->get(exec, *i);
|
||
|
clone->put(exec, *i, cloneInternal(exec, ctx, propVal, path)); // ### flags?
|
||
|
}
|
||
|
|
||
|
path.remove(obj);
|
||
|
|
||
|
return clone;
|
||
|
}
|
||
|
|
||
|
default: // shouldn't happen!
|
||
|
setDOMException(exec, DOM::DOMException::DATA_CLONE_ERR);
|
||
|
}
|
||
|
|
||
|
return jsUndefined();
|
||
|
}
|
||
|
|
||
|
JSValue* cloneData(ExecState* exec, JSValue* data)
|
||
|
{
|
||
|
QSet<JSObject*> visited;
|
||
|
return cloneInternal(exec, exec->dynamicInterpreter(), data, visited);
|
||
|
}
|
||
|
|
||
|
class JSMessageData : public DOM::MessageEventImpl::Data {
|
||
|
public:
|
||
|
virtual DOM::MessageEventImpl::DataType messageDataType() const {
|
||
|
return DOM::MessageEventImpl::JS_VALUE;
|
||
|
}
|
||
|
|
||
|
JSMessageData(JSValue* val): m_value(val) {}
|
||
|
|
||
|
ProtectedPtr<JSValue> m_value;
|
||
|
};
|
||
|
|
||
|
DOM::MessageEventImpl::Data* encapsulateMessageEventData(ExecState* exec, Interpreter* ctx,
|
||
|
JSValue* data)
|
||
|
{
|
||
|
QSet<JSObject*> visited;
|
||
|
JSValue* copy = cloneInternal(exec, ctx, data, visited);
|
||
|
if (exec->hadException())
|
||
|
return 0;
|
||
|
else
|
||
|
return new JSMessageData(copy);
|
||
|
}
|
||
|
|
||
|
JSValue* getMessageEventData(ExecState* /*exec*/, DOM::MessageEventImpl::Data* data)
|
||
|
{
|
||
|
if (data && data->messageDataType() == DOM::MessageEventImpl::JS_VALUE)
|
||
|
return static_cast<JSMessageData*>(data)->m_value.get();
|
||
|
else
|
||
|
return jsUndefined();
|
||
|
}
|
||
|
|
||
|
//------------------------------------------------------------------------------
|
||
|
DelayedPostMessage::DelayedPostMessage(KHTMLPart* _source,
|
||
|
const QString& _sourceOrigin,
|
||
|
const QString& _targetOrigin,
|
||
|
JSValue* _payload):
|
||
|
sourceOrigin(_sourceOrigin), targetOrigin(_targetOrigin), payload(_payload), source(_source)
|
||
|
{}
|
||
|
|
||
|
void DelayedPostMessage::mark()
|
||
|
{
|
||
|
if (!payload->marked())
|
||
|
payload->mark();
|
||
|
}
|
||
|
|
||
|
bool DelayedPostMessage::execute(Window* w)
|
||
|
{
|
||
|
KHTMLPart* part = qobject_cast<KHTMLPart*>(w->part());
|
||
|
DOM::DocumentImpl* doc = part ? static_cast<DOM::DocumentImpl*>(part->document().handle()) : 0;
|
||
|
KJSProxy* js = part ? KJSProxy::proxy(part) : 0;
|
||
|
|
||
|
kDebug(6070) << doc << js << sourceOrigin << targetOrigin;
|
||
|
if (doc && js) {
|
||
|
// Verify destination.
|
||
|
bool safe = false;
|
||
|
if (targetOrigin == QLatin1String("*")) {
|
||
|
safe = true;
|
||
|
} else {
|
||
|
RefPtr<SecurityOrigin> targetCtx =
|
||
|
SecurityOrigin::createFromString(targetOrigin);
|
||
|
safe = doc->origin()->isSameSchemeHostPort(targetCtx.get());
|
||
|
}
|
||
|
|
||
|
if (safe) {
|
||
|
RefPtr<MessageEventImpl> msg = new MessageEventImpl();
|
||
|
|
||
|
DOM::MessageEventImpl::Data* data =
|
||
|
encapsulateMessageEventData(js->interpreter()->globalExec(),
|
||
|
js->interpreter(), payload);
|
||
|
|
||
|
msg->initMessageEvent("message",
|
||
|
false, false, // doesn't bubble or cancel
|
||
|
data,
|
||
|
sourceOrigin,
|
||
|
DOMString(), // lastEventId -- not here
|
||
|
source.data());
|
||
|
doc->dispatchWindowEvent(msg.get());
|
||
|
} else {
|
||
|
kWarning(6070) << "PostMessage XSS check failed;"
|
||
|
<< "target mask:" << targetOrigin
|
||
|
<< "actual:" << doc->origin()->toString()
|
||
|
<< "source:" << sourceOrigin;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
} // namespace KJS
|
||
|
|
||
|
// kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;
|