Browse Source

cleanup: somewhat similar style in all files

master
Jørgen Lien Sellæg 9 years ago
parent
commit
f26df2639e
  1. 80
      toREST/include/http.hpp
  2. 81
      toREST/include/session.hpp
  3. 80
      toREST/include/util.hpp
  4. 93
      toREST/src/http.cpp
  5. 1
      toREST/tests/include/ConfigContext.hpp
  6. 7
      toREST/tests/include/ServerContext.hpp
  7. 2
      toREST/tests/include/TorrentContext.hpp

80
toREST/include/http.hpp

@ -1,56 +1,58 @@
#ifndef _TOREST_HTTP_HPP_ #ifndef _TR_HTTP_HPP_
#define _TOREST_HTTP_HPP_ #define _TR_HTTP_HPP_
#include <json.hpp> #include <json.hpp>
#include <unordered_map> #include <unordered_map>
namespace http { namespace http {
/// http codes /// http codes
enum status { enum status {
/*! Standard response for successful HTTP requests. */ ok=200, /*! Standard response for successful HTTP requests. */ ok = 200,
/*! The request has been fulfilled, resulting in the creation of a new resource. */ created=201, /*! The request has been fulfilled, resulting in the creation of a new resource. */ created = 201,
/*! The request has been accepted for processing, but the processing has not been completed. */ accepted=202, /*! The request has been accepted for processing, but the processing has not been completed. */ accepted = 202,
/*! The server successfully processed the request and is not returning any content. */ no_content=204, /*! The server successfully processed the request and is not returning any content. */ no_content = 204,
/*! The server cannot or will not process the request due to an apparent client error */ bad_request=400, /*! The server cannot or will not process the request due to an apparent client error */ bad_request = 400,
/*! Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided. */ unauthorized=401, /*! Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided. */ unauthorized = 401,
/*! Reserved for future use. The */ payment_required=402, /*! Reserved for future use. The */ payment_required = 402,
/*! the request was a valid request, but the server is refusing to respond to it. */ forbidden=403, /*! the request was a valid request, but the server is refusing to respond to it. */ forbidden = 403,
/*! The requested resource could not be found but may be available in the future. */ not_found=404, /*! The requested resource could not be found but may be available in the future. */ not_found = 404,
/*! Allowed A request method is not supported for the requested resource */ method_not_allowed=405, /*! Allowed A request method is not supported for the requested resource */ method_not_allowed = 405,
/*! The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request. */ not_acceptable=406, /*! The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request. */ not_acceptable = 406,
/*! A generic error message, given when an unexpected condition was encountered and no more specific message is suitable. */ internal_server_error=500, /*! A generic error message, given when an unexpected condition was encountered and no more specific message is suitable. */ internal_server_error = 500,
/*! The server either does not recognize the request method, or it lacks the ability to fulfill the request. */ not_implemented=501, /*! The server either does not recognize the request method, or it lacks the ability to fulfill the request. */ not_implemented = 501,
/*! The server was acting as a gateway or proxy and received an invalid response from the upstream server. */ bad_gateway=502, /*! The server was acting as a gateway or proxy and received an invalid response from the upstream server. */ bad_gateway = 502,
/*! The server is currently unavailable (because it is overloaded or down for maintenance). Generally, this is a temporary state. */ service_unavailable=503, /*! The server is currently unavailable (because it is overloaded or down for maintenance). Generally, this is a temporary state. */ service_unavailable = 503,
/*! Gateway timed out */ gateway_timeout=504, /*! Gateway timed out */ gateway_timeout = 504,
/*! http-version not supported */ http_version_not_supported=505 /*! http-version not supported */ http_version_not_supported = 505
}; };
typedef std::pair<std::string,std::string> header; typedef std::pair<std::string, std::string> header;
typedef std::unordered_map<std::string,std::string> headers; typedef std::unordered_map<std::string, std::string> headers;
/// creates a http::code object out of a http::status code /// creates a http::code object out of a http::status code
class code { class code {
public: public:
code(status status); code(status status);
public:
public:
status first; status first;
std::string second; std::string second;
}; };
class response { class response {
public: public:
friend std::ostream& operator<<(std::ostream& os,const response &rh){ return rh.do_response(os); } friend std::ostream &operator<<(std::ostream &os, const response &rh) { return rh.do_response(os); }
response():status_code(http::ok){} response() : status_code(http::ok) {}
void set_body(const std::string &content) { body=content; } void set_body(const std::string &content) { body = content; }
void set_body(const nlohmann::json &json); void set_body(const nlohmann::json &json);
void add_header(const http::header &header) { response_headers.emplace(header); } void add_header(const http::header &header) { response_headers.emplace(header); }
void set_status(http::status code) { status_code=code; } void set_status(http::status code) { status_code = code; }
std::ostream& do_response(std::ostream &os) const; std::ostream &do_response(std::ostream &os) const;
protected:
protected:
std::string body; std::string body;
headers response_headers; headers response_headers;
code status_code; code status_code;
}; };
}; };
#endif // _TOREST_HTTP_HPP_ #endif

