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_
#define _TOREST_HTTP_HPP_
#ifndef _TR_HTTP_HPP_
#define _TR_HTTP_HPP_
#include <json.hpp>
#include <unordered_map>
namespace http {
/// http codes
enum status {
/*! 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 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 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,
/*! 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 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,
/*! 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,
/*! 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 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,
/*! http-version not supported */ http_version_not_supported=505
};
typedef std::pair<std::string,std::string> header;
typedef std::unordered_map<std::string,std::string> headers;
/// http codes
enum status {
/*! 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 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 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,
/*! 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 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,
/*! 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,
/*! 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 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,
/*! http-version not supported */ http_version_not_supported = 505
};
typedef std::pair<std::string, std::string> header;
typedef std::unordered_map<std::string, std::string> headers;
/// creates a http::code object out of a http::status code
class code {
public:
/// creates a http::code object out of a http::status code
class code {
public:
code(status status);
public:
public:
status first;
std::string second;
};
};
class response {
public:
friend std::ostream& operator<<(std::ostream& os,const response &rh){ return rh.do_response(os); }
response():status_code(http::ok){}
void set_body(const std::string &content) { body=content; }
class response {
public:
friend std::ostream &operator<<(std::ostream &os, const response &rh) { return rh.do_response(os); }
response() : status_code(http::ok) {}
void set_body(const std::string &content) { body = content; }
void set_body(const nlohmann::json &json);
void add_header(const http::header &header) { response_headers.emplace(header); }
void set_status(http::status code) { status_code=code; }
std::ostream& do_response(std::ostream &os) const;
protected:
void set_status(http::status code) { status_code = code; }
std::ostream &do_response(std::ostream &os) const;
protected:
std::string body;
headers response_headers;
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 <util.hpp>
namespace tr{
namespace session {
template<class torrent_session, class request, class response>
void get(torrent_session&session,response resp,request req){
namespace tr {
namespace session {
template <class torrent_session, class request, class response>
void get(torrent_session &session, response resp, request req) {
auto http_response = http::response();
if (session.is_valid()) {
const auto settings = session.get_settings();
http_response.set_body({
{ "paused", session.is_paused() },
{ "port", session.listen_port() },
{ "dht_enabled", session.is_dht_running() },
{ "down_limit", settings.get_int(settings.download_rate_limit) },
{ "up_limit", settings.get_int(settings.upload_rate_limit) },
{ "torrents", session.get_torrents().size() }, //TODO Optimize
// { "default_download_dir", default_download_dir.filename().string() },
// { "root_dir", root_dir.string() },
{"paused", session.is_paused()},
{"port", session.listen_port()},
{"dht_enabled", session.is_dht_running()},
{"down_limit", settings.get_int(settings.download_rate_limit)},
{"up_limit", settings.get_int(settings.upload_rate_limit)},
{"torrents", session.get_torrents().size()}, //TODO Optimize
// { "default_download_dir", default_download_dir.filename().string() },
// { "root_dir", root_dir.string() },
});
} else {
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);
}
*resp << http_response;
}
template<class torrent_session, class request, class response>
void patch(torrent_session&session,response resp,request req){
}
template <class torrent_session, class request, class response>
void patch(torrent_session &session, response resp, request req) {
auto http_response = http::response();
if (!session.is_valid()) {
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);
} else {
const auto json=util::json::parse(req->content);
if(json.is_object() && !json.is_null()) {
if(util::json::get("paused",json,session.is_paused()))
const auto json = util::json::parse(req->content);
if (json.is_object() && !json.is_null()) {
if (util::json::get("paused", json, session.is_paused()))
session.pause();
else
session.resume();
auto settings = session.get_settings();
const auto new_listen_port=util::json::get("port",json,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));
const auto new_dht_enabled=util::json::get("dht_enabled",json,session.is_dht_running());
if(new_dht_enabled!=session.is_dht_running())
settings.set_bool(settings.enable_dht,new_dht_enabled);
auto old_limit=settings.get_int(settings.download_rate_limit);
auto new_limit=util::json::get("down_limit",json,old_limit);
if(new_limit!=old_limit)
settings.set_int(settings.download_rate_limit,new_limit);
old_limit=settings.get_int(settings.upload_rate_limit);
new_limit=util::json::get("up_limit",json,old_limit);
if(new_limit!=old_limit)
settings.set_int(settings.upload_rate_limit,new_limit);
const auto new_listen_port = util::json::get("port", json, 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));
const auto new_dht_enabled = util::json::get("dht_enabled", json, session.is_dht_running());
if (new_dht_enabled != session.is_dht_running())
settings.set_bool(settings.enable_dht, new_dht_enabled);
auto old_limit = settings.get_int(settings.download_rate_limit);
auto new_limit = util::json::get("down_limit", json, old_limit);
if (new_limit != old_limit)
settings.set_int(settings.download_rate_limit, new_limit);
old_limit = settings.get_int(settings.upload_rate_limit);
new_limit = util::json::get("up_limit", json, old_limit);
if (new_limit != old_limit)
settings.set_int(settings.upload_rate_limit, new_limit);
session.apply_settings(settings);
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);
} else {
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);
}
}
*resp << http_response;
}
}
}
}
}
#endif

80
toREST/include/util.hpp

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

93
toREST/src/http.cpp

@ -1,40 +1,17 @@
#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 {
os << "HTTP/1.1"
<< " " << 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";
if(status_code.first != http::no_content) {
if (status_code.first != http::no_content) {
os << "Content-Length: ";
if(!body.empty()) {
if (!body.empty()) {
return os << body.size() << "\r\n\r\n"
<< body;
} 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"
<< body_replace;
}
@ -42,7 +19,65 @@ std::ostream &http::response::do_response(std::ostream &os) const {
return os << "\r\n";
}
void http::response::set_body(const nlohmann::json &json){
add_header({"Content-Type","application/json"});
void http::response::set_body(const nlohmann::json &json) {
add_header({"Content-Type", "application/json"});
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>
#endif

7
toREST/tests/include/ServerContext.hpp

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

2
toREST/tests/include/TorrentContext.hpp

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

Loading…
Cancel
Save