fixed CORS and webserver and tests

This commit is contained in:
Simon Stürz 2015-08-14 14:14:01 +02:00 committed by Michael Zanetti
parent 653043f7b1
commit ba5aedaaab
13 changed files with 78 additions and 89 deletions

View File

@ -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": [
{

View File

@ -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
{

View File

@ -94,6 +94,9 @@ public:
QHash<QByteArray, QByteArray> rawHeaderList() const;
QByteArray rawHeader() const;
void setCloseConnection(const bool &close);
bool closeConnection() const;
bool isEmpty() const;
void clear();
@ -115,6 +118,8 @@ private:
QHash<QByteArray, QByteArray> m_rawHeaderList;
bool m_closeConnection;
QTimer *m_timer;
bool m_timedOut;

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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 {

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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();

View File

@ -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();

View File

@ -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

View File

@ -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;