81
toREST/include/session.hpp

@ -1,70 +1,75 @@
#ifndef _TR_SESSION_HPP_
#define _TR_SESSION_HPP_
#include <http.hpp> #include <http.hpp>
#include <util.hpp> #include <util.hpp>
namespace tr{ namespace tr {
namespace session { namespace session {
template<class torrent_session, class request, class response> template <class torrent_session, class request, class response>
void get(torrent_session&session,response resp,request req){ void get(torrent_session &session, response resp, request req) {
auto http_response = http::response(); auto http_response = http::response();
if (session.is_valid()) { if (session.is_valid()) {
const auto settings = session.get_settings(); const auto settings = session.get_settings();
http_response.set_body({ http_response.set_body({
{ "paused", session.is_paused() }, {"paused", session.is_paused()},
{ "port", session.listen_port() }, {"port", session.listen_port()},
{ "dht_enabled", session.is_dht_running() }, {"dht_enabled", session.is_dht_running()},
{ "down_limit", settings.get_int(settings.download_rate_limit) }, {"down_limit", settings.get_int(settings.download_rate_limit)},
{ "up_limit", settings.get_int(settings.upload_rate_limit) }, {"up_limit", settings.get_int(settings.upload_rate_limit)},
{ "torrents", session.get_torrents().size() }, //TODO Optimize {"torrents", session.get_torrents().size()}, //TODO Optimize
// { "default_download_dir", default_download_dir.filename().string() }, // { "default_download_dir", default_download_dir.filename().string() },
// { "root_dir", root_dir.string() }, // { "root_dir", root_dir.string() },
}); });
} else { } else {
auto response_code = http::code(http::service_unavailable); auto response_code = http::code(http::service_unavailable);
http_response.set_body({{"code", response_code.first}, { "status", response_code.second}}); http_response.set_body({{"code", response_code.first}, {"status", response_code.second}});
http_response.set_status(response_code.first); http_response.set_status(response_code.first);
} }
*resp << http_response; *resp << http_response;
} }
template<class torrent_session, class request, class response> template <class torrent_session, class request, class response>
void patch(torrent_session&session,response resp,request req){ void patch(torrent_session &session, response resp, request req) {
auto http_response = http::response(); auto http_response = http::response();
if (!session.is_valid()) { if (!session.is_valid()) {
auto response_code = http::code(http::service_unavailable); auto response_code = http::code(http::service_unavailable);
http_response.set_body({{"code",response_code.first},{"status", response_code.second}}); http_response.set_body({{"code", response_code.first}, {"status", response_code.second}});
http_response.set_status(response_code.first); http_response.set_status(response_code.first);
} else { } else {
const auto json=util::json::parse(req->content); const auto json = util::json::parse(req->content);
if(json.is_object() && !json.is_null()) { if (json.is_object() && !json.is_null()) {
if(util::json::get("paused",json,session.is_paused())) if (util::json::get("paused", json, session.is_paused()))
session.pause(); session.pause();
else else
session.resume(); session.resume();
auto settings = session.get_settings(); auto settings = session.get_settings();
const auto new_listen_port=util::json::get("port",json,session.listen_port()); const auto new_listen_port = util::json::get("port", json, session.listen_port());
if(new_listen_port!=session.listen_port()) if (new_listen_port != session.listen_port())
settings.set_str(settings.listen_interfaces,"0.0.0.0:"+std::to_string(new_listen_port)); settings.set_str(settings.listen_interfaces, "0.0.0.0:" + std::to_string(new_listen_port));
const auto new_dht_enabled=util::json::get("dht_enabled",json,session.is_dht_running()); const auto new_dht_enabled = util::json::get("dht_enabled", json, session.is_dht_running());
if(new_dht_enabled!=session.is_dht_running()) if (new_dht_enabled != session.is_dht_running())
settings.set_bool(settings.enable_dht,new_dht_enabled); settings.set_bool(settings.enable_dht, new_dht_enabled);
auto old_limit=settings.get_int(settings.download_rate_limit); auto old_limit = settings.get_int(settings.download_rate_limit);
auto new_limit=util::json::get("down_limit",json,old_limit); auto new_limit = util::json::get("down_limit", json, old_limit);
if(new_limit!=old_limit) if (new_limit != old_limit)
settings.set_int(settings.download_rate_limit,new_limit); settings.set_int(settings.download_rate_limit, new_limit);
old_limit=settings.get_int(settings.upload_rate_limit); old_limit = settings.get_int(settings.upload_rate_limit);
new_limit=util::json::get("up_limit",json,old_limit); new_limit = util::json::get("up_limit", json, old_limit);
if(new_limit!=old_limit) if (new_limit != old_limit)
settings.set_int(settings.upload_rate_limit,new_limit); settings.set_int(settings.upload_rate_limit, new_limit);
session.apply_settings(settings); session.apply_settings(settings);
auto response_code = http::code(http::accepted); auto response_code = http::code(http::accepted);
http_response.set_body({{"code",response_code.first},{"status", response_code.second}}); http_response.set_body({{"code", response_code.first}, {"status", response_code.second}});
http_response.set_status(response_code.first); http_response.set_status(response_code.first);
} else { } else {
auto response_code = http::code(http::bad_request); auto response_code = http::code(http::bad_request);
http_response.set_body({{"code",response_code.first},{"status", response_code.second}}); http_response.set_body({{"code", response_code.first}, {"status", response_code.second}});
http_response.set_status(response_code.first); http_response.set_status(response_code.first);
} }
} }
*resp << http_response; *resp << http_response;
}
}
} }
}
}
#endif

