mirror of
https://git.rwth-aachen.de/acs/public/villas/node/
synced 2025-03-09 00:00:00 +01:00
api: refactoring to fix undefined behavior
This commit is contained in:
parent
e59cd8ac15
commit
770e9c2f2c
21 changed files with 86 additions and 82 deletions
|
@ -32,11 +32,6 @@ namespace villas {
|
|||
namespace node {
|
||||
namespace api {
|
||||
|
||||
/* Forward declarations */
|
||||
class Session;
|
||||
class Response;
|
||||
class RequestFactory;
|
||||
|
||||
class NodeRequest : public Request {
|
||||
|
||||
public:
|
||||
|
|
|
@ -32,11 +32,6 @@ namespace villas {
|
|||
namespace node {
|
||||
namespace api {
|
||||
|
||||
/* Forward declarations */
|
||||
class Session;
|
||||
class Response;
|
||||
class RequestFactory;
|
||||
|
||||
class PathRequest : public Request {
|
||||
|
||||
public:
|
||||
|
|
|
@ -53,28 +53,18 @@ protected:
|
|||
Logger logger;
|
||||
|
||||
public:
|
||||
std::string uri;
|
||||
std::smatch matches;
|
||||
Session::Method method;
|
||||
json_t *body;
|
||||
|
||||
RequestFactory *factory;
|
||||
|
||||
enum Method {
|
||||
UNKNOWN,
|
||||
GET,
|
||||
POST,
|
||||
DELETE,
|
||||
OPTIONS,
|
||||
PUT,
|
||||
PATCH
|
||||
} method;
|
||||
|
||||
Request(Session *s) :
|
||||
session(s),
|
||||
logger(logging.get("api:request")),
|
||||
method(Session::Method::UNKNOWN),
|
||||
body(nullptr),
|
||||
factory(nullptr),
|
||||
method(Method::UNKNOWN)
|
||||
factory(nullptr)
|
||||
{ }
|
||||
|
||||
virtual ~Request()
|
||||
|
@ -106,7 +96,7 @@ public:
|
|||
make(Session *s) = 0;
|
||||
|
||||
static Request *
|
||||
make(Session *s, const std::string &uri, Request::Method meth);
|
||||
create(Session *s);
|
||||
};
|
||||
|
||||
template<typename T, const char *name, const char *re, const char *desc>
|
||||
|
|
|
@ -60,10 +60,24 @@ public:
|
|||
VERSION_2 = 2
|
||||
};
|
||||
|
||||
enum Method {
|
||||
UNKNOWN,
|
||||
GET,
|
||||
POST,
|
||||
DELETE,
|
||||
OPTIONS,
|
||||
PUT,
|
||||
PATCH
|
||||
};
|
||||
|
||||
protected:
|
||||
enum State state;
|
||||
enum Version version;
|
||||
|
||||
std::string uri;
|
||||
Method method;
|
||||
unsigned long contentLength;
|
||||
|
||||
lws *wsi;
|
||||
|
||||
Web *web;
|
||||
|
@ -97,11 +111,14 @@ public:
|
|||
void execute();
|
||||
void shutdown();
|
||||
|
||||
static int protocolCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
static int
|
||||
protocolCallback(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len);
|
||||
|
||||
int getRequestMethod(struct lws *wsi);
|
||||
Method getRequestMethod() const;
|
||||
std::string getRequestURI() const;
|
||||
|
||||
static std::string methodToString(int meth);
|
||||
static std::string
|
||||
methodToString(Method meth);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -34,10 +34,9 @@ using namespace villas::node;
|
|||
using namespace villas::node::api;
|
||||
|
||||
InvalidMethod::InvalidMethod(Request *req) :
|
||||
BadRequest(
|
||||
fmt::format("The '{}' API endpoint does not support {} requests",
|
||||
req->factory->getName(), Session::methodToString(req->method)
|
||||
)
|
||||
BadRequest("The '{}' API endpoint does not support {} requests",
|
||||
req->factory->getName(),
|
||||
Session::methodToString(req->method)
|
||||
)
|
||||
{ }
|
||||
|
||||
|
|
|
@ -28,8 +28,11 @@
|
|||
using namespace villas;
|
||||
using namespace villas::node::api;
|
||||
|
||||
Request * RequestFactory::make(Session *s, const std::string &uri, Request::Method meth)
|
||||
Request * RequestFactory::create(Session *s)
|
||||
{
|
||||
auto uri = s->getRequestURI();
|
||||
auto meth = s->getRequestMethod();
|
||||
|
||||
for (auto *rf : plugin::Registry::lookup<RequestFactory>()) {
|
||||
std::smatch mr;
|
||||
if (not rf->match(uri, mr))
|
||||
|
@ -40,13 +43,12 @@ Request * RequestFactory::make(Session *s, const std::string &uri, Request::Meth
|
|||
p->matches = mr;
|
||||
p->factory = rf;
|
||||
p->method = meth;
|
||||
p->uri = uri;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
throw BadRequest("Unknown API request", "{ s: s, s: i }",
|
||||
throw BadRequest("Unknown API request", "{ s: s, s: s }",
|
||||
"uri", uri.c_str(),
|
||||
"method", meth
|
||||
"method", Session::methodToString(meth).c_str()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
json_t *json_formats = json_array();
|
||||
json_t *json_name;
|
||||
|
||||
if (method != Method::GET)
|
||||
if (method != Session::Method::GET)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -38,7 +38,7 @@ public:
|
|||
{
|
||||
json_t *cfg = session->getSuperNode()->getConfig();
|
||||
|
||||
if (method != Method::GET)
|
||||
if (method != Session::Method::GET)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::POST)
|
||||
if (method != Session::Method::POST)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -39,7 +39,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::GET && method != Method::POST)
|
||||
if (method != Session::Method::GET && method != Session::Method::POST)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::GET)
|
||||
if (method != Session::Method::GET)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::GET)
|
||||
if (method != Session::Method::GET)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::POST)
|
||||
if (method != Session::Method::POST)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::GET)
|
||||
if (method != Session::Method::GET)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::POST)
|
||||
if (method != Session::Method::POST)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::GET)
|
||||
if (method != Session::Method::GET)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::GET)
|
||||
if (method != Session::Method::GET)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -63,7 +63,7 @@ public:
|
|||
int ret;
|
||||
json_error_t err;
|
||||
|
||||
if (method != Method::POST)
|
||||
if (method != Session::Method::POST)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
const char *cfg = nullptr;
|
||||
|
|
|
@ -37,7 +37,7 @@ public:
|
|||
|
||||
virtual Response * execute()
|
||||
{
|
||||
if (method != Method::POST)
|
||||
if (method != Session::Method::POST)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -42,7 +42,7 @@ public:
|
|||
struct lws_context *ctx = lws_get_context(s->wsi);
|
||||
char buf[4096];
|
||||
|
||||
if (method != Method::GET)
|
||||
if (method != Session::Method::GET)
|
||||
throw InvalidMethod(this);
|
||||
|
||||
if (body != nullptr)
|
||||
|
|
|
@ -37,6 +37,9 @@ using namespace villas::node;
|
|||
using namespace villas::node::api;
|
||||
|
||||
Session::Session(lws *w) :
|
||||
uri(),
|
||||
method(Method::UNKNOWN),
|
||||
contentLength(0),
|
||||
wsi(w),
|
||||
logger(logging.get("api:session"))
|
||||
{
|
||||
|
@ -73,21 +76,21 @@ void Session::execute()
|
|||
{
|
||||
Request *r = request.exchange(nullptr);
|
||||
|
||||
logger->debug("Running API request: uri={}, method={}", r->uri, r->method);
|
||||
logger->debug("Running API request: uri={}, method={}", uri, method);
|
||||
|
||||
try {
|
||||
r->prepare();
|
||||
response = r->execute();
|
||||
|
||||
logger->debug("Completed API request: request={}", r->uri, r->method);
|
||||
logger->debug("Completed API request: request={}", uri, method);
|
||||
} catch (const Error &e) {
|
||||
response = new ErrorResponse(this, e);
|
||||
|
||||
logger->warn("API request failed: uri={}, method={}, code={}: {}", r->uri, r->method, e.code, e.what());
|
||||
logger->warn("API request failed: uri={}, method={}, code={}: {}", uri, method, e.code, e.what());
|
||||
} catch (const RuntimeError &e) {
|
||||
response = new ErrorResponse(this, e);
|
||||
|
||||
logger->warn("API request failed: uri={}, method={}: {}", r->uri, r->method, e.what());
|
||||
logger->warn("API request failed: uri={}, method={}: {}", uri, method, e.what());
|
||||
}
|
||||
|
||||
logger->debug("Ran pending API requests. Triggering on_writeable callback: wsi={}", (void *) wsi);
|
||||
|
@ -124,17 +127,15 @@ void Session::open(void *in, size_t len)
|
|||
{
|
||||
int ret;
|
||||
char buf[32];
|
||||
unsigned long contentLength;
|
||||
|
||||
Request::Method meth;
|
||||
std::string uri = reinterpret_cast<char *>(in);
|
||||
uri = reinterpret_cast<char *>(in);
|
||||
|
||||
try {
|
||||
meth = (Request::Method) getRequestMethod(wsi);
|
||||
if (meth == Request::Method::UNKNOWN)
|
||||
auto method = getRequestMethod();
|
||||
if (method == Method::UNKNOWN)
|
||||
throw RuntimeError("Invalid request method");
|
||||
|
||||
request = RequestFactory::make(this, uri, meth);
|
||||
request = RequestFactory::create(this);
|
||||
|
||||
ret = lws_hdr_copy(wsi, buf, sizeof(buf), WSI_TOKEN_HTTP_CONTENT_LENGTH);
|
||||
if (ret < 0)
|
||||
|
@ -150,7 +151,7 @@ void Session::open(void *in, size_t len)
|
|||
*
|
||||
* We immediatly send headers and close the connection
|
||||
* without waiting for a POST body */
|
||||
if (meth == Request::Method::OPTIONS)
|
||||
if (method == Method::OPTIONS)
|
||||
lws_callback_on_writable(wsi);
|
||||
/* This request has no body.
|
||||
* We can reply immediatly */
|
||||
|
@ -317,43 +318,48 @@ int Session::protocolCallback(struct lws *wsi, enum lws_callback_reasons reason,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int Session::getRequestMethod(struct lws *wsi)
|
||||
std::string Session::getRequestURI() const
|
||||
{
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI))
|
||||
return Request::Method::GET;
|
||||
else if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
|
||||
return Request::Method::POST;
|
||||
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
|
||||
else if (lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))
|
||||
return Request::Method::PUT;
|
||||
else if (lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI))
|
||||
return Request::Method::PATCH;
|
||||
else if (lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI))
|
||||
return Request::Method::OPTIONS;
|
||||
#endif
|
||||
else
|
||||
return Request::Method::UNKNOWN;
|
||||
return uri;
|
||||
}
|
||||
|
||||
std::string Session::methodToString(int method)
|
||||
Session::Method Session::getRequestMethod() const
|
||||
{
|
||||
if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI))
|
||||
return Method::GET;
|
||||
else if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
|
||||
return Method::POST;
|
||||
#if defined(LWS_WITH_HTTP_UNCOMMON_HEADERS) || defined(LWS_HTTP_HEADERS_ALL)
|
||||
else if (lws_hdr_total_length(wsi, WSI_TOKEN_PUT_URI))
|
||||
return Method::PUT;
|
||||
else if (lws_hdr_total_length(wsi, WSI_TOKEN_PATCH_URI))
|
||||
return Method::PATCH;
|
||||
else if (lws_hdr_total_length(wsi, WSI_TOKEN_OPTIONS_URI))
|
||||
return Method::OPTIONS;
|
||||
#endif
|
||||
else
|
||||
return Method::UNKNOWN;
|
||||
}
|
||||
|
||||
std::string Session::methodToString(Method method)
|
||||
{
|
||||
switch (method) {
|
||||
case Request::Method::POST:
|
||||
case Method::POST:
|
||||
return "POST";
|
||||
|
||||
case Request::Method::GET:
|
||||
case Method::GET:
|
||||
return "GET";
|
||||
|
||||
case Request::Method::DELETE:
|
||||
case Method::DELETE:
|
||||
return "DELETE";
|
||||
|
||||
case Request::Method::PUT:
|
||||
case Method::PUT:
|
||||
return "PUT";
|
||||
|
||||
case Request::Method::PATCH:
|
||||
case Method::PATCH:
|
||||
return "GPATCHET";
|
||||
|
||||
case Request::Method::OPTIONS:
|
||||
case Method::OPTIONS:
|
||||
return "OPTIONS";
|
||||
|
||||
default:
|
||||
|
|
Loading…
Add table
Reference in a new issue