Skip to content
Snippets Groups Projects
Commit bbe922dd authored by Sébastien Blin's avatar Sébastien Blin
Browse files

remove headers, fix HTTP status, fix get /

parent 38ad5b9e
Branches
No related tags found
No related merge requests found
...@@ -26,6 +26,10 @@ ...@@ -26,6 +26,10 @@
#include <memory> #include <memory>
#include <functional> #include <functional>
#if OPENDHT_PROXY_SERVER
#include <json/json.h>
#endif //OPENDHT_PROXY_SERVER
namespace dht { namespace dht {
struct Node; struct Node;
...@@ -47,6 +51,12 @@ struct OPENDHT_PUBLIC NodeStats { ...@@ -47,6 +51,12 @@ struct OPENDHT_PUBLIC NodeStats {
unsigned table_depth; unsigned table_depth;
unsigned getKnownNodes() const { return good_nodes + dubious_nodes; } unsigned getKnownNodes() const { return good_nodes + dubious_nodes; }
std::string toString() const; std::string toString() const;
#if OPENDHT_PROXY_SERVER
/**
* Build a json object from a NodeStats
*/
Json::Value toJson() const;
#endif //OPENDHT_PROXY_SERVER
}; };
/** /**
......
...@@ -31,7 +31,6 @@ ...@@ -31,7 +31,6 @@
namespace dht { namespace dht {
class DhtRunner; class DhtRunner;
class InfoHash;
/** /**
* Describes the REST API * Describes the REST API
...@@ -64,7 +63,7 @@ private: ...@@ -64,7 +63,7 @@ private:
* Return the PublicKey id, the node id and node stats * Return the PublicKey id, the node id and node stats
* Method: GET "/" * Method: GET "/"
* Result: HTTP 200, body: Value in JSON format (one part = one value) * Result: HTTP 200, body: Value in JSON format (one part = one value)
* On error: HTTP 404, body: {"err":"xxxx"} * On error: HTTP 503, body: {"err":"xxxx"}
* @param session * @param session
*/ */
void getNodeInfo(const std::shared_ptr<restbed::Session>& session) const; void getNodeInfo(const std::shared_ptr<restbed::Session>& session) const;
...@@ -72,12 +71,11 @@ private: ...@@ -72,12 +71,11 @@ private:
/** /**
* Return Values of a InfoHash * Return Values of a InfoHash
* Method: GET "/{InfoHash: .*}" * Method: GET "/{InfoHash: .*}"
* Return: Multiple JSON object in parts. For 2 values, you will have 3 parts: * Return: Multiple JSON object in parts. Example:
* Value in JSON format (HTTP/1.1 200 OK Content-Type: application/json) * Value in JSON format\n
* Value in JSON format (HTTP/1.1 200 OK Content-Type: application/json) * Value in JSON format
* {"ok": 1}
* *
* On error: HTTP 404, body: {"err":"xxxx"} * On error: HTTP 503, body: {"err":"xxxx"}
* @param session * @param session
*/ */
void get(const std::shared_ptr<restbed::Session>& session) const; void get(const std::shared_ptr<restbed::Session>& session) const;
...@@ -85,11 +83,11 @@ private: ...@@ -85,11 +83,11 @@ private:
/** /**
* Listen incoming Values of a InfoHash. * Listen incoming Values of a InfoHash.
* Method: LISTEN "/{InfoHash: .*}" * Method: LISTEN "/{InfoHash: .*}"
* Return: Multiple JSON object in parts. For 2 values, you will have 2 parts: * Return: Multiple JSON object in parts. Example:
* Value in JSON format (HTTP/1.1 200 OK Content-Type: application/json) * Value in JSON format\n
* Value in JSON format (HTTP/1.1 200 OK Content-Type: application/json) * Value in JSON format
* *
* On error: HTTP 404, body: {"err":"xxxx"} * On error: HTTP 503, body: {"err":"xxxx"}
* @param session * @param session
*/ */
void listen(const std::shared_ptr<restbed::Session>& session) const; void listen(const std::shared_ptr<restbed::Session>& session) const;
...@@ -98,8 +96,8 @@ private: ...@@ -98,8 +96,8 @@ private:
* Put a value on the DHT * Put a value on the DHT
* Method: POST "/{InfoHash: .*}" * Method: POST "/{InfoHash: .*}"
* body = Value to put in JSON * body = Value to put in JSON
* Return: {"ok":"1"} * Return: HTTP 200 if success and the value put in JSON
* On error: HTTP 404, body: {"err":"xxxx"} if no dht * On error: HTTP 503, body: {"err":"xxxx"} if no dht
* HTTP 400, body: {"err":"xxxx"} if bad json * HTTP 400, body: {"err":"xxxx"} if bad json
* @param session * @param session
*/ */
...@@ -110,8 +108,8 @@ private: ...@@ -110,8 +108,8 @@ private:
* Put a value to sign by the proxy on the DHT * Put a value to sign by the proxy on the DHT
* Method: SIGN "/{InfoHash: .*}" * Method: SIGN "/{InfoHash: .*}"
* body = Value to put in JSON * body = Value to put in JSON
* Return: {"ok":"1"} * Return: HTTP 200 if success and the value put in JSON
* On error: HTTP 404, body: {"err":"xxxx"} if no dht * On error: HTTP 503, body: {"err":"xxxx"} if no dht
* HTTP 400, body: {"err":"xxxx"} if bad json * HTTP 400, body: {"err":"xxxx"} if bad json
* @param session * @param session
*/ */
...@@ -121,8 +119,8 @@ private: ...@@ -121,8 +119,8 @@ private:
* Put a value to encrypt by the proxy on the DHT * Put a value to encrypt by the proxy on the DHT
* Method: ENCRYPT "/{hash: .*}" * Method: ENCRYPT "/{hash: .*}"
* body = Value to put in JSON + "to":"infoHash" * body = Value to put in JSON + "to":"infoHash"
* Return: {"ok":"1"} * Return: HTTP 200 if success and the value put in JSON
* On error: HTTP 404, body: {"err":"xxxx"} if no dht * On error: HTTP 503, body: {"err":"xxxx"} if no dht
* HTTP 400, body: {"err":"xxxx"} if bad json * HTTP 400, body: {"err":"xxxx"} if bad json
* @param session * @param session
*/ */
...@@ -132,12 +130,11 @@ private: ...@@ -132,12 +130,11 @@ private:
/** /**
* Return Values of a InfoHash filtered by a value id * Return Values of a InfoHash filtered by a value id
* Method: GET "/{InfoHash: .*}/{ValueId: .*}" * Method: GET "/{InfoHash: .*}/{ValueId: .*}"
* Return: Multiple JSON object in parts. For 2 values, you will have 3 parts: * Return: Multiple JSON object in parts. Example:
* Value in JSON format (HTTP/1.1 200 OK Content-Type: application/json) * Value in JSON format\n
* Value in JSON format (HTTP/1.1 200 OK Content-Type: application/json) * Value in JSON format
* {"ok": 1}
* *
* On error: HTTP 404, body: {"err":"xxxx"} * On error: HTTP 503, body: {"err":"xxxx"}
* @param session * @param session
*/ */
void getFiltered(const std::shared_ptr<restbed::Session>& session) const; void getFiltered(const std::shared_ptr<restbed::Session>& session) const;
......
...@@ -68,4 +68,24 @@ NodeStats::toString() const ...@@ -68,4 +68,24 @@ NodeStats::toString() const
return ss.str(); return ss.str();
} }
#if OPENDHT_PROXY_SERVER
/**
* Build a json object from a NodeStats
*/
Json::Value
NodeStats::toJson() const
{
Json::Value val;
val["good"] = static_cast<Json::LargestUInt>(good_nodes);
val["dubious"] = static_cast<Json::LargestUInt>(dubious_nodes);
val["incoming"] = static_cast<Json::LargestUInt>(incoming_nodes);
if (table_depth > 1) {
val["table_depth"] = static_cast<Json::LargestUInt>(table_depth);
unsigned long tot_nodes = 8 * std::exp2(table_depth);
val["network_size_estimation"] = static_cast<Json::LargestUInt>(tot_nodes);
}
return val;
}
#endif //OPENDHT_PROXY_SERVER
} }
...@@ -19,13 +19,12 @@ ...@@ -19,13 +19,12 @@
#if OPENDHT_PROXY_SERVER #if OPENDHT_PROXY_SERVER
#include "dht_proxy_server.h" #include "dht_proxy_server.h"
#include <chrono>
#include <functional>
#include "default_types.h" #include "default_types.h"
#include "dhtrunner.h" #include "dhtrunner.h"
#include "msgpack.hpp" #include "msgpack.hpp"
#include <chrono>
#include <functional>
#include <json/json.h> #include <json/json.h>
#include <limits> #include <limits>
...@@ -96,13 +95,14 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port) ...@@ -96,13 +95,14 @@ DhtProxyServer::DhtProxyServer(std::shared_ptr<DhtRunner> dht, in_port_t port)
// Start server // Start server
auto settings = std::make_shared<restbed::Settings>(); auto settings = std::make_shared<restbed::Settings>();
settings->set_default_header("Content-Type", "application/json"); settings->set_default_header("Content-Type", "application/json");
settings->set_default_header("Connection", "keep-alive");
std::chrono::milliseconds timeout(std::numeric_limits<int>::max()); std::chrono::milliseconds timeout(std::numeric_limits<int>::max());
settings->set_connection_timeout(timeout); // there is a timeout, but really huge settings->set_connection_timeout(timeout); // there is a timeout, but really huge
settings->set_port(port); settings->set_port(port);
try { try {
service_->start(settings); service_->start(settings);
} catch(std::system_error& e) { } catch(std::system_error& e) {
// Fail silently for now. std::cerr << "Error running server on port " << port << ": " << e.what() << std::endl;
} }
}); });
...@@ -150,20 +150,21 @@ DhtProxyServer::getNodeInfo(const std::shared_ptr<restbed::Session>& session) co ...@@ -150,20 +150,21 @@ DhtProxyServer::getNodeInfo(const std::shared_ptr<restbed::Session>& session) co
const auto request = session->get_request(); const auto request = session->get_request();
int content_length = std::stoi(request->get_header("Content-Length", "0")); int content_length = std::stoi(request->get_header("Content-Length", "0"));
session->fetch(content_length, session->fetch(content_length,
[=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& b) [=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& /*b*/)
{ {
(void)b;
if (dht_) { if (dht_) {
Json::Value result; Json::Value result;
result["id"] = dht_->getId().toString(); auto id = dht_->getId();
if (id)
result["id"] = id.toString();
result["node_id"] = dht_->getNodeId().toString(); result["node_id"] = dht_->getNodeId().toString();
result["ipv4"] = dht_->getNodesStats(AF_INET).toString(); result["ipv4"] = dht_->getNodesStats(AF_INET).toJson();
result["ipv6"] = dht_->getNodesStats(AF_INET6).toString(); result["ipv6"] = dht_->getNodesStats(AF_INET6).toJson();
Json::FastWriter writer; Json::FastWriter writer;
s->close(restbed::OK, writer.write(result)); s->close(restbed::OK, writer.write(result));
} }
else else
s->close(restbed::NOT_FOUND, "{\"err\":\"Incorrect DhtRunner\"}"); s->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
} }
); );
} }
...@@ -175,35 +176,36 @@ DhtProxyServer::get(const std::shared_ptr<restbed::Session>& session) const ...@@ -175,35 +176,36 @@ DhtProxyServer::get(const std::shared_ptr<restbed::Session>& session) const
int content_length = std::stoi(request->get_header("Content-Length", "0")); int content_length = std::stoi(request->get_header("Content-Length", "0"));
auto hash = request->get_path_parameter("hash"); auto hash = request->get_path_parameter("hash");
session->fetch(content_length, session->fetch(content_length,
[=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& b) [=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& /*b* */)
{ {
(void)b;
if (dht_) { if (dht_) {
InfoHash infoHash(hash); InfoHash infoHash(hash);
if (!infoHash) { if (!infoHash) {
infoHash = InfoHash::get(hash); infoHash = InfoHash::get(hash);
} }
Json::FastWriter writer; s->yield(restbed::OK, "", [=]( const std::shared_ptr< restbed::Session > s) {
dht_->get(infoHash, [s, &writer](std::shared_ptr<Value> value) { dht_->get(infoHash, [s](std::shared_ptr<Value> value) {
// Send values as soon as we get them // Send values as soon as we get them
Json::Value result; Json::FastWriter writer;
s->yield(restbed::OK, writer.write(value->toJson())); s->yield(writer.write(value->toJson()), [](const std::shared_ptr<restbed::Session> /*session*/){ });
return true; return true;
}, [s, &writer](bool ok) { }, [s](bool /*ok* */) {
// Communication is finished // Communication is finished
auto response = std::to_string(ok); s->close();
s->close(restbed::OK, "{\"ok\": " + response + "}"); });
}); });
} else { } else {
s->close(restbed::NOT_FOUND, "{\"err\":\"Incorrect DhtRunner\"}"); s->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
} }
} }
); );
} }
void void
DhtProxyServer::listen(const std::shared_ptr<restbed::Session>& session) const DhtProxyServer::listen(const std::shared_ptr<restbed::Session>& session) const
{ {
const auto request = session->get_request(); const auto request = session->get_request();
int content_length = std::stoi(request->get_header("Content-Length", "0")); int content_length = std::stoi(request->get_header("Content-Length", "0"));
auto hash = request->get_path_parameter("hash"); auto hash = request->get_path_parameter("hash");
...@@ -211,16 +213,20 @@ DhtProxyServer::listen(const std::shared_ptr<restbed::Session>& session) const ...@@ -211,16 +213,20 @@ DhtProxyServer::listen(const std::shared_ptr<restbed::Session>& session) const
if (!infoHash) if (!infoHash)
infoHash = InfoHash::get(hash); infoHash = InfoHash::get(hash);
session->fetch(content_length, session->fetch(content_length,
[=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& b) [=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& /*b* */)
{ {
(void)b;
if (dht_) { if (dht_) {
s->yield(restbed::OK, ""); // Open the connection InfoHash infoHash(hash);
Json::FastWriter writer; if (!infoHash) {
size_t token = dht_->listen(infoHash, [s, &writer](std::shared_ptr<Value> value) { infoHash = InfoHash::get(hash);
}
s->yield(restbed::OK, "", [=]( const std::shared_ptr< restbed::Session > s) {
size_t token = dht_->listen(infoHash, [s](std::shared_ptr<Value> value) {
// Send values as soon as we get them // Send values as soon as we get them
if (!s->is_closed()) if (!s->is_closed()) {
s->yield(restbed::OK, writer.write(value->toJson())); Json::FastWriter writer;
s->yield(writer.write(value->toJson()), [](const std::shared_ptr<restbed::Session> /*session*/){ });
}
return !s->is_closed(); return !s->is_closed();
}).get(); }).get();
// Handle client deconnection // Handle client deconnection
...@@ -231,8 +237,9 @@ DhtProxyServer::listen(const std::shared_ptr<restbed::Session>& session) const ...@@ -231,8 +237,9 @@ DhtProxyServer::listen(const std::shared_ptr<restbed::Session>& session) const
listener.hash = infoHash; listener.hash = infoHash;
listener.token = token; listener.token = token;
currentListeners_.emplace_back(listener); currentListeners_.emplace_back(listener);
});
} else { } else {
s->close(restbed::NOT_FOUND, "{\"err\":\"Incorrect DhtRunner\"}"); s->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
} }
} }
); );
...@@ -267,15 +274,15 @@ DhtProxyServer::put(const std::shared_ptr<restbed::Session>& session) const ...@@ -267,15 +274,15 @@ DhtProxyServer::put(const std::shared_ptr<restbed::Session>& session) const
// Build the Value from json // Build the Value from json
auto value = std::make_shared<Value>(root); auto value = std::make_shared<Value>(root);
auto response = value->toString(); Json::FastWriter writer;
dht_->put(infoHash, value); dht_->put(infoHash, value);
s->close(restbed::OK, response); s->close(restbed::OK, writer.write(value->toJson()));
} else { } else {
s->close(restbed::BAD_REQUEST, "Incorrect JSON"); s->close(restbed::BAD_REQUEST, "Incorrect JSON");
} }
} }
} else { } else {
s->close(restbed::NOT_FOUND, ""); s->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
} }
} }
); );
...@@ -308,15 +315,15 @@ DhtProxyServer::putSigned(const std::shared_ptr<restbed::Session>& session) cons ...@@ -308,15 +315,15 @@ DhtProxyServer::putSigned(const std::shared_ptr<restbed::Session>& session) cons
if (parsingSuccessful) { if (parsingSuccessful) {
auto value = std::make_shared<Value>(root); auto value = std::make_shared<Value>(root);
auto response = value->toString(); Json::FastWriter writer;
dht_->putSigned(infoHash, value); dht_->putSigned(infoHash, value);
s->close(restbed::OK, response); s->close(restbed::OK, writer.write(value->toJson()));
} else { } else {
s->close(restbed::BAD_REQUEST, "Incorrect JSON" + strJson); s->close(restbed::BAD_REQUEST, "Incorrect JSON" + strJson);
} }
} }
} else { } else {
s->close(restbed::NOT_FOUND, ""); s->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
} }
} }
); );
...@@ -353,9 +360,9 @@ DhtProxyServer::putEncrypted(const std::shared_ptr<restbed::Session>& session) c ...@@ -353,9 +360,9 @@ DhtProxyServer::putEncrypted(const std::shared_ptr<restbed::Session>& session) c
if (toinfoHash) if (toinfoHash)
toInfoHash = InfoHash::get(toHash); toInfoHash = InfoHash::get(toHash);
auto response = value->toString(); Json::FastWriter writer;
dht_->putEncrypted(infoHash, toInfoHash, value); dht_->putEncrypted(infoHash, toInfoHash, value);
s->close(restbed::OK, response); s->close(restbed::OK, writer.write(value->toJson()));
} else { } else {
if(!parsingSuccessful) if(!parsingSuccessful)
s->close(restbed::BAD_REQUEST, "Incorrect JSON"); s->close(restbed::BAD_REQUEST, "Incorrect JSON");
...@@ -364,7 +371,7 @@ DhtProxyServer::putEncrypted(const std::shared_ptr<restbed::Session>& session) c ...@@ -364,7 +371,7 @@ DhtProxyServer::putEncrypted(const std::shared_ptr<restbed::Session>& session) c
} }
} }
} else { } else {
s->close(restbed::NOT_FOUND, ""); s->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
} }
} }
); );
...@@ -379,25 +386,26 @@ DhtProxyServer::getFiltered(const std::shared_ptr<restbed::Session>& session) co ...@@ -379,25 +386,26 @@ DhtProxyServer::getFiltered(const std::shared_ptr<restbed::Session>& session) co
auto hash = request->get_path_parameter("hash"); auto hash = request->get_path_parameter("hash");
auto value = request->get_path_parameter("value"); auto value = request->get_path_parameter("value");
session->fetch(content_length, session->fetch(content_length,
[=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& b) [=](const std::shared_ptr<restbed::Session> s, const restbed::Bytes& /*b* */)
{ {
(void)b;
if (dht_) { if (dht_) {
InfoHash infoHash(hash); InfoHash infoHash(hash);
if (!infoHash) { if (!infoHash) {
infoHash = InfoHash::get(hash); infoHash = InfoHash::get(hash);
} }
s->yield(restbed::OK, "", [=]( const std::shared_ptr< restbed::Session > s) {
dht_->get(infoHash, [s](std::shared_ptr<Value> v) {
// Send values as soon as we get them
Json::FastWriter writer; Json::FastWriter writer;
dht_->get(infoHash, [s, &writer](std::shared_ptr<Value> value) { s->yield(writer.write(v->toJson()), [](const std::shared_ptr<restbed::Session> /*session*/){ });
Json::Value result;
s->yield(restbed::OK, writer.write(value->toJson()));
return true; return true;
}, [s, &writer](bool ok) { }, [s](bool /*ok* */) {
auto response = std::to_string(ok); // Communication is finished
s->close(restbed::OK, "{\"ok\": " + response + "}"); s->close();
}, {}, value); }, {}, value);
});
} else { } else {
s->close(restbed::NOT_FOUND, "{\"err\":\"Incorrect DhtRunner\"}"); s->close(restbed::SERVICE_UNAVAILABLE, "{\"err\":\"Incorrect DhtRunner\"}");
} }
} }
); );
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment