diff --git a/plugins/deviceplugins/mailnotification/devicepluginmailnotification.json b/plugins/deviceplugins/mailnotification/devicepluginmailnotification.json index 9ece935b..36665843 100644 --- a/plugins/deviceplugins/mailnotification/devicepluginmailnotification.json +++ b/plugins/deviceplugins/mailnotification/devicepluginmailnotification.json @@ -79,7 +79,8 @@ }, { "name": "Google", - "id": "d02399c5-8e79-4 0be-8cf6-e00b55bbfe7c", + "idName": "google", + "id": "d02399c5-8e79-40be-8cf6-e00b55bbfe7c", "deviceClasses": [ { "deviceClassId": "3869884a-1592-4b8f-84a7-994be18ff555", @@ -127,6 +128,7 @@ }, { "name": "Yahoo", + "idName": "yahoo", "id": "5eb3e1e9-25a7-4740-806e-5cfc836e4bf5", "deviceClasses": [ { diff --git a/server/httpreply.cpp b/server/httpreply.cpp index 57376dc9..c13d3c11 100644 --- a/server/httpreply.cpp +++ b/server/httpreply.cpp @@ -125,6 +125,7 @@ HttpReply::HttpReply(QObject *parent) : m_statusCode(HttpReply::Ok), m_type(HttpReply::TypeSync), m_payload(QByteArray()), + m_closeConnection(false), m_timedOut(false) { m_timer = new QTimer(this); @@ -252,6 +253,16 @@ QByteArray HttpReply::rawHeader() const return m_rawHeader; } +void HttpReply::setCloseConnection(const bool &close) +{ + m_closeConnection = close; +} + +bool HttpReply::closeConnection() const +{ + return m_closeConnection; +} + /*! Returns true if the raw header and the payload of this \l{HttpReply} is empty.*/ bool HttpReply::isEmpty() const { diff --git a/server/httpreply.h b/server/httpreply.h index a5f1a154..2d93dcf0 100644 --- a/server/httpreply.h +++ b/server/httpreply.h @@ -94,6 +94,9 @@ public: QHash rawHeaderList() const; QByteArray rawHeader() const; + void setCloseConnection(const bool &close); + bool closeConnection() const; + bool isEmpty() const; void clear(); @@ -115,6 +118,8 @@ private: QHash m_rawHeaderList; + bool m_closeConnection; + QTimer *m_timer; bool m_timedOut; diff --git a/server/main.cpp b/server/main.cpp index d659603c..61819961 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -63,10 +63,10 @@ int main(int argc, char *argv[]) s_loggingFilters.insert("RuleEngine", true); s_loggingFilters.insert("Connection", true); s_loggingFilters.insert("TcpServer", false); - s_loggingFilters.insert("WebServer", false); + s_loggingFilters.insert("WebServer", true); s_loggingFilters.insert("WebSocketServer", false); s_loggingFilters.insert("JsonRpc", false); - s_loggingFilters.insert("Rest", false); + s_loggingFilters.insert("Rest", true); s_loggingFilters.insert("Hardware", false); s_loggingFilters.insert("LogEngine", false); diff --git a/server/rest/deviceclassesresource.cpp b/server/rest/deviceclassesresource.cpp index e52ccc3b..c72746d7 100644 --- a/server/rest/deviceclassesresource.cpp +++ b/server/rest/deviceclassesresource.cpp @@ -51,6 +51,7 @@ HttpReply *DeviceClassesResource::proccessRequest(const HttpRequest &request, co } m_deviceClass = GuhCore::instance()->findDeviceClass(deviceClassId); if (!m_deviceClass.isValid()) { + qCWarning(dcRest) << "DeviceClassId" << deviceClassId.toString() << "not found"; return createErrorReply(HttpReply::NotFound); } } diff --git a/server/rest/devicesresource.cpp b/server/rest/devicesresource.cpp index bf3d5614..d34e9d39 100644 --- a/server/rest/devicesresource.cpp +++ b/server/rest/devicesresource.cpp @@ -250,9 +250,11 @@ HttpReply *DevicesResource::removeDevice(Device *device) const // TODO: /api/v1/devices/{deviceId}?ruleId={ruleId}&removePolicy={RemovePolicy} - if (result == DeviceManager::DeviceErrorNoError) - return createSuccessReply(); - + if (result == DeviceManager::DeviceErrorNoError) { + HttpReply *reply = createSuccessReply(); + reply->setCloseConnection(true); + return reply; + } return createErrorReply(HttpReply::Forbidden); } @@ -322,7 +324,7 @@ HttpReply *DevicesResource::addConfiguredDevice(const QByteArray &payload) const return createErrorReply(HttpReply::InternalServerError); QVariantMap result; - result.insert("deviceId", newDeviceId); + result.insert("id", newDeviceId); HttpReply *reply = createSuccessReply(); reply->setPayload(QJsonDocument::fromVariant(result).toJson()); return reply; @@ -458,7 +460,7 @@ void DevicesResource::deviceSetupFinished(Device *device, DeviceManager::DeviceE } QVariantMap result; - result.insert("deviceId", device->id()); + result.insert("id", device->id()); reply->setPayload(QJsonDocument::fromVariant(result).toJson()); reply->finished(); } @@ -489,7 +491,7 @@ void DevicesResource::pairingFinished(const PairingTransactionId &pairingTransac if (status == DeviceManager::DeviceErrorNoError) { qCDebug(dcRest) << "Pairing device finished successfully"; QVariantMap response; - response.insert("deviceId", deviceId.toString()); + response.insert("id", deviceId.toString()); reply->setPayload(QJsonDocument::fromVariant(response).toJson()); reply->setHttpStatusCode(HttpReply::Ok); } else { diff --git a/server/rest/restserver.cpp b/server/rest/restserver.cpp index fe7e4fd6..a25109b3 100644 --- a/server/rest/restserver.cpp +++ b/server/rest/restserver.cpp @@ -111,6 +111,21 @@ void RestServer::processHttpRequest(const QUuid &clientId, const HttpRequest &re return; } + // check CORS call + if (request.method() == HttpRequest::Options) { + HttpReply *reply = RestResource::createSuccessReply(); + reply->setHeader(HttpReply::ContentTypeHeader, "text/plain;"); + reply->setRawHeader("Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, OPTIONS"); + reply->setRawHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); + reply->setClientId(clientId); + reply->setCloseConnection(true); + m_webserver->sendHttpReply(reply); + + reply->deleteLater(); + return; + } + + // process request in corresponding resource RestResource *resource = m_resources.value(resourceName); HttpReply *reply = resource->proccessRequest(request, urlTokens); diff --git a/server/rest/rulesresource.cpp b/server/rest/rulesresource.cpp index bb0ff188..aecca238 100644 --- a/server/rest/rulesresource.cpp +++ b/server/rest/rulesresource.cpp @@ -234,7 +234,7 @@ HttpReply *RulesResource::addRule(const QByteArray &payload) const if (status == RuleEngine::RuleErrorNoError) { QVariantMap returns; - returns.insert("ruleId", newRuleId.toString()); + returns.insert("id", newRuleId.toString()); HttpReply *reply = createSuccessReply(); reply->setPayload(QJsonDocument::fromVariant(returns).toJson()); return reply; diff --git a/server/webserver.cpp b/server/webserver.cpp index 30b9682d..159382de 100644 --- a/server/webserver.cpp +++ b/server/webserver.cpp @@ -133,10 +133,12 @@ void WebServer::sendHttpReply(HttpReply *reply) QSslSocket *socket = 0; socket = m_clientList.value(reply->clientId()); if (!socket) { - qCDebug(dcWebServer) << "Invalid socket pointer! This should never happen!!!"; + qCDebug(dcWebServer) << "Invalid socket pointer! This should never happen!!! Missing clientId in reply?"; return; } + writeData(socket, reply->data()); + socket->close(); } bool WebServer::verifyFile(QSslSocket *socket, const QString &fileName) @@ -190,7 +192,6 @@ QString WebServer::fileName(const QString &query) void WebServer::writeData(QSslSocket *socket, const QByteArray &data) { socket->write(data); - //socket->close(); } void WebServer::incomingConnection(qintptr socketDescriptor) @@ -291,13 +292,6 @@ void WebServer::readClient() return; } - // check CORS call - if (request.method() == HttpRequest::Options) { - HttpReply reply(HttpReply::Ok); - reply.setRawHeader("Access-Control-Allow-Methods","PUT, POST, GET, DELETE, OPTIONS"); - writeData(socket, reply.data()); - } - // verify API query if (request.url().path().startsWith("/api/v1")) { emit httpRequestReady(clientId, request); diff --git a/tests/auto/restdeviceclasses/testrestdeviceclasses.cpp b/tests/auto/restdeviceclasses/testrestdeviceclasses.cpp index 3df45e85..5eede816 100644 --- a/tests/auto/restdeviceclasses/testrestdeviceclasses.cpp +++ b/tests/auto/restdeviceclasses/testrestdeviceclasses.cpp @@ -93,8 +93,8 @@ void TestRestDeviceClasses::getSupportedDevices() QNetworkReply *reply = nam->get(request); clientSpy.wait(); QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver"); - // jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); - // QCOMPARE(error.error, QJsonParseError::NoError); + jsonDoc = QJsonDocument::fromJson(reply->readAll(), &error); + QCOMPARE(error.error, QJsonParseError::NoError); reply->deleteLater(); } nam->deleteLater(); @@ -276,8 +276,11 @@ void TestRestDeviceClasses::discoverDevices() QVariantList foundDevices = jsonDoc.toVariant().toList(); QCOMPARE(foundDevices.count(), resultCount); + qDebug() << jsonDoc.toJson(); + // ADD the discovered device request.setUrl(QUrl("http://localhost:3333/api/v1/devices")); + request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json"); DeviceDescriptorId descriptorId = DeviceDescriptorId(foundDevices.first().toMap().value("id").toString()); qDebug() << descriptorId; params.clear(); @@ -286,21 +289,25 @@ void TestRestDeviceClasses::discoverDevices() clientSpy.clear(); QByteArray payload = QJsonDocument::fromVariant(params).toJson(QJsonDocument::Compact); + qDebug() << payload; reply = nam->post(request, payload); clientSpy.wait(); QCOMPARE(clientSpy.count(), 1); data = reply->readAll(); - qDebug() << reply->rawHeaderList(); + qDebug() << data; + statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); reply->deleteLater(); QCOMPARE(statusCode, expectedStatusCode); - // REMOVE added device jsonDoc = QJsonDocument::fromJson(data, &error); QCOMPARE(error.error, QJsonParseError::NoError); QVariantMap response = jsonDoc.toVariant().toMap(); - DeviceId deviceId = DeviceId(response.value("deviceId").toString()); + DeviceId deviceId = DeviceId(response.value("id").toString()); + QVERIFY2(!deviceId.isNull(), "got invalid device id"); + + // REMOVE added device request = QNetworkRequest(QUrl(QString("http://localhost:3333/api/v1/devices/%1").arg(deviceId.toString()))); clientSpy.clear(); diff --git a/tests/auto/restdevices/testrestdevices.cpp b/tests/auto/restdevices/testrestdevices.cpp index 8655cbf4..1b23a117 100644 --- a/tests/auto/restdevices/testrestdevices.cpp +++ b/tests/auto/restdevices/testrestdevices.cpp @@ -202,7 +202,8 @@ void TestRestDevices::addConfiguredDevice() QCOMPARE(error.error, QJsonParseError::NoError); QVariantMap response = jsonDoc.toVariant().toMap(); - DeviceId deviceId = DeviceId(response.value("deviceId").toString()); + DeviceId deviceId = DeviceId(response.value("id").toString()); + QVERIFY2(!deviceId.isNull(),"invalid device id for removing"); request.setUrl(QUrl(QString("http://localhost:3333/api/v1/devices/%1").arg(deviceId.toString()))); clientSpy.clear(); @@ -430,7 +431,7 @@ void TestRestDevices::editDevices() QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), 200); reply->deleteLater(); QVariantMap responseMap = QJsonDocument::fromJson(data).toVariant().toMap(); - DeviceId deviceId = DeviceId(responseMap.value("deviceId").toString()); + DeviceId deviceId = DeviceId(responseMap.value("id").toString()); qDebug() << deviceId.toString(); QVERIFY2(deviceId != DeviceId(), "DeviceId not returned"); @@ -561,7 +562,7 @@ void TestRestDevices::editByDiscovery() QCOMPARE(error.error, QJsonParseError::NoError); QVariantMap response = jsonDoc.toVariant().toMap(); - DeviceId deviceId = DeviceId(response.value("deviceId").toString()); + DeviceId deviceId = DeviceId(response.value("id").toString()); QVERIFY(!deviceId.isNull()); @@ -618,62 +619,6 @@ void TestRestDevices::editByDiscovery() QCOMPARE(statusCode, expectedStatusCode); reply->deleteLater(); - - -// response = injectAndWait("Devices.EditDevice", params); -// verifyDeviceError(response, error); - -// response.clear(); -// response = injectAndWait("Devices.GetConfiguredDevices", QVariantMap()); - -// QVariantMap deviceMap; -// bool found = false; -// foreach (const QVariant device, response.toMap().value("params").toMap().value("devices").toList()) { -// if (DeviceId(device.toMap().value("id").toString()) == deviceId) { -// qDebug() << "found added device" << device.toMap().value("params"); -// found = true; -// deviceMap = device.toMap(); -// break; -// } -// } - -// QVERIFY2(found, "Device missing in config!"); -// QCOMPARE(deviceMap.value("id").toString(), deviceId.toString()); -// if (deviceMap.contains("setupComplete")) { -// QVERIFY2(deviceMap.value("setupComplete").toBool(), "Setup not completed after edit"); -// } - -// // Note: this shows that by discovery a not editable param (name) can be changed! -// foreach (QVariant param, deviceMap.value("params").toList()) { -// if (param.toMap().value("name") == "name") { -// QCOMPARE(param.toMap().value("value").toString(), QString("Discovered Mock Device 2")); -// } -// if (param.toMap().value("name") == "httpport") { -// QCOMPARE(param.toMap().value("value").toInt(), 55556); -// } -// } - -// // check if the daemons are running -// QNetworkAccessManager nam; -// QSignalSpy spy(&nam, SIGNAL(finished(QNetworkReply*))); - -// // check if old daemon is still running (should not) -// QNetworkRequest request(QUrl(QString("http://localhost:%1").arg(55555))); -// QNetworkReply *reply = nam.get(request); -// spy.wait(); -// QVERIFY2(reply->error(), "The old daemon is still running"); -// reply->deleteLater(); - -// // check if the daemon is realy running on the new port -// request = QNetworkRequest(QUrl(QString("http://localhost:%1").arg(55556))); -// reply = nam.get(request); -// spy.wait(); -// QVERIFY2(reply->error() == QNetworkReply::NoError, "The new daemon is not running"); -// reply->deleteLater(); - - - - // remove added device request = QNetworkRequest(QUrl(QString("http://localhost:3333/api/v1/devices/%1").arg(deviceId.toString()))); clientSpy.clear(); diff --git a/tests/auto/restrules/testrestrules.cpp b/tests/auto/restrules/testrestrules.cpp index f6790eca..556cf5ab 100644 --- a/tests/auto/restrules/testrestrules.cpp +++ b/tests/auto/restrules/testrestrules.cpp @@ -363,7 +363,7 @@ void TestRestRules::addRemoveRules() QCOMPARE(error.error, QJsonParseError::NoError); reply->deleteLater(); - RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("ruleId").toString()); + RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("id").toString()); QVERIFY(!ruleId.isNull()); // GET rule details @@ -677,7 +677,7 @@ void TestRestRules::editRules() QCOMPARE(error.error, QJsonParseError::NoError); reply->deleteLater(); - RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("ruleId").toString()); + RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("id").toString()); QVERIFY(!ruleId.isNull()); // now create the new rule and edit the original one @@ -792,7 +792,7 @@ void TestRestRules::enableDisableRule() QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &error); QCOMPARE(error.error, QJsonParseError::NoError); - RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("ruleId").toString()); + RuleId ruleId = RuleId(jsonDoc.toVariant().toMap().value("id").toString()); QVERIFY(!ruleId.isNull()); // ENABLE rule diff --git a/tests/auto/webserver/testwebserver.cpp b/tests/auto/webserver/testwebserver.cpp index 45bcb61e..20dc1909 100644 --- a/tests/auto/webserver/testwebserver.cpp +++ b/tests/auto/webserver/testwebserver.cpp @@ -176,6 +176,8 @@ void TestWebserver::checkAllowedMethodCall() request.setUrl(QUrl("http://localhost:3333")); QNetworkReply *reply = 0; + clientSpy.clear(); + if (method == "GET") { reply = nam->get(request); } else if(method == "PUT") { @@ -189,6 +191,7 @@ void TestWebserver::checkAllowedMethodCall() } else if(method == "CONNECT") { reply = nam->sendCustomRequest(request, "CONNECT"); } else if(method == "OPTIONS") { + request.setUrl(QUrl("http://localhost:3333/api/v1/devices")); reply = nam->sendCustomRequest(request, "OPTIONS"); } else if(method == "TRACE") { reply = nam->sendCustomRequest(request, "TRACE"); @@ -197,8 +200,13 @@ void TestWebserver::checkAllowedMethodCall() reply = nam->get(request); } - clientSpy.wait(200); - QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver"); + clientSpy.wait(); + + printResponse(reply); + + QCOMPARE(clientSpy.count(), 1); + //QVERIFY2(clientSpy.count() == 1, "expected exactly 1 response from webserver"); + if (expectedStatusCode == 405){ QCOMPARE(reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(), expectedStatusCode); QVERIFY2(reply->hasRawHeader("Allow"), "405 should contain the allowed methods header"); @@ -229,7 +237,6 @@ void TestWebserver::badRequests_data() userAgentMissing.append("GET / HTTP/1.1\r\n"); userAgentMissing.append("\r\n"); - QTest::newRow("wrong content length") << wrongContentLength << 400; QTest::newRow("invalid header formatting") << wrongHeaderFormatting << 400; QTest::newRow("user agent missing") << userAgentMissing << 400;