diff --git a/docs/api/test-rest-api.md b/docs/api/test-rest-api.md new file mode 100644 index 00000000..a634075e --- /dev/null +++ b/docs/api/test-rest-api.md @@ -0,0 +1,77 @@ +# Test all the REST API of domo. + +## Outlets + +### list + +``` +curl -v http://localhost:34000/v1/outlets +``` + +```json +{ + "id": "", + "outlets": [ + { + "id": 1, + "name": "Bureau JB", + "sender": 12797322, + "speech_name": "bureau", + "state": true, + "switch": 0 + }, + { + "id": 2, + "name": "Salon", + "sender": 12797322, + "speech_name": "salon", + "state": false, + "switch": 1 + }, + { + "id": 3, + "name": "Sapin", + "sender": 12797322, + "speech_name": "sapin", + "state": false, + "switch": 2 + } + ], + "response_code": 200, + "status": "passed" +} +``` +### read + +``` +curl -v http://localhost:34000/v1/outlets/2 +``` + +```json +{ + "id": 2, + "name": "Salon", + "sender": 12797322, + "speech_name": "salon", + "state": false, + "switch": 1 +} +``` + +### create + +``` +curl -X POST -v http://localhost:34000/v1/outlets -d "{\"name\":\"test\", \"sender\": 12797322, \"switch\": 4}" +``` + +### update + +``` +curl -X PUT -v http://localhost:34000/v1/outlets/4 -d "{\"name\":\"test1\", \"sender\": 1, \"switch\": 2}" +``` + +### delete + +``` +curl -v http://localhost:34000/v1/outlets/2 +``` diff --git a/docs/api/tests-api.md b/docs/api/tests-ubus-api.md similarity index 100% rename from docs/api/tests-api.md rename to docs/api/tests-ubus-api.md diff --git a/src/plugins/uhttpd/uhttpd-rest-api/core/http-parameter.cpp b/src/plugins/uhttpd/uhttpd-rest-api/core/http-parameter.cpp index a3ef8b6c..d03468e1 100644 --- a/src/plugins/uhttpd/uhttpd-rest-api/core/http-parameter.cpp +++ b/src/plugins/uhttpd/uhttpd-rest-api/core/http-parameter.cpp @@ -52,15 +52,12 @@ HttpParameter::HttpParameter(void) : m_request_timeout(-1) * * @brief parse parameters from the uri. */ -std::string HttpParameter::parse_from_uri(const std::string &a_parameters) +void HttpParameter::parse_from_uri(struct json_object *a_root_node, const std::string &a_parameters) { - std::string the_result; std::vector the_list; std::vector::iterator the_it; std::string the_key, the_value, the_value_decoded; std::size_t the_pos; - struct json_object *the_root_node = NULL; - the_root_node = json_object_new_object(); the_list = split_params(a_parameters, '&'); for (the_it = the_list.begin(); the_it != the_list.end(); ++the_it) @@ -79,15 +76,30 @@ std::string HttpParameter::parse_from_uri(const std::string &a_parameters) printf(" - valuedecode = %s\n", the_value_decoded.c_str()); #endif if (is_number(the_value_decoded)) - json_object_object_add(the_root_node, the_key.c_str(), json_object_new_int(std::stoi(the_value_decoded))); + json_object_object_add(a_root_node, the_key.c_str(), json_object_new_int(std::stoi(the_value_decoded))); else if (the_value_decoded == "true") - json_object_object_add(the_root_node, the_key.c_str(), json_object_new_boolean(true)); + json_object_object_add(a_root_node, the_key.c_str(), json_object_new_boolean(true)); else if (the_value_decoded == "false") - json_object_object_add(the_root_node, the_key.c_str(), json_object_new_boolean(false)); + json_object_object_add(a_root_node, the_key.c_str(), json_object_new_boolean(false)); else - json_object_object_add(the_root_node, the_key.c_str(), json_object_new_string(the_value_decoded.c_str())); + json_object_object_add(a_root_node, the_key.c_str(), json_object_new_string(the_value_decoded.c_str())); } } +} + +/*! ---------------------------------------------------------------------------- + * @fn parse_from_uri + * + * @brief parse parameters from the uri. + */ +std::string HttpParameter::parse_from_uri(const std::string &a_parameters) +{ + std::string the_result; + struct json_object *the_root_node; + + the_root_node = json_object_new_object(); + + parse_from_uri(the_root_node, a_parameters); the_result = json_object_to_json_string(the_root_node); diff --git a/src/plugins/uhttpd/uhttpd-rest-api/core/http-parameter.h b/src/plugins/uhttpd/uhttpd-rest-api/core/http-parameter.h index 2fc6d754..91ec1d88 100644 --- a/src/plugins/uhttpd/uhttpd-rest-api/core/http-parameter.h +++ b/src/plugins/uhttpd/uhttpd-rest-api/core/http-parameter.h @@ -33,6 +33,7 @@ /*----------------------------- Dependencies --------------------------------*/ struct client; +struct json_object; /*--------------------------------- CLASS ----------------------------------*/ @@ -41,6 +42,7 @@ class HttpParameter public: HttpParameter(void); + void parse_from_uri(struct json_object *a_root_node, const std::string &a_parameters); std::string parse_from_uri(const std::string &a_parameters); bool parse(client *a_client); diff --git a/src/plugins/uhttpd/uhttpd-rest-api/core/web-connection.h b/src/plugins/uhttpd/uhttpd-rest-api/core/web-connection.h index f97dcbdf..82bd9276 100644 --- a/src/plugins/uhttpd/uhttpd-rest-api/core/web-connection.h +++ b/src/plugins/uhttpd/uhttpd-rest-api/core/web-connection.h @@ -47,7 +47,7 @@ class WebConnection WebConnection(struct uhttpd_ops *an_ops, struct client *a_client); virtual ~WebConnection(void); - int add_data(const char *a_data, int a_len); + virtual int add_data(const char *a_data, int a_len); struct client *get_client(void); virtual void invoke(struct ubus_context *a_ctx); diff --git a/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-connection.cpp b/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-connection.cpp index 98e32526..6eb5d232 100644 --- a/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-connection.cpp +++ b/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-connection.cpp @@ -51,10 +51,11 @@ extern "C" { RestConnection::RestConnection(struct uhttpd_ops *an_ops, struct client *a_client, RestController *a_controller, const std::string &a_parameters) : WebConnection(an_ops, a_client), m_controller(a_controller), m_ctx(0) { + m_param_node = json_object_new_object(); if (!a_parameters.empty()) { HttpParameter the_http_parm; - m_connection_data = the_http_parm.parse_from_uri(a_parameters); + the_http_parm.parse_from_uri(m_param_node, a_parameters); } // printf("RestConnection:: constructor....\n"); } @@ -66,6 +67,7 @@ RestConnection::RestConnection(struct uhttpd_ops *an_ops, struct client *a_clien */ RestConnection::~RestConnection(void) { + json_object_put(m_param_node); abort(m_ctx); } @@ -96,23 +98,17 @@ void RestConnection::invoke(struct ubus_context *a_ctx) m_ctx = a_ctx; - printf("RestConnection::invoke(object: %s)....\n", m_controller->get_path().c_str()); + // printf("RestConnection::invoke(object: %s)....\n", m_controller->get_path().c_str()); if (!ubus_lookup_id(a_ctx, m_controller->get_ubus().get_path().c_str(), &the_id)) { - json_object *the_parameter_doc; - - the_parameter_doc = json_tokener_parse(m_connection_data.c_str()); - - if (the_parameter_doc == 0) - the_parameter_doc = parse_form_encoded_data(); - - // printf("RestConnection::invoke launch async call (%d)....\n", the_id); - printf("RestConnection::invoke - param:(%s)....\n", json_object_to_json_string(the_parameter_doc)); - +#if 0 + printf("RestConnection::invoke method: (%s)- param:(%s)....\n", + m_controller->get_ubus().get_method().c_str(), + json_object_to_json_string(m_param_node)); +#endif the_cmd.exec_async(a_ctx, the_id, m_controller->get_ubus().get_method().c_str(), - json_object_to_json_string(the_parameter_doc), this); + json_object_to_json_string(m_param_node), this); - json_object_put(the_parameter_doc); } else { @@ -120,21 +116,73 @@ void RestConnection::invoke(struct ubus_context *a_ctx) } } +/*! ---------------------------------------------------------------------------- + * @fn add_data + * + * @brief add data to the connection parameter. + */ +int RestConnection::add_data(const char *a_data, int a_len) +{ + struct json_object *the_root_node; + + the_root_node = json_tokener_parse(a_data); + + // the data is not a json object. + if (the_root_node == NULL) + { + char *the_parameters = strdup(a_data); + const char *the_encoded_name; + const char *the_encoded_value; + + for (the_encoded_name = strtok(the_parameters, "="); the_encoded_name != NULL; the_encoded_name = strtok(NULL, "=")) + { + std::string the_name, the_value; + + the_encoded_value = strtok(NULL, "&"); + + if (the_encoded_value == NULL) + the_encoded_value = ""; + + the_name = UriTransform::decode(std::string(the_encoded_name)); + the_value = UriTransform::decode(std::string(the_encoded_value)); + + json_object_object_add(m_param_node, the_name.c_str(), json_object_new_string(the_value.c_str())); + } + + free(the_parameters); + } + else // C'est un document json. + { + struct json_object_iterator the_it; + struct json_object_iterator the_it_end; + + the_it = json_object_iter_begin(the_root_node); + the_it_end = json_object_iter_end(the_root_node); + + while (!json_object_iter_equal(&the_it, &the_it_end)) + { + json_object_object_add(m_param_node, json_object_iter_peek_name(&the_it), + json_object_iter_peek_value(&the_it)); + json_object_iter_next(&the_it); + } + } + + return a_len; +} + /*! ---------------------------------------------------------------------------- * @fn parse_form_encoded_data * * @brief Parse the document content as form encoded parameters * and return them as a json object with an attribute for each parameter. */ -json_object *RestConnection::parse_form_encoded_data() +bool RestConnection::parse_form_encoded_data(json_object *a_root_document) { - json_object *the_parsed_document; + // removed !!!!! char *the_parameters = strdup(m_connection_data.c_str()); const char *the_encoded_name; const char *the_encoded_value; - the_parsed_document = json_object_new_object(); - for (the_encoded_name = strtok(the_parameters, "="); the_encoded_name != NULL; the_encoded_name = strtok(NULL, "=")) { std::string the_name, the_value; @@ -147,12 +195,12 @@ json_object *RestConnection::parse_form_encoded_data() the_name = UriTransform::decode(std::string(the_encoded_name)); the_value = UriTransform::decode(std::string(the_encoded_value)); - json_object_object_add(the_parsed_document, the_name.c_str(), json_object_new_string(the_value.c_str())); + json_object_object_add(a_root_document, the_name.c_str(), json_object_new_string(the_value.c_str())); } free(the_parameters); - return the_parsed_document; + return true; } /*! ---------------------------------------------------------------------------- diff --git a/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-connection.h b/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-connection.h index 69d325c5..ad65206c 100644 --- a/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-connection.h +++ b/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-connection.h @@ -49,11 +49,14 @@ class RestConnection : public WebConnection, public UBusExecReceiver void invoke(struct ubus_context *a_ctx); + int add_data(const char *a_data, int a_len); + private: RestController *m_controller; struct ubus_context *m_ctx; + struct json_object *m_param_node; - json_object *parse_form_encoded_data(void); + bool parse_form_encoded_data(json_object *a_root_document); void send_response(int a_result_code, std::string a_content_document = ""); }; diff --git a/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-controller.cpp b/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-controller.cpp index 95fa2f88..9641fb4a 100644 --- a/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-controller.cpp +++ b/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-controller.cpp @@ -46,9 +46,10 @@ * * @brief constructor of the rest controller object. */ -RestController::RestController(void) : m_parameter_position(std::string::npos) +RestController::RestController(void) : + mf_raw_response(true), + m_parameter_position(std::string::npos) { - printf("constructor empty.\n"); } /*! ---------------------------------------------------------------------------- @@ -58,12 +59,6 @@ RestController::RestController(void) : m_parameter_position(std::string::npos) */ RestController::RestController(const std::string &a_path, const std::string &a_method_get, const std::string &a_method_put, int a_timeout, bool a_raw_response) : WebController(a_path), mf_raw_response(false) -#if 0 - m_method_get(a_method_get), - m_method_put(a_method_put), - m_timeout(a_timeout), - mf_raw_response(a_raw_response) -#endif { } @@ -146,7 +141,7 @@ bool RestController::find(uint8_t a_method, const std::string &an_url) std::vector::iterator the_it; std::size_t the_pos; - printf("find : url: %s, endpoint:%s method: %d ubus:%s\n", an_url.c_str(), m_endpoint.c_str(), a_method, get_ubus().get_method().c_str()); + // printf("find : url: %s, endpoint:%s method: %d ubus:%s\n", an_url.c_str(), m_endpoint.c_str(), a_method, get_ubus().get_method().c_str()); if ((m_endpoint == an_url) && (m_method == a_method)) { return true; @@ -167,8 +162,6 @@ bool RestController::find(uint8_t a_method, const std::string &an_url) the_endpoint.erase(the_pos); } - printf("endpoint: %s\n", the_endpoint.c_str()); - the_pos = an_url.find(the_endpoint); if (the_pos == std::string::npos) { @@ -177,11 +170,10 @@ bool RestController::find(uint8_t a_method, const std::string &an_url) if (m_method != a_method) { - printf ("pas la bonne methode.(%d) != (%d)\n", m_method, a_method); + // printf ("pas la bonne methode.(%d) != (%d)\n", m_method, a_method); return false; } - printf("!!!!!! c'est bon. c'est le meme.\n"); return true; } @@ -199,13 +191,16 @@ std::string RestController::get_parameter(const std::string &an_uri) if (m_parameter_position != std::string::npos) { the_tmp = an_uri.substr(m_parameter_position); - printf("uri: %s, tmp: %s pos: %d\n", an_uri.c_str(), the_tmp.c_str(), (int)m_parameter_position); + // printf("uri: %s, tmp: %s pos: %d\n", an_uri.c_str(), the_tmp.c_str(), (int)m_parameter_position); } the_pos = the_tmp.find_first_of("/"); if (the_pos != std::string::npos) { the_tmp = the_tmp.substr(0, the_pos); + } + + if (!the_tmp.empty()) { the_parameter = fmt::format("{}={}", m_parameter_name, the_tmp); } @@ -279,86 +274,5 @@ void RestController::manage_endpoint(void) m_controller = m_parameter_name.substr(the_pos + 1); m_parameter_name = m_parameter_name.substr(0, the_pos); } - printf ("endpoint: %s pos: %d ubus: %s\n", m_endpoint.c_str(), (int)m_parameter_position, get_ubus().get_method().c_str()); + // printf ("endpoint: %s pos: %d ubus: %s\n", m_endpoint.c_str(), (int)m_parameter_position, get_ubus().get_method().c_str()); } - - -#if 0 - std::string - - // Remove the last char if it's a / - the_pos = the_endpoint.find_last_of("/"); - if(the_pos != std::string::npos) - { - the_endpoint.erase(the_pos); - } - - printf("endpoint: %s\n", the_endpoint.c_str()); - - the_pos = an_url.find(the_endpoint); - if (the_pos == std::string::npos) - { - return false; - } - - printf("c'est bon. c'est le meme.\n"); - return true; -#endif - -#if 0 -/*! ---------------------------------------------------------------------------- - * @fn get_method_get - * - * @brief return the get method of the controller. - */ -std::string RestController::get_method_get(void) -{ - return ""; //m_method_get; -} - -/*! ---------------------------------------------------------------------------- - * @fn get_method_put - * - * @brief return the put method of the controller. - */ -std::string RestController::get_method_put(void) -{ - return ""; //m_method_put; -} - -/*! ---------------------------------------------------------------------------- - * @fn get_timeout - * - * @brief return the wanted timeout of the controller. - */ -uint16_t RestController::get_timeout(void) -{ - return 0; //m_timeout; -} - - -/*! ---------------------------------------------------------------------------- - * @fn get_method - * - * @brief return the right method in function of the client connection. - */ -std::string RestController::get_method(uint8_t a_method) -{ -#if 0 - switch (a_method) - { - case UH_HTTP_MSG_GET: - return m_method_get; - break; - case UH_HTTP_MSG_PUT: - case UH_HTTP_MSG_POST: - return m_method_put; - break; - default: - // TODO ERROR - break; - }; -#endif - return ""; -} -#endif \ No newline at end of file diff --git a/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-controller.h b/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-controller.h index f5b3f2e7..4d62be54 100644 --- a/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-controller.h +++ b/src/plugins/uhttpd/uhttpd-rest-api/rest/rest-controller.h @@ -49,7 +49,7 @@ class RestController : public WebController public: RestController(void); RestController(const std::string &a_path, const std::string &a_method_get = "", const std::string &a_method_put = "", int a_timeout = kDefaultTimeout, bool a_raw_response = false); - virtual ~RestController(void); + ~RestController(void); WebConnection *new_connection(struct uhttpd_ops *an_ops, struct client *a_client, const std::string &a_parameters); @@ -65,33 +65,17 @@ class RestController : public WebController bool is_raw_response(void); -/* - std::string get_method_get(void); - std::string get_method_put(void); - uint16_t get_timeout(void); - - std::string get_method(uint8_t a_method); -*/ protected: uint8_t m_method; std::string m_endpoint; Ubus m_ubus; bool mf_raw_response; -/* - std::string m_name; - std::string m_path; - std::string m_method_get; - std::string m_method_put; - uint16_t m_timeout; -*/ - -private: + private: void manage_endpoint(void); std::string m_parameter_name; std::size_t m_parameter_position; std::string m_controller; - }; #endif /* _REST_CONTROLLER_H */ diff --git a/src/plugins/uhttpd/uhttpd-rest-api/uhttp-server.cpp b/src/plugins/uhttpd/uhttpd-rest-api/uhttp-server.cpp index 91cbbaf4..d92a15ab 100644 --- a/src/plugins/uhttpd/uhttpd-rest-api/uhttp-server.cpp +++ b/src/plugins/uhttpd/uhttpd-rest-api/uhttp-server.cpp @@ -283,7 +283,7 @@ struct ubus_context *UhttpServer::get_context(void) bool UhttpServer::check_url(const std::string &an_url) { ControllerIterator the_it; - printf("UhttpServer::check_url: %s\n", an_url.c_str()); + // printf("UhttpServer::check_url: %s\n", an_url.c_str()); for (the_it = m_controllers.begin(); the_it != m_controllers.end(); ++the_it) { @@ -306,7 +306,7 @@ void UhttpServer::handle_request(struct client *a_cl, const std::string &an_url, std::string the_url, the_parameters; std::size_t the_pos; WebController *the_controller; - printf("uhttp_server_handle_request : url: <%s> client: %p\n", an_url.c_str(), a_cl); + // printf("uhttp_server_handle_request : url: <%s> client: %p\n", an_url.c_str(), a_cl); // Check if parameters are present on the url. the_pos = an_url.find_first_of("?", 0); @@ -325,7 +325,6 @@ void UhttpServer::handle_request(struct client *a_cl, const std::string &an_url, the_controller = get_controller(a_cl->request.method, the_url); if (the_controller == NULL) { - printf ("not found :( \n"); std::string the_msg; the_msg = fmt::format(kJsonControlerNotFound, the_url); send_error(a_cl, 404, "Not Found", the_msg); @@ -333,7 +332,7 @@ void UhttpServer::handle_request(struct client *a_cl, const std::string &an_url, } the_parameters = the_controller->get_parameter(the_url); - printf ("the parameter: %s\n", the_parameters.c_str()); + // printf ("the parameter: %s\n", the_parameters.c_str()); // We found the controller. // printf("method: %d\n", a_cl->request.method); struct dispatch *d = &a_cl->dispatch; @@ -362,7 +361,7 @@ void UhttpServer::handle_request(struct client *a_cl, const std::string &an_url, send_error(a_cl, 400, "Bad Request", "Invalid Request"); } - printf("uhttp_server_handle_request -done.\n"); + // printf("uhttp_server_handle_request -done.\n"); } /*! ---------------------------------------------------------------------------- @@ -425,6 +424,12 @@ int UhttpServer::load_config_dir(const char *a_config_dir_path) struct dirent *the_dir_ent = NULL; std::string the_path; struct json_object *the_root_node; + + if (a_config_dir_path == NULL) { + fprintf (stderr, "ERROR: a config dir is mandatory.\n"); + return -1; + } + the_rep = opendir(a_config_dir_path); if (the_rep == NULL) { fprintf (stderr, "Impossible to open the config directory (%s).\n", a_config_dir_path); @@ -661,32 +666,12 @@ struct json_object *UhttpServer::load(const std::string &a_file) int UhttpServer::add_controller(ControllerKey a_key, WebController *a_controller) { std::string the_path; - std::size_t the_pos; if (a_controller == NULL) return -1; -// a_controller->set_name(an_uri); - m_controllers[a_key] = std::unique_ptr(a_controller); - //m_controller_array[an_uri] = a_controller; - -#if 0 - printf("add: an_uri:%s\n", an_uri.c_str()); - - // Keep a list of the API root. to check if a controller is managed by this plugin or not. - the_pos = an_uri.find_first_of("/", 1); - if (the_pos != std::string::npos) - { - the_path = an_uri.substr(0, the_pos + 1); - if (std::find(m_path_list.begin(), m_path_list.end(), the_path) == m_path_list.end()) - { - // uniq version. we add it. - m_path_list.push_back(the_path); - } - } -#endif return 0; } @@ -704,7 +689,6 @@ WebController *UhttpServer::get_controller(uint8_t a_method, const std::string & { if (the_it->second.get()->find(a_method, an_url)) { - printf ("return the controller.\n"); return the_it->second.get(); } }