aboutsummaryrefslogtreecommitdiffstats
path: root/src/qml/qml
diff options
context:
space:
mode:
authorChris Adams <christopher.adams@nokia.com>2012-04-23 16:37:05 +1000
committerQt by Nokia <qt-info@nokia.com>2012-07-02 09:43:36 +0200
commitfdeee38b781376012c4f086276c3c376726c8839 (patch)
treee35e5f02ec00a1750854bb81c7e4d5d85a4dd8ae /src/qml/qml
parent4c02780738241d784849f423944a8a4852022967 (diff)
Fix crash in QQmlXmlHttpRequest
If an onreadystatechange handler of a QQmlXmlHttpRequest uses code which requires the engine->callingContext() to be valid, a crash could previously occur (since the callingContext() would be null if the handler was called due to a network request finishing. This commit saves the calling context on send, so that on dispatch we can create an activation scope from that context and use it. Note that even in this case, if the original context had previously been deleted (e.g., by a loader deleting the item context on source change) the saved context could be invalid by the time the dispatch function was invoked. In that case, we simply do nothing as the function call cannot succeed (invalid context). Change-Id: Iba357829a69433c11cc279e6cc9fdc0bedaa31fb Reviewed-by: Yunqiao Yin <charles.yin@nokia.com>
Diffstat (limited to 'src/qml/qml')
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp57
1 files changed, 49 insertions, 8 deletions
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 9d4c64b2ca..11ba552a44 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -98,6 +98,14 @@ static inline QQmlXMLHttpRequestData *xhrdata(QV8Engine *engine)
return (QQmlXMLHttpRequestData *)engine->xmlHttpRequestData();
}
+static v8::Local<v8::Object> constructMeObject(v8::Handle<v8::Object> thisObj, QV8Engine *e)
+{
+ v8::Local<v8::Object> meObj = v8::Object::New();
+ meObj->Set(v8::String::New("ThisObject"), thisObj);
+ meObj->Set(v8::String::New("ActivationObject"), e->qmlScope(e->callingContext(), 0));
+ return meObj;
+}
+
QQmlXMLHttpRequestData::QQmlXMLHttpRequestData()
{
}
@@ -1075,7 +1083,9 @@ v8::Handle<v8::Value> QQmlXMLHttpRequest::open(v8::Handle<v8::Object> me, const
m_method = method;
m_url = url;
m_state = Opened;
+ v8::TryCatch tc;
dispatchCallback(me);
+ if (tc.HasCaught()) printError(tc.Message());
return v8::Undefined();
}
@@ -1216,7 +1226,9 @@ v8::Handle<v8::Value> QQmlXMLHttpRequest::abort(v8::Handle<v8::Object> me)
m_state = Done;
m_sendFlag = false;
+ v8::TryCatch tc;
dispatchCallback(me);
+ if (tc.HasCaught()) printError(tc.Message());
}
m_state = Unsent;
@@ -1355,7 +1367,6 @@ void QQmlXMLHttpRequest::finished()
}
}
-
m_data.clear();
destroyNetwork();
if (m_state < Loading) {
@@ -1451,12 +1462,42 @@ const QByteArray &QQmlXMLHttpRequest::rawResponseBody() const
// Requires a TryCatch scope
void QQmlXMLHttpRequest::dispatchCallback(v8::Handle<v8::Object> me)
{
- v8::Local<v8::Value> callback = me->Get(v8::String::New("onreadystatechange"));
- if (callback->IsFunction()) {
- v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
+ v8::HandleScope hs;
+ v8::Context::Scope scope(engine->context());
- f->Call(me, 0, 0);
+ if (me.IsEmpty() || me->IsNull()) {
+ v8::ThrowException(v8::Exception::Error(v8::String::New("Unable to dispatch QQmlXmlHttpRequest callback: invalid object")));
+ return;
}
+
+ if (me->Get(v8::String::New("ThisObject")).IsEmpty()) {
+ v8::ThrowException(v8::Exception::Error(v8::String::New("QQmlXMLHttpRequest: internal error: empty ThisObject")));
+ return;
+ }
+
+ v8::Local<v8::Object> thisObj = me->Get(v8::String::New("ThisObject"))->ToObject();
+ v8::Local<v8::Value> callback = thisObj->Get(v8::String::New("onreadystatechange"));
+ if (!callback->IsFunction()) {
+ // not an error, but no onreadystatechange function to call.
+ return;
+ }
+
+ if (me->Get(v8::String::New("ActivationObject")).IsEmpty()) {
+ v8::ThrowException(v8::Exception::Error(v8::String::New("QQmlXMLHttpRequest: internal error: empty ActivationObject")));
+ return;
+ }
+
+ v8::Local<v8::Object> activationObject = me->Get(v8::String::New("ActivationObject"))->ToObject();
+ QQmlContextData *callingContext = engine->contextWrapper()->context(activationObject);
+ if (callingContext) {
+ v8::Local<v8::Function> f = v8::Local<v8::Function>::Cast(callback);
+ f->Call(activationObject, 0, 0); // valid activation object.
+ }
+
+ // if the callingContext object is no longer valid, then it has been
+ // deleted explicitly (e.g., by a Loader deleting the itemContext when
+ // the source is changed). We do nothing in this case, as the evaluation
+ // cannot succeed.
}
// Must have a handle scope
@@ -1523,7 +1564,7 @@ static v8::Handle<v8::Value> qmlxmlhttprequest_open(const v8::Arguments &args)
if (!username.isNull()) url.setUserName(username);
if (!password.isNull()) url.setPassword(password);
- return r->open(args.This(), method, url);
+ return r->open(constructMeObject(args.This(), engine), method, url);
}
static v8::Handle<v8::Value> qmlxmlhttprequest_setRequestHeader(const v8::Arguments &args)
@@ -1589,7 +1630,7 @@ static v8::Handle<v8::Value> qmlxmlhttprequest_send(const v8::Arguments &args)
if (args.Length() > 0)
data = engine->toString(args[0]).toUtf8();
- return r->send(args.This(), data);
+ return r->send(constructMeObject(args.This(), engine), data);
}
static v8::Handle<v8::Value> qmlxmlhttprequest_abort(const v8::Arguments &args)
@@ -1598,7 +1639,7 @@ static v8::Handle<v8::Value> qmlxmlhttprequest_abort(const v8::Arguments &args)
if (!r)
V8THROW_REFERENCE("Not an XMLHttpRequest object");
- return r->abort(args.This());
+ return r->abort(constructMeObject(args.This(), r->engine));
}
static v8::Handle<v8::Value> qmlxmlhttprequest_getResponseHeader(const v8::Arguments &args)