summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAaron Kennedy <aaron.kennedy@nokia.com>2010-02-03 06:45:41 (GMT)
committerAaron Kennedy <aaron.kennedy@nokia.com>2010-02-03 06:46:26 (GMT)
commit142dc7e75faaf76894633851c25a907bd7e8b9b8 (patch)
tree3e4783e7576e47c16ba99a8a7d095058a29ab4ed
parent6abdaa41a3f40238e8a60b80b9ac55a694181e11 (diff)
downloadQt-142dc7e75faaf76894633851c25a907bd7e8b9b8.zip
Qt-142dc7e75faaf76894633851c25a907bd7e8b9b8.tar.gz
Qt-142dc7e75faaf76894633851c25a907bd7e8b9b8.tar.bz2
XMLHttpRequest redirection
-rw-r--r--src/declarative/qml/qmlxmlhttprequest.cpp44
-rw-r--r--tests/auto/declarative/shared/testhttpserver.cpp11
-rw-r--r--tests/auto/declarative/shared/testhttpserver.h2
-rw-r--r--tests/auto/declarative/xmlhttprequest/data/redirectError.qml23
-rw-r--r--tests/auto/declarative/xmlhttprequest/data/redirectRecur.qml23
-rw-r--r--tests/auto/declarative/xmlhttprequest/data/redirects.qml22
-rw-r--r--tests/auto/declarative/xmlhttprequest/data/redirecttarget.html1
-rw-r--r--tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp67
8 files changed, 181 insertions, 12 deletions
diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp
index f69f254..2c35ebf 100644
--- a/src/declarative/qml/qmlxmlhttprequest.cpp
+++ b/src/declarative/qml/qmlxmlhttprequest.cpp
@@ -966,12 +966,16 @@ private slots:
void finished();
private:
+ void requestFromUrl(const QUrl &url);
+
State m_state;
bool m_errorFlag;
bool m_sendFlag;
QString m_method;
QUrl m_url;
QByteArray m_responseEntityBody;
+ QByteArray m_data;
+ int m_redirectCount;
typedef QPair<QByteArray, QByteArray> HeaderPair;
typedef QList<HeaderPair> HeadersList;
@@ -1001,7 +1005,7 @@ private:
QmlXMLHttpRequest::QmlXMLHttpRequest()
: m_state(Unsent), m_errorFlag(false), m_sendFlag(false),
- m_network(0), m_nam(0)
+ m_redirectCount(0), m_network(0), m_nam(0)
{
}
@@ -1109,16 +1113,10 @@ void QmlXMLHttpRequest::fillHeadersList()
}
}
-QScriptValue QmlXMLHttpRequest::send(const QByteArray &data)
+void QmlXMLHttpRequest::requestFromUrl(const QUrl &url)
{
- m_errorFlag = false;
- m_sendFlag = true;
-
- QScriptValue cbv = dispatchCallback();
- if (cbv.isError()) return cbv;
-
- m_request.setUrl(m_url);
QNetworkRequest request = m_request;
+ request.setUrl(url);
if(m_method == QLatin1String("POST") ||
m_method == QLatin1String("PUT")) {
QVariant var = request.header(QNetworkRequest::ContentTypeHeader);
@@ -1153,9 +1151,9 @@ QScriptValue QmlXMLHttpRequest::send(const QByteArray &data)
else if (m_method == QLatin1String("HEAD"))
m_network = networkAccessManager()->head(request);
else if(m_method == QLatin1String("POST"))
- m_network = networkAccessManager()->post(request, data);
+ m_network = networkAccessManager()->post(request, m_data);
else if(m_method == QLatin1String("PUT"))
- m_network = networkAccessManager()->put(request, data);
+ m_network = networkAccessManager()->put(request, m_data);
QObject::connect(m_network, SIGNAL(downloadProgress(qint64,qint64)),
this, SLOT(downloadProgress(qint64)));
@@ -1163,6 +1161,16 @@ QScriptValue QmlXMLHttpRequest::send(const QByteArray &data)
this, SLOT(error(QNetworkReply::NetworkError)));
QObject::connect(m_network, SIGNAL(finished()),
this, SLOT(finished()));
+}
+
+QScriptValue QmlXMLHttpRequest::send(const QByteArray &data)
+{
+ m_errorFlag = false;
+ m_sendFlag = true;
+ m_redirectCount = 0;
+ m_data = data;
+
+ requestFromUrl(m_url);
return QScriptValue();
}
@@ -1224,6 +1232,7 @@ void QmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
m_responseEntityBody = QByteArray();
m_request = QNetworkRequest();
+ m_data.clear();
destroyNetwork();
if (error == QNetworkReply::ContentAccessDenied ||
@@ -1243,9 +1252,19 @@ void QmlXMLHttpRequest::error(QNetworkReply::NetworkError error)
if (cbv.isError()) printError(cbv);
}
+#define XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION 15
void QmlXMLHttpRequest::finished()
{
- // ### We need to transparently redirect as dictated by the spec
+ m_redirectCount++;
+ if (m_redirectCount < XMLHTTPREQUEST_MAXIMUM_REDIRECT_RECURSION) {
+ QVariant redirect = m_network->attribute(QNetworkRequest::RedirectionTargetAttribute);
+ if (redirect.isValid()) {
+ QUrl url = redirect.toUrl();
+ destroyNetwork();
+ requestFromUrl(url);
+ return;
+ }
+ }
m_status =
m_network->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -1259,6 +1278,7 @@ void QmlXMLHttpRequest::finished()
if (cbv.isError()) printError(cbv);
}
m_responseEntityBody.append(m_network->readAll());
+ m_data.clear();
destroyNetwork();
if (m_state < Loading) {
m_state = Loading;
diff --git a/tests/auto/declarative/shared/testhttpserver.cpp b/tests/auto/declarative/shared/testhttpserver.cpp
index 6c9d849..490fc95 100644
--- a/tests/auto/declarative/shared/testhttpserver.cpp
+++ b/tests/auto/declarative/shared/testhttpserver.cpp
@@ -115,6 +115,11 @@ void TestHTTPServer::addAlias(const QString &filename, const QString &alias)
aliases.insert(filename, alias);
}
+void TestHTTPServer::addRedirect(const QString &filename, const QString &redirectName)
+{
+ redirects.insert(filename, redirectName);
+}
+
bool TestHTTPServer::wait(const QUrl &expect, const QUrl &reply, const QUrl &body)
{
m_hasFailed = false;
@@ -230,6 +235,12 @@ void TestHTTPServer::readyRead()
bool TestHTTPServer::reply(QTcpSocket *socket, const QByteArray &fileName)
{
+ if (redirects.contains(fileName)) {
+ QByteArray response = "HTTP/1.1 302 Found\r\nContent-length: 0\r\nContent-type: text/html; charset=UTF-8\r\nLocation: " + redirects[fileName].toUtf8() + "\r\n\r\n";
+ socket->write(response);
+ return true;
+ }
+
for (int ii = 0; ii < dirs.count(); ++ii) {
QString dir = dirs.at(ii).first;
Mode mode = dirs.at(ii).second;
diff --git a/tests/auto/declarative/shared/testhttpserver.h b/tests/auto/declarative/shared/testhttpserver.h
index 2a8709f..178122d 100644
--- a/tests/auto/declarative/shared/testhttpserver.h
+++ b/tests/auto/declarative/shared/testhttpserver.h
@@ -62,6 +62,7 @@ public:
bool hasFailed() const;
void addAlias(const QString &filename, const QString &aliasName);
+ void addRedirect(const QString &filename, const QString &redirectName);
private slots:
void newConnection();
@@ -83,6 +84,7 @@ private:
bool m_hasFailed;
QHash<QString,QString> aliases;
+ QHash<QString,QString> redirects;
QTcpServer server;
};
diff --git a/tests/auto/declarative/xmlhttprequest/data/redirectError.qml b/tests/auto/declarative/xmlhttprequest/data/redirectError.qml
new file mode 100644
index 0000000..6b345cc
--- /dev/null
+++ b/tests/auto/declarative/xmlhttprequest/data/redirectError.qml
@@ -0,0 +1,23 @@
+import Qt 4.6
+
+QtObject {
+ property string url
+
+ property bool dataOK: false
+ property bool done: false
+
+ Component.onCompleted: {
+ var x = new XMLHttpRequest;
+ x.open("GET", url);
+
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.DONE) {
+ done = true;
+ dataOK = x.status == 404;
+ }
+ }
+
+ x.send();
+ }
+}
+
diff --git a/tests/auto/declarative/xmlhttprequest/data/redirectRecur.qml b/tests/auto/declarative/xmlhttprequest/data/redirectRecur.qml
new file mode 100644
index 0000000..c0321dc
--- /dev/null
+++ b/tests/auto/declarative/xmlhttprequest/data/redirectRecur.qml
@@ -0,0 +1,23 @@
+import Qt 4.6
+
+QtObject {
+ property string url
+
+ property bool dataOK: false
+ property bool done: false
+
+ Component.onCompleted: {
+ var x = new XMLHttpRequest;
+ x.open("GET", url);
+
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.DONE) {
+ done = true;
+ dataOK = x.status == 302;
+ }
+ }
+
+ x.send();
+ }
+}
+
diff --git a/tests/auto/declarative/xmlhttprequest/data/redirects.qml b/tests/auto/declarative/xmlhttprequest/data/redirects.qml
new file mode 100644
index 0000000..f6fabdb
--- /dev/null
+++ b/tests/auto/declarative/xmlhttprequest/data/redirects.qml
@@ -0,0 +1,22 @@
+import Qt 4.6
+
+QtObject {
+ property string url
+
+ property bool dataOK: false
+ property bool done: false
+
+ Component.onCompleted: {
+ var x = new XMLHttpRequest;
+ x.open("GET", url);
+
+ x.onreadystatechange = function() {
+ if (x.readyState == XMLHttpRequest.DONE) {
+ done = true;
+ dataOK = x.responseText == "Redirected\n";
+ }
+ }
+
+ x.send();
+ }
+}
diff --git a/tests/auto/declarative/xmlhttprequest/data/redirecttarget.html b/tests/auto/declarative/xmlhttprequest/data/redirecttarget.html
new file mode 100644
index 0000000..95f35e0
--- /dev/null
+++ b/tests/auto/declarative/xmlhttprequest/data/redirecttarget.html
@@ -0,0 +1 @@
+Redirected
diff --git a/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp b/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp
index d3201e2..253e041 100644
--- a/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp
+++ b/tests/auto/declarative/xmlhttprequest/tst_xmlhttprequest.cpp
@@ -98,6 +98,7 @@ private slots:
void responseText();
void responseXML_invalid();
void invalidMethodUsage();
+ void redirects();
// Attributes
void document();
@@ -1160,6 +1161,72 @@ void tst_xmlhttprequest::invalidMethodUsage()
delete object;
}
+// Test that XMLHttpRequest transparently redirects
+void tst_xmlhttprequest::redirects()
+{
+ {
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirecttarget.html");
+ server.serveDirectory("data");
+
+ QmlComponent component(&engine, TEST_FILE("redirects.qml"));
+ QObject *object = component.beginCreate(engine.rootContext());
+ QVERIFY(object != 0);
+ object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
+ object->setProperty("expectedText", "");
+ component.completeCreate();
+
+ TRY_WAIT(object->property("done").toBool() == true);
+ QCOMPARE(object->property("dataOK").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirectmissing.html");
+ server.serveDirectory("data");
+
+ QmlComponent component(&engine, TEST_FILE("redirectError.qml"));
+ QObject *object = component.beginCreate(engine.rootContext());
+ QVERIFY(object != 0);
+ object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
+ object->setProperty("expectedText", "");
+ component.completeCreate();
+
+ TRY_WAIT(object->property("done").toBool() == true);
+ QCOMPARE(object->property("dataOK").toBool(), true);
+
+ delete object;
+ }
+
+ {
+ TestHTTPServer server(SERVER_PORT);
+ QVERIFY(server.isValid());
+ server.addRedirect("redirect.html", "http://127.0.0.1:14445/redirect.html");
+ server.serveDirectory("data");
+
+ QmlComponent component(&engine, TEST_FILE("redirectRecur.qml"));
+ QObject *object = component.beginCreate(engine.rootContext());
+ QVERIFY(object != 0);
+ object->setProperty("url", "http://127.0.0.1:14445/redirect.html");
+ object->setProperty("expectedText", "");
+ component.completeCreate();
+
+ for (int ii = 0; ii < 60; ++ii) {
+ if (object->property("done").toBool()) break;
+ QTest::qWait(50);
+ }
+ QVERIFY(object->property("done").toBool() == true);
+
+ QCOMPARE(object->property("dataOK").toBool(), true);
+
+ delete object;
+ }
+}
+
void tst_xmlhttprequest::responseXML_invalid()
{
QmlComponent component(&engine, TEST_FILE("responseXML_invalid.qml"));