From aa5f22c91c5bc173b7a7990e9846e8fade77f4a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20Lien=20Sell=C3=A6g?= Date: Tue, 25 Apr 2017 09:57:30 +0200 Subject: [PATCH] Simplify http and remove resource --- toREST/CMakeLists.txt | 14 ++++---- toREST/include/http.hpp | 13 +------ toREST/include/resource.hpp | 4 +-- toREST/include/session.hpp | 26 ++++++-------- toREST/src/http.cpp | 13 ++----- toREST/src/main.cxx | 62 ++++++++++---------------------- toREST/src/session.cpp | 35 ++++++++----------- toREST/tests/session_test.cpp | 66 +++++++++++++++++------------------ 8 files changed, 90 insertions(+), 143 deletions(-) diff --git a/toREST/CMakeLists.txt b/toREST/CMakeLists.txt index fa6a261..80169b2 100644 --- a/toREST/CMakeLists.txt +++ b/toREST/CMakeLists.txt @@ -36,20 +36,20 @@ add_library(project_shared OBJECT ${source_files}) add_executable(${project_name} ./src/main.cxx $) target_link_libraries(${project_name} ${global_libraries}) -enable_testing() +# enable_testing() -file(GLOB test_files "./tests/*.cpp") +# file(GLOB test_files "./tests/*.cpp") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O0 -Wall -fprofile-arcs -ftest-coverage ") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -Wall -fprofile-arcs -ftest-coverage ") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage ") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage ") -set(test yea) -add_executable(${test} ${test_files} $) -target_include_directories(${test} PUBLIC ../lib/Catch) -target_link_libraries(${test} ${global_libraries}) -add_test(${test} ${test}) +set(test test${project_name}) +# add_executable(${test} ${test_files} $) +#target_include_directories(${test} PUBLIC ../lib/Catch) +#target_link_libraries(${test} ${global_libraries}) +#add_test(${test} ${test}) find_package(Doxygen) diff --git a/toREST/include/http.hpp b/toREST/include/http.hpp index 78ca4ee..75c4e29 100644 --- a/toREST/include/http.hpp +++ b/toREST/include/http.hpp @@ -52,6 +52,7 @@ namespace http { public: response():status_code(http::ok){} void set_body(const std::string &content) override { body=content; } + void set_body(const nlohmann::json &json); void add_header(const http::header &header) override { response_headers.emplace(header); } void set_status(http::status code) override { status_code=code; } protected: @@ -60,18 +61,6 @@ namespace http { headers response_headers; code status_code; }; - - /// A JSON response. The default constructor sets the Content-Type header to - /// application/json, the response defaults to 200 OK. - class json_response : public response { - public: - json_response(); - /// Method updates the http status code. set_statups also updates the body to correspond to the new status. - /// Notice: if you previously set a body, it will be overwritten by the status code JSON representation. - void set_status(http::status code) override ; - void set_body(const nlohmann::json &json) ; - using response::set_body; - }; }; #endif // _TOREST_HTTP_HPP_ diff --git a/toREST/include/resource.hpp b/toREST/include/resource.hpp index fa015fb..f0834aa 100644 --- a/toREST/include/resource.hpp +++ b/toREST/include/resource.hpp @@ -19,9 +19,9 @@ public: /// PUT Update/Replace 404 (Not Found), unless you want to update/replace every resource in the entire collection. 200 (OK) or 204 (No Content). 404 (Not Found), if ID not found or invalid. virtual void put(nlohmann::json data=nullptr){} /// get a reference to the underlying JSON response - http::json_response& get_response(){ return json_response; } + http::response& get_response(){ return json_response; } protected: - http::json_response json_response; + http::response json_response; }; #endif // _TOREST_RESOURCE_HPP_ diff --git a/toREST/include/session.hpp b/toREST/include/session.hpp index e12afb1..8566089 100644 --- a/toREST/include/session.hpp +++ b/toREST/include/session.hpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace session { class basic_manager { @@ -15,15 +16,10 @@ namespace session { virtual int listen_port() const = 0; virtual void set_session(std::shared_ptr) = 0; virtual void set_listen_port() = 0; - // virtual std::shared_ptr get_session() = 0; }; - class translate - { public: static nlohmann::json to_json(const libtorrent::session_handle &handle); }; - class manager : public basic_manager { public: - // std::shared_ptr get_session() override { return handle; } void set_session(std::shared_ptr session) override { handle=session; } nlohmann::json get_json() const override ; bool is_valid() const override { return handle && handle->is_valid(); } @@ -33,7 +29,7 @@ namespace session { std::shared_ptr handle; }; - class basic_resource : public resource_base { + class basic_resource { public: virtual ~basic_resource() {} virtual void set_session(std::shared_ptr)=0; @@ -41,15 +37,14 @@ namespace session { class resource : public basic_resource { public: - resource(){} //TODO remove? void set_session(std::shared_ptr session_manager) override { mgr=session_manager; } - virtual void get(nlohmann::json arg=nullptr) override { + virtual void get(nlohmann::json arg=nullptr) { if(mgr && mgr->is_valid()){ - get_response().set_status(http::ok); - get_response().set_body(mgr->get_json()); + response.set_status(http::ok); + response.set_body(mgr->get_json()); }else{ - get_response().set_status(http::service_unavailable); + response.set_status(http::service_unavailable); } } /** @@ -59,14 +54,15 @@ namespace session { * @param[in] data takes an JSON object with at least one `action` set. * available `action`s are `is_paused` `listen_port` */ - virtual void patch(const nlohmann::json&data=nlohmann::json::object()); + void patch(const nlohmann::json&data=nlohmann::json::object()); // @todo should we return service unavailable or just method not allowed? - virtual void del(nlohmann::json arg=nullptr) override { get_response().set_status(http::method_not_allowed); } - virtual void put(nlohmann::json arg=nullptr) override { get_response().set_status(http::method_not_allowed); } - virtual void post(nlohmann::json arg=nullptr) override { get_response().set_status(http::method_not_allowed); } + void del(nlohmann::json arg=nullptr) { response.set_status(http::method_not_allowed); } + void put(nlohmann::json arg=nullptr) { response.set_status(http::method_not_allowed); } + virtual void post(nlohmann::json arg=nullptr) { response.set_status(http::method_not_allowed); } protected: std::shared_ptr mgr; + http::response response; }; } #endif // _TOREST_RESOURCE_HPP_ diff --git a/toREST/src/http.cpp b/toREST/src/http.cpp index 25016a5..28c9ef4 100644 --- a/toREST/src/http.cpp +++ b/toREST/src/http.cpp @@ -34,7 +34,7 @@ std::ostream &http::response::do_response(std::ostream &os) const { return os << body.size() << "\r\n\r\n" << body; } else { - auto body_replace= std::to_string(status_code.first) + " " + status_code.second; + const auto body_replace=std::to_string(status_code.first) + " " + status_code.second; return os << body_replace.size() << "\r\n\r\n" << body_replace; } @@ -42,14 +42,7 @@ std::ostream &http::response::do_response(std::ostream &os) const { return os << "\r\n"; } -void http::json_response::set_status(http::status code){ - response::set_status(code); - set_body({{"code",status_code.first},{"status",status_code.second}}); -} - -void http::json_response::set_body(const nlohmann::json &json){ response::set_body(json.dump()); } - -http::json_response::json_response(){ +void http::response::set_body(const nlohmann::json &json){ add_header({"Content-Type","application/json"}); - set_body({{"code",status_code.first},{"status",status_code.second}}); + response::set_body(json.dump()); } diff --git a/toREST/src/main.cxx b/toREST/src/main.cxx index 9d91a73..af344df 100644 --- a/toREST/src/main.cxx +++ b/toREST/src/main.cxx @@ -1,4 +1,5 @@ #include +#include #include typedef SimpleWeb::Server HttpServer; @@ -6,59 +7,35 @@ typedef SimpleWeb::Server HttpServer; using namespace std; int main(int argc, char *argv[]) { - //auto config=filesystem::get_config(); - //auto wsc=config["webserver"]; int http_port=8080, http_threads=4; HttpServer http_server(http_port,http_threads); + + libtorrent::session session; + http_server.default_resource["GET"]=[](std::shared_ptr resp, std::shared_ptr req) { auto response = http::response(); response.set_status(http::not_found); *resp << response; }; - session::resource session; - http_server.resource["^/v1/session$"]["GET"]=[&session](std::shared_ptr resp, std::shared_ptr req) { - session.get(); - *resp << session; - }; - - /* - http_server.resource["^/v1/session$"]["GET"]=[&session](HttpServer::Response &response, std::shared_ptr request) { - http http(&response, request.get()); - if(!session.is_valid()){ - return http.internal_server_error(); - } - auto json=translate::session::to_json(session); - http.json(json); - }; - http_server.resource["^/v1/session$"]["POST"]=[&session](HttpServer::Response &response, std::shared_ptr request) { - http http(&response, request.get()); - if(!http.is_json_request()){ - return http.not_found(); - } - if(!session.is_valid()){ - return http.internal_server_error(); - } - nlohmann::json json(request->content); - std::string action = json.value("action",""); - if(action==""){ - return http.bad_request("Invalid JSON request"); - } - if(action=="TORRENTS_PAUSE"){ - session.pause(); - } else if (action=="TORRENTS_START"){ - session.resume(); + http_server.resource["^/session(\\?.*)?\\/?$"]["GET"]=[&session](std::shared_ptr resp, std::shared_ptr req) { + auto response = http::response(); + const auto path = util::uri::parse(req->path); + if (session.is_valid()) { + const auto session_settings=session.get_settings(); + + response.set_body( + { + {"paused",session.is_paused()}, + {"up_limit",session.get_settings()} + } + ); + } else { + } - return http.json(json); + *resp << response; }; -*/ -/* - std::thread websocketserver_thread([&websocket_server]() { - websocket_server.start(); - std::cout << "WebSocketServer listening on port " << config["websocket.port"] << std::endl; - }); -*/ std::thread server_thread([&http_server](){ http_server.start(); }); @@ -77,7 +54,6 @@ int main(int argc, char *argv[]) { } server_thread.join(); - // websocketserver_thread.join(); return 0; }; diff --git a/toREST/src/session.cpp b/toREST/src/session.cpp index a58fdef..3d098c3 100644 --- a/toREST/src/session.cpp +++ b/toREST/src/session.cpp @@ -1,26 +1,21 @@ #include namespace session { - nlohmann::json translate::to_json(const libtorrent::session_handle &handle){ - nlohmann::json session_json; - return session_json; - } - nlohmann::json manager::get_json() const { nlohmann::json session_json; - session_json["peer_id"] = handle->id().to_string(); - session_json["is_paused"] = handle->is_paused(); - session_json["is_listening"] = handle->is_listening(); - session_json["listen_port"] = handle->listen_port(); - session_json["ssl_listen_port"] = handle->ssl_listen_port(); + session_json["id"] = handle->id().to_string(); + session_json["paused"] = handle->is_paused(); + session_json["listening"] = handle->is_listening(); + session_json["port"] = handle->listen_port(); + session_json["ssl_port"] = handle->ssl_listen_port(); return session_json; } bool manager::patch(const nlohmann::json &data) { - int is_paused=data["is_paued"]; - int listen_port=data["listen_port"]; + int paused=data["paused"]; + int port=data["port"]; - auto pause = [this](int is_paused){ + const auto pause = [this](int is_paused){ if(is_paused!=-1){ if(is_paused==handle->is_paused()){ return true; @@ -35,7 +30,7 @@ namespace session { return false; }; - auto listen = [this](int listen_port){ + const auto listen = [this](int listen_port){ if(listen_port!=-1&&listen_port>6880){ libtorrent::settings_pack sp; sp.set_str(libtorrent::settings_pack::listen_interfaces,"0.0.0.0:"+std::to_string(listen_port)); @@ -45,7 +40,7 @@ namespace session { return false; }; - return pause(is_paused) && listen(listen_port); + return pause(paused) && listen(port); }; void resource::patch(const nlohmann::json &data){ if(mgr && mgr->is_valid()){ @@ -56,18 +51,18 @@ namespace session { if(at_at_least_one_option_is_set){ nlohmann::json patch={{"is_paused",is_paused},{"listen_port",listen_port}}; if(mgr->patch(patch)){ - return get_response().set_status(http::ok); + return response.set_status(http::ok); }else{ - return get_response().set_status(http::internal_server_error); + return response.set_status(http::internal_server_error); } }else{ - return get_response().set_status(http::bad_request); + return response.set_status(http::bad_request); } } - return get_response().set_status(http::bad_request); + return response.set_status(http::bad_request); // auto data=data.array(); }else{ - return get_response().set_status(http::service_unavailable); + return response.set_status(http::service_unavailable); } } } \ No newline at end of file diff --git a/toREST/tests/session_test.cpp b/toREST/tests/session_test.cpp index 5355094..20e3f4f 100644 --- a/toREST/tests/session_test.cpp +++ b/toREST/tests/session_test.cpp @@ -13,36 +13,36 @@ const std::string bad_request ="HTTP/1.1 400 Bad Request\r\nContent- using namespace session; SCENARIO("test of responses by session_manager on /v1/session"){ - session::resource sr; + session::resource sut; std::stringstream ss; GIVEN("the session is invalid"){ WHEN("we receive a GET request"){ - sr.get(); - ss << sr; + sut.get(); + ss << sut; THEN("the response is a 503 Service Unavailable JSON object") REQUIRE(ss.str()==service_unavailable_json); } WHEN("we receive a PATCH request"){ - sr.patch(); - ss << sr; + sut.patch(); + ss << sut; THEN("the response is a 503 Service Unavailable JSON object") REQUIRE(ss.str()==service_unavailable_json); } WHEN("we receive a POST request"){ - sr.post(); - ss << sr; + sut.post(); + ss << sut; THEN("the response is a 405 Method Not Allowed JSON object") REQUIRE(ss.str()==method_not_allowed_json); } WHEN("we receive a DELETE request"){ - sr.del(); - ss << sr; + sut.del(); + ss << sut; THEN("the response is a 405 Method Not Allowed JSON object") REQUIRE(ss.str()==method_not_allowed_json); } WHEN("we receive a PUT request"){ - sr.put(); - ss << sr; + sut.put(); + ss << sut; THEN("the response is a 405 Method Not Allowed JSON object") REQUIRE(ss.str()==method_not_allowed_json); } @@ -52,64 +52,62 @@ SCENARIO("test of responses by session_manager on /v1/session"){ When(Method(mock_session,basic_manager::is_valid)).AlwaysReturn(true); When(Method(mock_session,basic_manager::get_json)).AlwaysReturn(nullptr); auto session=std::shared_ptr(&(mock_session.get()),[](...){}); - sr.set_session(session); - - + sut.set_session(session); + WHEN("we receive a GET request"){ - sr.get(); - ss << sr; + sut.get(); + ss << sut; THEN("the response is a 200 OK JSON object ") REQUIRE(ss.str()==ok_nullptr_json); } - - + WHEN("we receive a PATCH request with invalid data"){ GIVEN("the JSON is invalid"){ - sr.patch(nullptr); - ss << sr; + sut.patch(nullptr); + ss << sut; THEN("the response is a 400 Bad Request JSON object") REQUIRE(ss.str()==bad_request); } GIVEN("the JSON is valid, but contains no data"){ - sr.patch({}); - ss << sr; + sut.patch({}); + ss << sut; THEN("the response is a 400 Bad Request JSON object") REQUIRE(ss.str()==bad_request); } GIVEN("the JSON is valid, but the port number is to low"){ When(Method(mock_session,basic_manager::patch)).AlwaysReturn(false); - sr.patch({{"listen_port",1}}); - ss << sr; + sut.patch({{"listen_port",1}}); + ss << sut; THEN("the response is a 500 Internal Server Error JSON object") REQUIRE(ss.str()==internal_server_error_json); } GIVEN("the JSON is valid, but listen_port is a string"){ - sr.patch({{"listen_port","1"}}); - ss << sr; + sut.patch({{"listen_port","1"}}); + ss << sut; THEN("the response is a 400 Bad Request JSON object") REQUIRE(ss.str()==bad_request); } GIVEN("the JSON is valid, but is_paused is a string"){ - sr.patch({{"is_paused","1"}}); - ss << sr; + sut.patch({{"is_paused","1"}}); + ss << sut; THEN("the response is a 400 Bad Request JSON object") REQUIRE(ss.str()==bad_request); } WHEN("we receive a POST request"){ - sr.post(); - ss << sr; + sut.post(); + ss << sut; THEN("the response is a 405 Method Not Allowed JSON object") REQUIRE(ss.str()==method_not_allowed_json); } WHEN("we receive a DELETE request"){ - sr.del(); - ss << sr; + sut.del(); + ss << sut; THEN("the response is a 405 Method Not Allowed JSON object") REQUIRE(ss.str()==method_not_allowed_json); } WHEN("we receive a PUT request"){ - sr.put(); - ss << sr; + sut.put(); + ss << sut; THEN("the response is a 405 Method Not Allowed JSON object") REQUIRE(ss.str()==method_not_allowed_json); }