From 100b55e4ddc9e4846ab877ea670473e2a9ed641e Mon Sep 17 00:00:00 2001 From: Peter Hartmann Date: Tue, 10 Mar 2009 17:35:17 +0100 Subject: add HTTP DELETE support to Network Access API added new method QNetworkAccessManager::deleteResource (naming the method "delete" was not possible since it is a reserverd word in C++) and adjusted all the internals necessary. Task-number: 242916 Reviewed-by: Thiago --- src/network/access/qnetworkaccesshttpbackend.cpp | 10 +++ src/network/access/qnetworkaccessmanager.cpp | 19 ++++- src/network/access/qnetworkaccessmanager.h | 2 + tests/auto/qnetworkreply/tst_qnetworkreply.cpp | 99 ++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 2 deletions(-) diff --git a/src/network/access/qnetworkaccesshttpbackend.cpp b/src/network/access/qnetworkaccesshttpbackend.cpp index bd364cb..7517000 100644 --- a/src/network/access/qnetworkaccesshttpbackend.cpp +++ b/src/network/access/qnetworkaccesshttpbackend.cpp @@ -212,6 +212,7 @@ QNetworkAccessHttpBackendFactory::create(QNetworkAccessManager::Operation op, case QNetworkAccessManager::PostOperation: case QNetworkAccessManager::HeadOperation: case QNetworkAccessManager::PutOperation: + case QNetworkAccessManager::DeleteOperation: break; default: @@ -244,6 +245,10 @@ static QNetworkReply::NetworkError statusCodeFromHttp(int httpStatusCode, const code = QNetworkReply::ContentNotFoundError; break; + case 405: // Method Not Allowed + code = QNetworkReply::ContentOperationNotPermittedError; + break; + case 407: code = QNetworkReply::ProxyAuthenticationRequiredError; break; @@ -485,6 +490,11 @@ void QNetworkAccessHttpBackend::postRequest() httpRequest.setUploadByteDevice(createUploadByteDevice()); break; + case QNetworkAccessManager::DeleteOperation: + invalidateCache(); + httpRequest.setOperation(QHttpNetworkRequest::Delete); + break; + default: break; // can't happen } diff --git a/src/network/access/qnetworkaccessmanager.cpp b/src/network/access/qnetworkaccessmanager.cpp index bf06ede..7ca5f78 100644 --- a/src/network/access/qnetworkaccessmanager.cpp +++ b/src/network/access/qnetworkaccessmanager.cpp @@ -148,6 +148,9 @@ static void ensureInitialized() \value PostOperation send the contents of an HTML form for processing via HTTP POST (created with post()) + \value DeleteOperation delete contents operation (created with + deleteResource()) + \omitvalue UnknownOperation \sa QNetworkReply::operation() @@ -555,7 +558,7 @@ QNetworkReply *QNetworkAccessManager::head(const QNetworkRequest &request) a new QNetworkReply object opened for reading which emits its QIODevice::readyRead() signal whenever new data arrives. - \sa post(), put() + \sa post(), put(), deleteResource() */ QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request) { @@ -577,7 +580,7 @@ QNetworkReply *QNetworkAccessManager::get(const QNetworkRequest &request) Note: sending a POST request on protocols other than HTTP and HTTPS is undefined and will probably fail. - \sa get(), put() + \sa get(), put(), deleteResource() */ QNetworkReply *QNetworkAccessManager::post(const QNetworkRequest &request, QIODevice *data) { @@ -642,6 +645,18 @@ QNetworkReply *QNetworkAccessManager::put(const QNetworkRequest &request, const } /*! + This function is used to send a request to delete the resource + identified by the URL of \a request. + This feature is currently available for HTTP only, performing an HTTP DELETE request. + + \sa get(), post(), put() +*/ +QNetworkReply *QNetworkAccessManager::deleteResource(const QNetworkRequest &request) +{ + return d_func()->postProcess(createRequest(QNetworkAccessManager::DeleteOperation, request)); +} + +/*! Returns a new QNetworkReply object to handle the operation \a op and request \a req. The device \a outgoingData is always 0 for Get and Head requests, but is the value passed to post() and put() in diff --git a/src/network/access/qnetworkaccessmanager.h b/src/network/access/qnetworkaccessmanager.h index 4fe218e..79f512c 100644 --- a/src/network/access/qnetworkaccessmanager.h +++ b/src/network/access/qnetworkaccessmanager.h @@ -74,6 +74,7 @@ public: GetOperation, PutOperation, PostOperation, + DeleteOperation, UnknownOperation = 0 }; @@ -100,6 +101,7 @@ public: QNetworkReply *post(const QNetworkRequest &request, const QByteArray &data); QNetworkReply *put(const QNetworkRequest &request, QIODevice *data); QNetworkReply *put(const QNetworkRequest &request, const QByteArray &data); + QNetworkReply *deleteResource(const QNetworkRequest &request); Q_SIGNALS: #ifndef QT_NO_NETWORKPROXY diff --git a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp index b76a4e6..43b4ea9 100644 --- a/tests/auto/qnetworkreply/tst_qnetworkreply.cpp +++ b/tests/auto/qnetworkreply/tst_qnetworkreply.cpp @@ -161,6 +161,10 @@ private Q_SLOTS: void putToHttp(); void postToHttp_data(); void postToHttp(); + void deleteFromHttp_data(); + void deleteFromHttp(); + void putGetDeleteGetFromHttp_data(); + void putGetDeleteGetFromHttp(); void ioGetFromData_data(); void ioGetFromData(); @@ -903,6 +907,10 @@ QString tst_QNetworkReply::runSimpleRequest(QNetworkAccessManager::Operation op, reply = manager.post(request, data); break; + case QNetworkAccessManager::DeleteOperation: + reply = manager.deleteResource(request); + break; + default: Q_ASSERT_X(false, "tst_QNetworkReply", "Invalid/unknown operation requested"); } @@ -1478,6 +1486,97 @@ void tst_QNetworkReply::postToHttp() QCOMPARE(uploadedData, md5sum.toHex()); } +void tst_QNetworkReply::deleteFromHttp_data() +{ + QTest::addColumn("url"); + QTest::addColumn("resultCode"); + QTest::addColumn("error"); + + // for status codes to expect, see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html + + QTest::newRow("405-method-not-allowed") << QUrl("http://" + QtNetworkSettings::serverName() + "/index.html") << 405 << QNetworkReply::ContentOperationNotPermittedError; + QTest::newRow("200-ok") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?200-ok") << 200 << QNetworkReply::NoError; + QTest::newRow("202-accepted") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?202-accepted") << 202 << QNetworkReply::NoError; + QTest::newRow("204-no-content") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?204-no-content") << 204 << QNetworkReply::NoError; + QTest::newRow("404-not-found") << QUrl("http://" + QtNetworkSettings::serverName() + "/cgi-bin/http-delete.cgi?404-not-found") << 404 << QNetworkReply::ContentNotFoundError; +} + +void tst_QNetworkReply::deleteFromHttp() +{ + QFETCH(QUrl, url); + QFETCH(int, resultCode); + QFETCH(QNetworkReply::NetworkError, error); + QNetworkRequest request(url); + QNetworkReplyPtr reply; + runSimpleRequest(QNetworkAccessManager::DeleteOperation, request, reply, 0); + QCOMPARE(reply->url(), url); + QCOMPARE(reply->error(), error); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), resultCode); +} + +void tst_QNetworkReply::putGetDeleteGetFromHttp_data() +{ + QTest::addColumn("putUrl"); + QTest::addColumn("putResultCode"); + QTest::addColumn("putError"); + QTest::addColumn("deleteUrl"); + QTest::addColumn("deleteResultCode"); + QTest::addColumn("deleteError"); + QTest::addColumn("get2Url"); + QTest::addColumn("get2ResultCode"); + QTest::addColumn("get2Error"); + + QUrl url("http://" + QtNetworkSettings::serverName()); + url.setPath(QString("/dav/qnetworkaccess-putToHttp-%1-%2") + .arg(QTest::currentDataTag()) + .arg(uniqueExtension)); + + // first use case: put, get (to check it is there), delete, get (to check it is not there anymore) + QTest::newRow("success") << url << 201 << QNetworkReply::NoError << url << 204 << QNetworkReply::NoError << url << 404 << QNetworkReply::ContentNotFoundError; + + QUrl wrongUrl("http://" + QtNetworkSettings::serverName()); + wrongUrl.setPath(QString("/dav/qnetworkaccess-thisURLisNotAvailable")); + + // second use case: put, get (to check it is there), delete wrong URL, get (to check it is still there) + QTest::newRow("delete-error") << url << 201 << QNetworkReply::NoError << wrongUrl << 404 << QNetworkReply::ContentNotFoundError << url << 200 << QNetworkReply::NoError; + +} + +void tst_QNetworkReply::putGetDeleteGetFromHttp() +{ + QFETCH(QUrl, putUrl); + QFETCH(int, putResultCode); + QFETCH(QNetworkReply::NetworkError, putError); + QFETCH(QUrl, deleteUrl); + QFETCH(int, deleteResultCode); + QFETCH(QNetworkReply::NetworkError, deleteError); + QFETCH(QUrl, get2Url); + QFETCH(int, get2ResultCode); + QFETCH(QNetworkReply::NetworkError, get2Error); + + QNetworkRequest putRequest(putUrl); + QNetworkRequest deleteRequest(deleteUrl); + QNetworkRequest get2Request(get2Url); + QNetworkReplyPtr reply; + + RUN_REQUEST(runSimpleRequest(QNetworkAccessManager::PutOperation, putRequest, reply, 0)); + QCOMPARE(reply->error(), putError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), putResultCode); + + runSimpleRequest(QNetworkAccessManager::GetOperation, putRequest, reply, 0); + QCOMPARE(reply->error(), QNetworkReply::NoError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); + + runSimpleRequest(QNetworkAccessManager::DeleteOperation, deleteRequest, reply, 0); + QCOMPARE(reply->error(), deleteError); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), deleteResultCode); + + runSimpleRequest(QNetworkAccessManager::GetOperation, get2Request, reply, 0); + QCOMPARE(reply->error(), get2Error); + QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), get2ResultCode); + +} + void tst_QNetworkReply::ioGetFromData_data() { QTest::addColumn("urlStr"); -- cgit v0.12