Browse Source

Simplify http and remove resource

master
Jørgen Lien Sellæg 9 years ago
parent
commit
aa5f22c91c
  1. 14
      toREST/CMakeLists.txt
  2. 13
      toREST/include/http.hpp
  3. 4
      toREST/include/resource.hpp
  4. 26
      toREST/include/session.hpp
  5. 13
      toREST/src/http.cpp
  6. 62
      toREST/src/main.cxx
  7. 35
      toREST/src/session.cpp
  8. 66
      toREST/tests/session_test.cpp

14
toREST/CMakeLists.txt

@ -36,20 +36,20 @@ add_library(project_shared OBJECT ${source_files})
add_executable(${project_name} ./src/main.cxx $<TARGET_OBJECTS:project_shared>)
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_OBJECTS:project_shared>)
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_OBJECTS:project_shared>)
#target_include_directories(${test} PUBLIC ../lib/Catch)
#target_link_libraries(${test} ${global_libraries})
#add_test(${test} ${test})
find_package(Doxygen)

13
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_

4
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_

26
toREST/include/session.hpp

@ -4,6 +4,7 @@
#include <resource.hpp>
#include <util.hpp>
#include <libtorrent/session.hpp>
#include <http.hpp>
namespace session {
class basic_manager {
@ -15,15 +16,10 @@ namespace session {
virtual int listen_port() const = 0;
virtual void set_session(std::shared_ptr<libtorrent::session>) = 0;
virtual void set_listen_port() = 0;
// virtual std::shared_ptr<libtorrent::session> 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<libtorrent::session> get_session() override { return handle; }
void set_session(std::shared_ptr<libtorrent::session> 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<libtorrent::session> handle;
};
class basic_resource : public resource_base {
class basic_resource {
public:
virtual ~basic_resource() {}
virtual void set_session(std::shared_ptr<basic_manager>)=0;
@ -41,15 +37,14 @@ namespace session {
class resource : public basic_resource {
public:
resource(){} //TODO remove?
void set_session(std::shared_ptr<basic_manager> 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<bool>` `listen_port<bool>`
*/
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<basic_manager> mgr;
http::response response;
};
}
#endif // _TOREST_RESOURCE_HPP_

13
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());
}

62
toREST/src/main.cxx

@ -1,4 +1,5 @@
#include <server_http.hpp>
#include <http.hpp>
#include <session.hpp>
typedef SimpleWeb::Server<SimpleWeb::HTTP> HttpServer;
@ -6,59 +7,35 @@ typedef SimpleWeb::Server<SimpleWeb::HTTP> 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<HttpServer::Response> resp, std::shared_ptr<HttpServer::Request> 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<HttpServer::Response> resp, std::shared_ptr<HttpServer::Request> req) {
session.get();
*resp << session;
};
/*
http_server.resource["^/v1/session$"]["GET"]=[&session](HttpServer::Response &response, std::shared_ptr<HttpServer::Request> 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<HttpServer::Request> 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<HttpServer::Response> resp, std::shared_ptr<HttpServer::Request> 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;
};

35
toREST/src/session.cpp

@ -1,26 +1,21 @@
#include <session.hpp>
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);
}
}
}

66
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<basic_manager>(&(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);
}

Loading…
Cancel
Save