1 /* 2 * Copyright (C) 2005-2018 Team Kodi 3 * This file is part of Kodi - https://kodi.tv 4 * 5 * SPDX-License-Identifier: GPL-2.0-or-later 6 * See LICENSES/README.md for more information. 7 */ 8 9 #pragma once 10 11 #include "JSONUtils.h" 12 #include "utils/Variant.h" 13 14 #include <limits> 15 #include <memory> 16 #include <string> 17 #include <vector> 18 19 namespace JSONRPC 20 { 21 class JSONSchemaTypeDefinition; 22 typedef std::shared_ptr<JSONSchemaTypeDefinition> JSONSchemaTypeDefinitionPtr; 23 24 /*! 25 \ingroup jsonrpc 26 \brief Class for a parameter of a 27 json rpc method. 28 29 Represents a parameter of a defined 30 json rpc method and is used to verify 31 and extract the value of the parameter 32 in a method call. 33 */ 34 class JSONSchemaTypeDefinition : protected CJSONUtils 35 { 36 public: 37 JSONSchemaTypeDefinition(); 38 39 bool Parse(const CVariant &value, bool isParameter = false); 40 JSONRPC_STATUS Check(const CVariant& value, CVariant& outputValue, CVariant& errorData) const; 41 void Print(bool isParameter, bool isGlobal, bool printDefault, bool printDescriptions, CVariant &output) const; 42 void ResolveReference(); 43 44 std::string missingReference; 45 46 /*! 47 \brief Name of the parameter (for 48 by-name calls) 49 */ 50 std::string name; 51 52 /*! 53 \brief Id of the type (for 54 referenced types) 55 Renamed from "id" because of possible 56 issues with Objective-C. 57 */ 58 std::string ID; 59 60 /*! 61 \brief Referenced object 62 */ 63 JSONSchemaTypeDefinitionPtr referencedType; 64 65 /*! 66 \brief Whether the type has been set 67 based on the referenced type 68 */ 69 bool referencedTypeSet = false; 70 71 /*! 72 \brief Array of reference types 73 which are extended by this type. 74 */ 75 std::vector<JSONSchemaTypeDefinitionPtr> extends; 76 77 /*! 78 \brief Description of the parameter 79 */ 80 std::string description; 81 82 /*! 83 \brief JSON schema type of the parameter's value 84 */ 85 JSONSchemaType type = AnyValue; 86 87 /*! 88 \brief JSON schema type definitions in case 89 of a union type 90 */ 91 std::vector<JSONSchemaTypeDefinitionPtr> unionTypes; 92 93 /*! 94 \brief Whether or not the parameter is 95 optional 96 */ 97 bool optional = true; 98 99 /*! 100 \brief Default value of the parameter 101 (only needed when it is optional) 102 */ 103 CVariant defaultValue; 104 105 /*! 106 \brief Minimum value for Integer 107 or Number types 108 */ 109 double minimum; 110 111 /*! 112 \brief Maximum value for Integer or Number types 113 */ 114 double maximum; 115 116 /*! 117 \brief Whether to exclude the defined Minimum 118 value from the valid range or not 119 */ 120 bool exclusiveMinimum = false; 121 122 /*! 123 \brief Whether to exclude the defined Maximum 124 value from the valid range or not 125 */ 126 bool exclusiveMaximum = false; 127 128 /*! 129 \brief Integer by which the value (of type 130 Integer) must be divisible without rest 131 */ 132 unsigned int divisibleBy = 0; 133 134 /*! 135 \brief Minimum length for String types 136 */ 137 int minLength = -1; 138 139 /*! 140 \brief Maximum length for String types 141 */ 142 int maxLength = -1; 143 144 /*! 145 \brief (Optional) List of allowed values 146 for the type 147 */ 148 std::vector<CVariant> enums; 149 150 /*! 151 \brief List of possible values in an array 152 */ 153 std::vector<JSONSchemaTypeDefinitionPtr> items; 154 155 /*! 156 \brief Minimum amount of items in the array 157 */ 158 unsigned int minItems = 0; 159 160 /*! 161 \brief Maximum amount of items in the array 162 */ 163 unsigned int maxItems = 0; 164 165 /*! 166 \brief Whether every value in the array 167 must be unique or not 168 */ 169 bool uniqueItems = false; 170 171 /*! 172 \brief List of json schema definitions for 173 additional items in an array with tuple 174 typing (defined schemas in "items") 175 */ 176 std::vector<JSONSchemaTypeDefinitionPtr> additionalItems; 177 178 /*! 179 \brief Maps a properties name to its 180 json schema type definition 181 */ 182 class CJsonSchemaPropertiesMap 183 { 184 public: 185 CJsonSchemaPropertiesMap(); 186 187 void add(const JSONSchemaTypeDefinitionPtr& property); 188 189 typedef std::map<std::string, JSONSchemaTypeDefinitionPtr>::const_iterator JSONSchemaPropertiesIterator; 190 JSONSchemaPropertiesIterator begin() const; 191 JSONSchemaPropertiesIterator find(const std::string& key) const; 192 JSONSchemaPropertiesIterator end() const; 193 unsigned int size() const; 194 private: 195 std::map<std::string, JSONSchemaTypeDefinitionPtr> m_propertiesmap; 196 }; 197 198 /*! 199 \brief List of properties of the parameter (only needed when the 200 parameter is an object) 201 */ 202 CJsonSchemaPropertiesMap properties; 203 204 /*! 205 \brief Whether the type can have additional properties 206 or not 207 */ 208 bool hasAdditionalProperties = false; 209 210 /*! 211 \brief Type definition for additional properties 212 */ 213 JSONSchemaTypeDefinitionPtr additionalProperties; 214 }; 215 216 /*! 217 \ingroup jsonrpc 218 \brief Structure for a published json 219 rpc method. 220 221 Represents a published json rpc method 222 and is used to verify an incoming json 223 rpc request against a defined method. 224 */ 225 class JsonRpcMethod : protected CJSONUtils 226 { 227 public: 228 JsonRpcMethod(); 229 230 bool Parse(const CVariant &value); 231 JSONRPC_STATUS Check(const CVariant &requestParameters, ITransportLayer *transport, IClient *client, bool notification, MethodCall &methodCall, CVariant &outputParameters) const; 232 233 std::string missingReference; 234 235 /*! 236 \brief Name of the represented method 237 */ 238 std::string name; 239 /*! 240 \brief Pointer tot he implementation 241 of the represented method 242 */ 243 MethodCall method; 244 /*! 245 \brief Definition of the type of 246 request/response 247 */ 248 TransportLayerCapability transportneed = Response; 249 /*! 250 \brief Definition of the permissions needed 251 to execute the method 252 */ 253 OperationPermission permission = ReadData; 254 /*! 255 \brief Description of the method 256 */ 257 std::string description; 258 /*! 259 \brief List of accepted parameters 260 */ 261 std::vector<JSONSchemaTypeDefinitionPtr> parameters; 262 /*! 263 \brief Definition of the return value 264 */ 265 JSONSchemaTypeDefinitionPtr returns; 266 267 private: 268 bool parseParameter(const CVariant& value, const JSONSchemaTypeDefinitionPtr& parameter); 269 bool parseReturn(const CVariant &value); 270 static JSONRPC_STATUS checkParameter(const CVariant& requestParameters, 271 const JSONSchemaTypeDefinitionPtr& type, 272 unsigned int position, 273 CVariant& outputParameters, 274 unsigned int& handled, 275 CVariant& errorData); 276 }; 277 278 /*! 279 \ingroup jsonrpc 280 \brief Structure mapping a json rpc method 281 definition to an actual method implementation. 282 */ 283 typedef struct 284 { 285 /*! 286 \brief Name of the json rpc method. 287 */ 288 std::string name; 289 /*! 290 \brief Pointer to the actual 291 implementation of the json rpc 292 method. 293 */ 294 MethodCall method; 295 } JsonRpcMethodMap; 296 297 /*! 298 \ingroup jsonrpc 299 \brief Helper class for json schema service descriptor based 300 service descriptions for the json rpc API 301 302 Provides static functions to parse a complete json schema 303 service descriptor of a published service containing json rpc 304 methods, print the json schema service descriptor representation 305 into a string (mainly for output purposes) and evaluate and verify 306 parameters provided in a call to one of the publish json rpc methods 307 against a parameter definition parsed from a json schema service 308 descriptor. 309 */ 310 class CJSONServiceDescription : public CJSONUtils 311 { 312 friend class JSONSchemaTypeDefinition; 313 friend class JsonRpcMethod; 314 public: 315 /*! 316 \brief Parses the given json schema description and evaluates 317 and stores the defined type 318 \param jsonType json schema description to parse 319 \return True if the json schema description has been parsed successfully otherwise false 320 */ 321 static bool AddType(const std::string &jsonType); 322 323 /*! 324 \brief Parses the given json schema description and evaluates 325 and stores the defined method 326 \param jsonMethod json schema description to parse 327 \param method pointer to the implementation 328 \return True if the json schema description has been parsed successfully otherwise false 329 */ 330 static bool AddMethod(const std::string &jsonMethod, MethodCall method); 331 332 /*! 333 \brief Parses the given json schema description and evaluates 334 and stores the defined builtin method 335 \param jsonMethod json schema description to parse 336 \return True if the json schema description has been parsed successfully otherwise false 337 */ 338 static bool AddBuiltinMethod(const std::string &jsonMethod); 339 340 /*! 341 \brief Parses the given json schema description and evaluates 342 and stores the defined notification 343 \param jsonNotification json schema description to parse 344 \return True if the json schema description has been parsed successfully otherwise false 345 */ 346 static bool AddNotification(const std::string &jsonNotification); 347 348 static bool AddEnum(const std::string &name, const std::vector<CVariant> &values, CVariant::VariantType type = CVariant::VariantTypeNull, const CVariant &defaultValue = CVariant::ConstNullVariant); 349 static bool AddEnum(const std::string &name, const std::vector<std::string> &values); 350 static bool AddEnum(const std::string &name, const std::vector<int> &values); 351 352 /*! 353 \brief Gets the version of the json 354 schema description 355 \return Version of the json schema description 356 */ 357 static const char* GetVersion(); 358 359 /*! 360 \brief Prints the json schema description into the given result object 361 \param result Object into which the json schema description is printed 362 \param transport Transport layer capabilities 363 \param client Client requesting a print 364 \param printDescriptions Whether to print descriptions or not 365 \param printMetadata Whether to print XBMC specific data or not 366 \param filterByTransport Whether to filter by transport or not 367 */ 368 static JSONRPC_STATUS Print(CVariant &result, ITransportLayer *transport, IClient *client, bool printDescriptions = true, bool printMetadata = false, bool filterByTransport = true, const std::string &filterByName = "", const std::string &filterByType = "", bool printReferences = true); 369 370 /*! 371 \brief Checks the given parameters from the request against the 372 json schema description for the given method 373 \param method Called method 374 \param requestParameters Parameters from the request 375 \param client Client who sent the request 376 \param notification Whether the request was sent as a notification or not 377 \param methodCall Object which will contain the actual C/C++ method to be called 378 \param outputParameters Cleaned up parameter list 379 \return OK if the validation of the request succeeded otherwise an appropriate error code 380 381 Checks if the given method is a valid json rpc method, if the client has the permission 382 to call this method, if the method can be called as a notification or not, assigns the 383 actual C/C++ implementation of the method to the "methodCall" parameter and checks the 384 given parameters from the request against the json schema description for the given method. 385 */ 386 static JSONRPC_STATUS CheckCall(const char* method, const CVariant &requestParameters, ITransportLayer *transport, IClient *client, bool notification, MethodCall &methodCall, CVariant &outputParameters); 387 388 static JSONSchemaTypeDefinitionPtr GetType(const std::string &identification); 389 390 static void ResolveReferences(); 391 static void Cleanup(); 392 393 private: 394 static bool prepareDescription(std::string &description, CVariant &descriptionObject, std::string &name); 395 static bool addMethod(const std::string &jsonMethod, MethodCall method); 396 static void parseHeader(const CVariant &descriptionObject); 397 static bool parseJSONSchemaType(const CVariant &value, std::vector<JSONSchemaTypeDefinitionPtr>& typeDefinitions, JSONSchemaType &schemaType, std::string &missingReference); 398 static void addReferenceTypeDefinition(const JSONSchemaTypeDefinitionPtr& typeDefinition); 399 static void removeReferenceTypeDefinition(const std::string &typeID); 400 401 static void getReferencedTypes(const JSONSchemaTypeDefinitionPtr& type, 402 std::vector<std::string>& referencedTypes); 403 404 class CJsonRpcMethodMap 405 { 406 public: 407 CJsonRpcMethodMap(); 408 409 void add(const JsonRpcMethod &method); 410 411 typedef std::map<std::string, JsonRpcMethod>::const_iterator JsonRpcMethodIterator; 412 JsonRpcMethodIterator begin() const; 413 JsonRpcMethodIterator find(const std::string& key) const; 414 JsonRpcMethodIterator end() const; 415 416 void clear(); 417 private: 418 std::map<std::string, JsonRpcMethod> m_actionmap; 419 }; 420 421 static CJsonRpcMethodMap m_actionMap; 422 static std::map<std::string, JSONSchemaTypeDefinitionPtr> m_types; 423 static std::map<std::string, CVariant> m_notifications; 424 static JsonRpcMethodMap m_methodMaps[]; 425 426 typedef enum SchemaDefinition 427 { 428 SchemaDefinitionType, 429 SchemaDefinitionMethod 430 } SchemaDefinition; 431 432 typedef struct IncompleteSchemaDefinition 433 { 434 std::string Schema; 435 SchemaDefinition Type; 436 MethodCall Method; 437 } IncompleteSchemaDefinition; 438 439 typedef std::map<std::string, std::vector<IncompleteSchemaDefinition> > IncompleteSchemaDefinitionMap; 440 static IncompleteSchemaDefinitionMap m_incompleteDefinitions; 441 }; 442 } 443