From 46076998a0069207ad6651cbc9558953bd5bc4cd Mon Sep 17 00:00:00 2001 From: johan Date: Sun, 18 Aug 2013 12:02:17 +0200 Subject: [PATCH] Schema checking for all commands added --- libsrc/jsonserver/JsonClientConnection.cpp | 120 ++++++++++++++---- libsrc/jsonserver/JsonClientConnection.h | 13 +- libsrc/jsonserver/JsonServer.cpp | 2 +- libsrc/jsonserver/resource.qrc | 12 +- libsrc/jsonserver/schema/schema-clear.json | 16 +++ libsrc/jsonserver/schema/schema-clearall.json | 12 ++ libsrc/jsonserver/schema/schema-color.json | 29 +++++ libsrc/jsonserver/schema/schema-image.json | 34 +++++ .../jsonserver/schema/schema-serverinfo.json | 12 ++ .../schema-transform.json} | 35 +---- libsrc/jsonserver/schema/schema.json | 11 ++ src/hyperion-remote/JsonConnection.cpp | 2 +- 12 files changed, 231 insertions(+), 67 deletions(-) create mode 100644 libsrc/jsonserver/schema/schema-clear.json create mode 100644 libsrc/jsonserver/schema/schema-clearall.json create mode 100644 libsrc/jsonserver/schema/schema-color.json create mode 100644 libsrc/jsonserver/schema/schema-image.json create mode 100644 libsrc/jsonserver/schema/schema-serverinfo.json rename libsrc/jsonserver/{schema.json => schema/schema-transform.json} (65%) create mode 100644 libsrc/jsonserver/schema/schema.json diff --git a/libsrc/jsonserver/JsonClientConnection.cpp b/libsrc/jsonserver/JsonClientConnection.cpp index f14d9c6d..9a93b46e 100644 --- a/libsrc/jsonserver/JsonClientConnection.cpp +++ b/libsrc/jsonserver/JsonClientConnection.cpp @@ -16,20 +16,8 @@ JsonClientConnection::JsonClientConnection(QTcpSocket *socket) : QObject(), _socket(socket), - _schemaChecker(), _receiveBuffer() { - // read the json schema from the resource - QResource schemaData(":/schema.json"); - assert(schemaData.isValid()); - Json::Reader jsonReader; - Json::Value schemaJson; - if (!jsonReader.parse(reinterpret_cast(schemaData.data()), reinterpret_cast(schemaData.data()) + schemaData.size(), schemaJson, false)) - { - throw std::runtime_error("Schema error: " + jsonReader.getFormattedErrorMessages()) ; - } - _schemaChecker.setSchema(schemaJson); - // connect internal signals and slots connect(_socket, SIGNAL(disconnected()), this, SLOT(socketClosed())); connect(_socket, SIGNAL(readyRead()), this, SLOT(readData())); @@ -64,33 +52,80 @@ void JsonClientConnection::socketClosed() emit connectionClosed(this); } -void JsonClientConnection::handleMessage(const std::string &message) +void JsonClientConnection::handleMessage(const std::string &messageString) { Json::Reader reader; - Json::Value messageRoot; - if (!reader.parse(message, messageRoot, false)) + Json::Value message; + if (!reader.parse(messageString, message, false)) { sendErrorReply("Error while parsing json: " + reader.getFormattedErrorMessages()); return; } - if (!_schemaChecker.validate(messageRoot)) + // check basic message + std::string errors; + if (!checkJson(message, ":schema", errors)) { - const std::list & errors = _schemaChecker.getMessages(); - std::stringstream ss; - ss << "Error while validating json: {"; - foreach (const std::string & error, errors) { - ss << error << ", "; - } - ss << "}"; - sendErrorReply(ss.str()); + sendErrorReply("Error while validating json: " + errors); return; } - handleNotImplemented(messageRoot); + // check specific message + const std::string command = message["command"].asString(); + if (!checkJson(message, QString("schema-%1").arg(QString::fromStdString(command)), errors)) + { + sendErrorReply("Error while validating json: " + errors); + return; + } + + // switch over all possible commands and handle them + if (command == "color") + handleColorCommand(message); + else if (command == "image") + handleImageCommand(message); + else if (command == "serverinfo") + handleServerInfoCommand(message); + else if (command == "clear") + handleClearCommand(message); + else if (command == "clearall") + handleClearallCommand(message); + else if (command == "transform") + handleTransformCommand(message); + else + handleNotImplemented(); } -void JsonClientConnection::handleNotImplemented(const Json::Value & message) +void JsonClientConnection::handleColorCommand(const Json::Value &message) +{ + handleNotImplemented(); +} + +void JsonClientConnection::handleImageCommand(const Json::Value &message) +{ + handleNotImplemented(); +} + +void JsonClientConnection::handleServerInfoCommand(const Json::Value &message) +{ + handleNotImplemented(); +} + +void JsonClientConnection::handleClearCommand(const Json::Value &message) +{ + handleNotImplemented(); +} + +void JsonClientConnection::handleClearallCommand(const Json::Value &message) +{ + handleNotImplemented(); +} + +void JsonClientConnection::handleTransformCommand(const Json::Value &message) +{ + handleNotImplemented(); +} + +void JsonClientConnection::handleNotImplemented() { sendErrorReply("Command not implemented"); } @@ -112,3 +147,36 @@ void JsonClientConnection::sendErrorReply(const std::string &error) // send reply sendMessage(reply); } + +bool JsonClientConnection::checkJson(const Json::Value & message, const QString & schemaResource, std::string & errorMessage) +{ + // read the json schema from the resource + QResource schemaData(schemaResource); + assert(schemaData.isValid()); + Json::Reader jsonReader; + Json::Value schemaJson; + if (!jsonReader.parse(reinterpret_cast(schemaData.data()), reinterpret_cast(schemaData.data()) + schemaData.size(), schemaJson, false)) + { + throw std::runtime_error("Schema error: " + jsonReader.getFormattedErrorMessages()) ; + } + + // create schema checker + JsonSchemaChecker schema; + schema.setSchema(schemaJson); + + // check the message + if (!schema.validate(message)) + { + const std::list & errors = schema.getMessages(); + std::stringstream ss; + ss << "{"; + foreach (const std::string & error, errors) { + ss << error << " "; + } + ss << "}"; + errorMessage = ss.str(); + return false; + } + + return true; +} diff --git a/libsrc/jsonserver/JsonClientConnection.h b/libsrc/jsonserver/JsonClientConnection.h index ee46e642..e022742f 100644 --- a/libsrc/jsonserver/JsonClientConnection.h +++ b/libsrc/jsonserver/JsonClientConnection.h @@ -30,15 +30,22 @@ private slots: private: void handleMessage(const std::string & message); - void handleNotImplemented(const Json::Value & message); + void handleColorCommand(const Json::Value & message); + void handleImageCommand(const Json::Value & message); + void handleServerInfoCommand(const Json::Value & message); + void handleClearCommand(const Json::Value & message); + void handleClearallCommand(const Json::Value & message); + void handleTransformCommand(const Json::Value & message); + void handleNotImplemented(); void sendMessage(const Json::Value & message); void sendErrorReply(const std::string & error); private: - QTcpSocket * _socket; + bool checkJson(const Json::Value & message, const QString &schemaResource, std::string & errors); - JsonSchemaChecker _schemaChecker; +private: + QTcpSocket * _socket; QByteArray _receiveBuffer; }; diff --git a/libsrc/jsonserver/JsonServer.cpp b/libsrc/jsonserver/JsonServer.cpp index 5b3e3c36..f9f898c8 100644 --- a/libsrc/jsonserver/JsonServer.cpp +++ b/libsrc/jsonserver/JsonServer.cpp @@ -37,11 +37,11 @@ uint16_t JsonServer::getPort() const void JsonServer::newConnection() { - std::cout << "New incoming json connection" << std::endl; QTcpSocket * socket = _server.nextPendingConnection(); if (socket != nullptr) { + std::cout << "New json connection" << std::endl; JsonClientConnection * connection = new JsonClientConnection(socket); _openConnections.insert(connection); diff --git a/libsrc/jsonserver/resource.qrc b/libsrc/jsonserver/resource.qrc index cb387153..5c2f1afb 100644 --- a/libsrc/jsonserver/resource.qrc +++ b/libsrc/jsonserver/resource.qrc @@ -1,5 +1,11 @@ - - schema.json - + + schema/schema.json + schema/schema-color.json + schema/schema-image.json + schema/schema-serverinfo.json + schema/schema-clear.json + schema/schema-clearall.json + schema/schema-transform.json + diff --git a/libsrc/jsonserver/schema/schema-clear.json b/libsrc/jsonserver/schema/schema-clear.json new file mode 100644 index 00000000..8e794c6f --- /dev/null +++ b/libsrc/jsonserver/schema/schema-clear.json @@ -0,0 +1,16 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["clear"] + }, + "priority": { + "type": "integer", + "required": true + } + }, + "additionalProperties": false +} diff --git a/libsrc/jsonserver/schema/schema-clearall.json b/libsrc/jsonserver/schema/schema-clearall.json new file mode 100644 index 00000000..0326cd70 --- /dev/null +++ b/libsrc/jsonserver/schema/schema-clearall.json @@ -0,0 +1,12 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["clearall"] + } + }, + "additionalProperties": false +} diff --git a/libsrc/jsonserver/schema/schema-color.json b/libsrc/jsonserver/schema/schema-color.json new file mode 100644 index 00000000..c825698d --- /dev/null +++ b/libsrc/jsonserver/schema/schema-color.json @@ -0,0 +1,29 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["color"] + }, + "priority": { + "type": "integer", + "required": true + }, + "duration": { + "type": "integer", + "required": false + }, + "color": { + "type": "array", + "required": true, + "items" :{ + "type" : "integer" + }, + "minItems": 3, + "maxItems": 3 + } + }, + "additionalProperties": false +} diff --git a/libsrc/jsonserver/schema/schema-image.json b/libsrc/jsonserver/schema/schema-image.json new file mode 100644 index 00000000..0b0b936c --- /dev/null +++ b/libsrc/jsonserver/schema/schema-image.json @@ -0,0 +1,34 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["image"] + }, + "priority": { + "type": "integer", + "required": true + }, + "duration": { + "type": "integer", + "required": false + }, + "imagewidth": { + "type" : "integer", + "required": true, + "minimum": 0 + }, + "imageheight": { + "type" : "integer", + "required": true, + "minimum": 0 + }, + "imagedata": { + "type": "string", + "required": true + } + }, + "additionalProperties": false +} diff --git a/libsrc/jsonserver/schema/schema-serverinfo.json b/libsrc/jsonserver/schema/schema-serverinfo.json new file mode 100644 index 00000000..31f41de6 --- /dev/null +++ b/libsrc/jsonserver/schema/schema-serverinfo.json @@ -0,0 +1,12 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["serverinfo"] + } + }, + "additionalProperties": false +} diff --git a/libsrc/jsonserver/schema.json b/libsrc/jsonserver/schema/schema-transform.json similarity index 65% rename from libsrc/jsonserver/schema.json rename to libsrc/jsonserver/schema/schema-transform.json index 3ad665f0..781c989d 100644 --- a/libsrc/jsonserver/schema.json +++ b/libsrc/jsonserver/schema/schema-transform.json @@ -5,42 +5,11 @@ "command": { "type" : "string", "required" : true, - "enum" : ["color", "image", "serverinfo", "clear", "clearall", "transform"] - }, - "priority": { - "type": "integer", - "required": false - }, - "duration": { - "type": "integer", - "required": false - }, - "color": { - "type": "array", - "required": false, - "items" :{ - "type" : "integer" - }, - "minItems": 3, - "maxItems": 3 - }, - "imagewidth": { - "type" : "integer", - "required": false, - "minimum": 0 - }, - "imageheight": { - "type" : "integer", - "required": false, - "minimum": 0 - }, - "imagedata": { - "type": "string", - "required": false + "enum" : ["transform"] }, "transform": { "type": "object", - "required": false, + "required": true, "properties": { "threshold": { "type": "array", diff --git a/libsrc/jsonserver/schema/schema.json b/libsrc/jsonserver/schema/schema.json new file mode 100644 index 00000000..1cbbbb06 --- /dev/null +++ b/libsrc/jsonserver/schema/schema.json @@ -0,0 +1,11 @@ +{ + "type":"object", + "required":true, + "properties":{ + "command": { + "type" : "string", + "required" : true, + "enum" : ["color", "image", "serverinfo", "clear", "clearall", "transform"] + } + } +} diff --git a/src/hyperion-remote/JsonConnection.cpp b/src/hyperion-remote/JsonConnection.cpp index c1aff4e2..6975114e 100644 --- a/src/hyperion-remote/JsonConnection.cpp +++ b/src/hyperion-remote/JsonConnection.cpp @@ -275,7 +275,7 @@ bool JsonConnection::parseReply(const Json::Value &reply) if (!success) { - throw std::runtime_error("Error while executing command: " + reason); + throw std::runtime_error("Error: " + reason); } return success;