aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/qml/doc/src/javascript/qmlglobalobject.qdoc1
-rw-r--r--src/qml/qml/qqmlxmlhttprequest.cpp41
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/data/open_sync.qml14
-rw-r--r--tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp39
4 files changed, 72 insertions, 23 deletions
diff --git a/src/qml/doc/src/javascript/qmlglobalobject.qdoc b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
index 62ec296178..fd702cd879 100644
--- a/src/qml/doc/src/javascript/qmlglobalobject.qdoc
+++ b/src/qml/doc/src/javascript/qmlglobalobject.qdoc
@@ -57,7 +57,6 @@ The XMLHttpRequest API implements the same \l {http://www.w3.org/TR/XMLHttpReque
as many popular web browsers with following exceptions:
\list
\li QML's XMLHttpRequest does not enforce the same origin policy.
-\li QML's XMLHttpRequest does not support \e synchronous requests.
\endlist
Additionally, the \c responseXML XML DOM tree currently supported by QML is a reduced subset
diff --git a/src/qml/qml/qqmlxmlhttprequest.cpp b/src/qml/qml/qqmlxmlhttprequest.cpp
index 517f5a8b59..0117432e31 100644
--- a/src/qml/qml/qqmlxmlhttprequest.cpp
+++ b/src/qml/qml/qqmlxmlhttprequest.cpp
@@ -1040,6 +1040,10 @@ class QQmlXMLHttpRequest : public QObject
{
Q_OBJECT
public:
+ enum LoadType {
+ AsynchronousLoad,
+ SynchronousLoad
+ };
enum State { Unsent = 0,
Opened = 1, HeadersReceived = 2,
Loading = 3, Done = 4 };
@@ -1053,7 +1057,7 @@ public:
int replyStatus() const;
QString replyStatusText() const;
- ReturnedValue open(const ValueRef me, const QString &, const QUrl &);
+ ReturnedValue open(const ValueRef me, const QString &, const QUrl &, LoadType);
ReturnedValue send(const ValueRef me, const QByteArray &);
ReturnedValue abort(const ValueRef me);
@@ -1152,7 +1156,7 @@ QString QQmlXMLHttpRequest::replyStatusText() const
return m_statusText;
}
-ReturnedValue QQmlXMLHttpRequest::open(const ValueRef me, const QString &method, const QUrl &url)
+ReturnedValue QQmlXMLHttpRequest::open(const ValueRef me, const QString &method, const QUrl &url, LoadType loadType)
{
destroyNetwork();
m_sendFlag = false;
@@ -1160,6 +1164,7 @@ ReturnedValue QQmlXMLHttpRequest::open(const ValueRef me, const QString &method,
m_responseEntityBody = QByteArray();
m_method = method;
m_url = url;
+ m_request.setAttribute(QNetworkRequest::SynchronousRequestAttribute, loadType == SynchronousLoad);
m_state = Opened;
m_addedHeaders.clear();
dispatchCallback(me);
@@ -1276,12 +1281,24 @@ void QQmlXMLHttpRequest::requestFromUrl(const QUrl &url)
buffer->setParent(m_network);
}
- QObject::connect(m_network, SIGNAL(readyRead()),
- this, SLOT(readyRead()));
- QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)),
- this, SLOT(error(QNetworkReply::NetworkError)));
- QObject::connect(m_network, SIGNAL(finished()),
- this, SLOT(finished()));
+ if (m_request.attribute(QNetworkRequest::SynchronousRequestAttribute).toBool()) {
+ if (m_network->bytesAvailable() > 0)
+ readyRead();
+
+ QNetworkReply::NetworkError networkError = m_network->error();
+ if (networkError != QNetworkReply::NoError) {
+ error(networkError);
+ } else {
+ finished();
+ }
+ } else {
+ QObject::connect(m_network, SIGNAL(readyRead()),
+ this, SLOT(readyRead()));
+ QObject::connect(m_network, SIGNAL(error(QNetworkReply::NetworkError)),
+ this, SLOT(error(QNetworkReply::NetworkError)));
+ QObject::connect(m_network, SIGNAL(finished()),
+ this, SLOT(finished()));
+ }
}
ReturnedValue QQmlXMLHttpRequest::send(const ValueRef me, const QByteArray &data)
@@ -1759,9 +1776,11 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
if (url.isRelative())
url = engine->callingContext()->resolvedUrl(url);
+ bool async = true;
// Argument 2 - async (optional)
- if (ctx->d()->callData->argc > 2 && !ctx->d()->callData->args[2].booleanValue())
- V4THROW_DOM(DOMEXCEPTION_NOT_SUPPORTED_ERR, "Synchronous XMLHttpRequest calls are not supported");
+ if (ctx->d()->callData->argc > 2) {
+ async = ctx->d()->callData->args[2].booleanValue();
+ }
// Argument 3/4 - user/pass (optional)
QString username, password;
@@ -1778,7 +1797,7 @@ ReturnedValue QQmlXMLHttpRequestCtor::method_open(CallContext *ctx)
if (!password.isNull()) url.setPassword(password);
ScopedValue meObject(scope, constructMeObject(ctx->d()->callData->thisObject, engine));
- return r->open(meObject, method, url);
+ return r->open(meObject, method, url, async ? QQmlXMLHttpRequest::AsynchronousLoad : QQmlXMLHttpRequest::SynchronousLoad);
}
ReturnedValue QQmlXMLHttpRequestCtor::method_setRequestHeader(CallContext *ctx)
diff --git a/tests/auto/qml/qqmlxmlhttprequest/data/open_sync.qml b/tests/auto/qml/qqmlxmlhttprequest/data/open_sync.qml
index 0f31c966fa..3c73141954 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/data/open_sync.qml
+++ b/tests/auto/qml/qqmlxmlhttprequest/data/open_sync.qml
@@ -1,17 +1,15 @@
import QtQuick 2.0
QtObject {
- property bool exceptionThrown: false
+ property url url
+ property string responseText
Component.onCompleted: {
var x = new XMLHttpRequest;
-
- try {
- x.open("GET", "http://www.qt-project.org", false);
- } catch (e) {
- if (e.code == DOMException.NOT_SUPPORTED_ERR)
- exceptionThrown = true;
- }
+ x.open("GET", url, false);
+ x.setRequestHeader("Accept-Language", "en-US");
+ x.send();
+ responseText = x.responseText;
}
}
diff --git a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
index 441893a853..0d70e47b3d 100644
--- a/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
+++ b/tests/auto/qml/qqmlxmlhttprequest/tst_qqmlxmlhttprequest.cpp
@@ -37,6 +37,7 @@
#include <QDebug>
#include <QScopedPointer>
#include <QNetworkCookieJar>
+#include <QThread>
#include "testhttpserver.h"
#include "../../shared/util.h"
@@ -282,14 +283,46 @@ void tst_qqmlxmlhttprequest::open_invalid_method()
QCOMPARE(object->property("exceptionThrown").toBool(), true);
}
-// Test that calling XMLHttpRequest.open() with sync raises an exception
+class TestThreadedHTTPServer : public QObject
+{
+ Q_OBJECT
+public:
+ TestThreadedHTTPServer(const QUrl &expectUrl, const QUrl &replyUrl, const QUrl &bodyUrl)
+ : m_server(Q_NULLPTR) {
+ moveToThread(&m_thread);
+ m_thread.start();
+ QMetaObject::invokeMethod(this, "start", Qt::QueuedConnection, Q_ARG(QUrl, expectUrl), Q_ARG(QUrl, replyUrl), Q_ARG(QUrl, bodyUrl));
+ }
+ ~TestThreadedHTTPServer() {
+ m_server->deleteLater();
+ m_thread.exit();
+ m_thread.wait();
+ }
+
+private slots:
+ void start(const QUrl &expectUrl, const QUrl &replyUrl, const QUrl &bodyUrl) {
+ m_server = new TestHTTPServer;
+ QVERIFY2(m_server->listen(SERVER_PORT), qPrintable(m_server->errorString()));
+ QVERIFY(m_server->wait(expectUrl, replyUrl, bodyUrl));
+ }
+
+private:
+ TestHTTPServer *m_server;
+ QThread m_thread;
+};
+
+// Test that calling XMLHttpRequest.open() with sync
void tst_qqmlxmlhttprequest::open_sync()
{
+ TestThreadedHTTPServer server(testFileUrl("open_network.expect"), testFileUrl("open_network.reply"), testFileUrl("testdocument.html"));
+
QQmlComponent component(&engine, testFileUrl("open_sync.qml"));
- QScopedPointer<QObject> object(component.create());
+ QScopedPointer<QObject> object(component.beginCreate(engine.rootContext()));
QVERIFY(!object.isNull());
+ object->setProperty("url", "http://127.0.0.1:14445/testdocument.html");
+ component.completeCreate();
- QCOMPARE(object->property("exceptionThrown").toBool(), true);
+ QCOMPARE(object->property("responseText").toString(), QStringLiteral("QML Rocks!\n"));
}
// Calling with incorrect arg count raises an exception