80
toREST/include/util.hpp

@ -1,84 +1,82 @@
#ifndef _BT_HELPERS_HPP_ #ifndef _TR_UTIL_HPP_
#define _BT_HELPERS_HPP_ #define _TR_UTIL_HPP_
#include <unordered_map>
#include <boost/regex.hpp> #include <boost/regex.hpp>
#include <json.hpp> #include <json.hpp>
#include <unordered_map>
namespace util { namespace util {
class uri { class uri {
public: public:
auto static parse(const std::string &request_path){ auto static parse(const std::string &request_path) {
std::unordered_map<std::string,std::string> options; std::unordered_map<std::string, std::string> options;
std::string option, value; std::string option, value;
bool collect=false; bool collect = false;
for(auto &c:request_path){ for (auto &c : request_path) {
switch(c){ switch (c) {
case '&': case '&':
options.insert(std::make_pair(option,value)); options.insert(std::make_pair(option, value));
option=""; option = "";
collect=true; collect = true;
break; break;
case '?': case '?':
collect=true; collect = true;
break; break;
case '=': case '=':
collect=false; collect = false;
value=""; value = "";
break; break;
default: default:
if(collect) if (collect)
option+=c; option += c;
else else
value+=c; value += c;
break; break;
} }
} }
if(!option.empty() || !value.empty()) if (!option.empty() || !value.empty())
options.insert(std::make_pair(option,value)); options.insert(std::make_pair(option, value));
return options; return options;
} }
}; };
const boost::regex regex("@(https?|ftp)://(-\\.)?([^\\s/?\\.#-]+\\.?)+(/[^\\s]*)?$@", boost::regex_constants::perl | boost::regex_constants::icase); const boost::regex regex("@(https?|ftp)://(-\\.)?([^\\s/?\\.#-]+\\.?)+(/[^\\s]*)?$@", boost::regex_constants::perl | boost::regex_constants::icase);
class json { class json {
public: public:
/*! @brief Wrapper for nlohmann::json::parse. If the parse fails, result.is_null() will be */ /*! @brief Wrapper for nlohmann::json::parse. If the parse fails, result.is_null() will be */
static nlohmann::json parse(std::istream &istream) { static nlohmann::json parse(std::istream &istream) {
try { try {
return nlohmann::json::parse(istream); return nlohmann::json::parse(istream);
} catch(const std::invalid_argument &exp) { } catch (const std::invalid_argument &exp) {
} }
return nlohmann::json(nullptr); return nlohmann::json(nullptr);
} }
/*! @brief wrapper around nlohmann::json::parse, but object returns null on throw */ /*! @brief wrapper around nlohmann::json::parse, but object returns null on throw */
static nlohmann::json parse(const std::string &string){ static nlohmann::json parse(const std::string &string) {
try { try {
return nlohmann::json::parse(string); return nlohmann::json::parse(string);
} catch(const std::invalid_argument &exp) { } catch (const std::invalid_argument &exp) {
} }
return nlohmann::json(nullptr); return nlohmann::json(nullptr);
} }
static bool has_property(const std::string &key, const nlohmann::json &object){ static bool has_property(const std::string &key, const nlohmann::json &object) {
auto it=object.find(key); auto it = object.find(key);
return it!=object.end(); return it != object.end();
} }
template<class T> template <class T>
static auto get(const std::string &key, const nlohmann::json &object, const T &default_value){ static auto get(const std::string &key, const nlohmann::json &object, const T &default_value) {
if(has_property(key,object)){ if (has_property(key, object)) {
T r; T r;
try{ try {
r=object[key]; //TODO fix use json parser where a non-throwable exist r = object[key]; //TODO fix use json parser where a non-throwable exist
} catch(const std::exception&){ } catch (const std::exception &) {
return default_value; return default_value;
} }
return r; return r;
} }
return default_value; return default_value;
} }
}; };
} }
#endif // _BT_HELPERS_HPP_ #endif

93
toREST/src/http.cpp

@ -1,40 +1,17 @@
#include <http.hpp> #include <http.hpp>
http::code::code(status status):first(status){
switch(status) {
case accepted: second="Accepted"; break;
case bad_gateway: second="Bad Gateway"; break;
case bad_request: second="Bad Request"; break;
case created: second="Created"; break;
case forbidden: second="Forbidden"; break;
case gateway_timeout: second="Gateway Timeout"; break;
case http_version_not_supported: second="HTTP Version Not Supported"; break;
case internal_server_error: second="Internal Server Error"; break;
case method_not_allowed: second="Method Not Allowed"; break;
case not_acceptable: second="Not Acceptable"; break;
case no_content: second="No Content"; break;
case not_found: second="Not Found"; break;
case not_implemented: second="Not Implemented"; break;
case ok: second="OK"; break;
case payment_required: second="Payment Required"; break;
case service_unavailable: second="Service Unavailable"; break;
case unauthorized: second="Unauthorized"; break;
default: second="UNKNOWN";
}
}
std::ostream &http::response::do_response(std::ostream &os) const { std::ostream &http::response::do_response(std::ostream &os) const {
os << "HTTP/1.1" os << "HTTP/1.1"
<< " " << status_code.first << " " << status_code.second << "\r\n"; << " " << status_code.first << " " << status_code.second << "\r\n";
for(auto &header : response_headers) for (auto &header : response_headers)
os << header.first << ": " << header.second << "\r\n"; os << header.first << ": " << header.second << "\r\n";
if(status_code.first != http::no_content) { if (status_code.first != http::no_content) {
os << "Content-Length: "; os << "Content-Length: ";
if(!body.empty()) { if (!body.empty()) {
return os << body.size() << "\r\n\r\n" return os << body.size() << "\r\n\r\n"
<< body; << body;
} else { } else {
const 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" return os << body_replace.size() << "\r\n\r\n"
<< body_replace; << body_replace;
} }
@ -42,7 +19,65 @@ std::ostream &http::response::do_response(std::ostream &os) const {
return os << "\r\n"; return os << "\r\n";
} }
void http::response::set_body(const nlohmann::json &json){ void http::response::set_body(const nlohmann::json &json) {
add_header({"Content-Type","application/json"}); add_header({"Content-Type", "application/json"});
response::set_body(json.dump()); response::set_body(json.dump());
} }
http::code::code(status status) : first(status) {
switch (status) {
case accepted:
second = "Accepted";
break;
case bad_gateway:
second = "Bad Gateway";
break;
case bad_request:
second = "Bad Request";
break;
case created:
second = "Created";
break;
case forbidden:
second = "Forbidden";
break;
case gateway_timeout:
second = "Gateway Timeout";
break;
case http_version_not_supported:
second = "HTTP Version Not Supported";
break;
case internal_server_error:
second = "Internal Server Error";
break;
case method_not_allowed:
second = "Method Not Allowed";
break;
case not_acceptable:
second = "Not Acceptable";
break;
case no_content:
second = "No Content";
break;
case not_found:
second = "Not Found";
break;
case not_implemented:
second = "Not Implemented";
break;
case ok:
second = "OK";
break;
case payment_required:
second = "Payment Required";
break;
case service_unavailable:
second = "Service Unavailable";
break;
case unauthorized:
second = "Unauthorized";
break;
default:
second = "UNKNOWN";
}
}

1
toREST/tests/include/ConfigContext.hpp

@ -3,5 +3,4 @@
#include <config.hpp> #include <config.hpp>
#endif #endif

7
toREST/tests/include/ServerContext.hpp

@ -1,9 +1,10 @@
#ifndef _TR_TEST_SERVER_CONTEXT_HPP_ #ifndef _TR_TEST_SERVER_CONTEXT_HPP_
#define _TR_TEST_SERVER_CONTEXT_HPP_ #define _TR_TEST_SERVER_CONTEXT_HPP_
#include <Catch/fakeit.hpp> #include <Catch/fakeit.hpp>
#include <json.hpp> #include <json.hpp>
#include <unordered_map>
#include <sstream> #include <sstream>
#include <unordered_map>
class TestRequest { class TestRequest {
public: public:
@ -13,12 +14,12 @@ public:
class TestResponse : public std::stringstream { class TestResponse : public std::stringstream {
public: public:
std::string buffer; std::string buffer;
std::unordered_map<std::string,std::string> headers_; std::unordered_map<std::string, std::string> headers_;
std::string string(); std::string string();
std::string message(); std::string message();
std::string code(); std::string code();
std::string content(); std::string content();
const std::unordered_map<std::string,std::string>& headers(); const std::unordered_map<std::string, std::string> &headers();
}; };
class CommonResponse { class CommonResponse {

2
toREST/tests/include/TorrentContext.hpp

@ -1,8 +1,8 @@
#ifndef _TR_TEST_TORRENT_CONTEXT_HPP_ #ifndef _TR_TEST_TORRENT_CONTEXT_HPP_
#define _TR_TEST_TORRENT_CONTEXT_HPP_ #define _TR_TEST_TORRENT_CONTEXT_HPP_
#include <string>
#include <libtorrent/magnet_uri.hpp> #include <libtorrent/magnet_uri.hpp>
#include <string>
class TorrentStatus { class TorrentStatus {
public: public:

Loading…
Cancel
Save