Skip to content

Commit

Permalink
Middleware support continues...
Browse files Browse the repository at this point in the history
  • Loading branch information
mathieucarbou committed Aug 17, 2024
1 parent 8348554 commit 987ab3f
Show file tree
Hide file tree
Showing 19 changed files with 240 additions and 75 deletions.
11 changes: 5 additions & 6 deletions examples/esp-idf/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ const char* app_user = "admin";
const char* app_pass = "admin";
const char* app_name = "Your App";

AuthenticationMiddleware basicAuth(app_user, app_pass, HTTPAuthMethod::BASIC_AUTH, app_name, "You must log in.");
AuthenticationMiddleware digestAuth(app_user, app_pass, HTTPAuthMethod::DIGEST_AUTH, app_name, "You must log in.");

// hostname for mdns (psychic.local)
const char* local_hostname = "psychic";

Expand Down Expand Up @@ -314,16 +317,12 @@ void setup()
// how to do basic auth
server.on("/auth-basic", HTTP_GET, [](PsychicRequest* request, PsychicResponse *response)
{
if (!request->authenticate(app_user, app_pass))
return request->requestAuthentication(BASIC_AUTH, app_name, "You must log in.");
return response->send("Auth Basic Success!"); });
return response->send("Auth Basic Success!"); })->addMiddleware(&basicAuth);

// how to do digest auth
server.on("/auth-digest", HTTP_GET, [](PsychicRequest* request, PsychicResponse *response)
{
if (!request->authenticate(app_user, app_pass))
return request->requestAuthentication(DIGEST_AUTH, app_name, "You must log in.");
return response->send("Auth Digest Success!"); });
return response->send("Auth Digest Success!"); })->addMiddleware(&digestAuth);

// example of getting / setting cookies
server.on("/cookies", HTTP_GET, [](PsychicRequest* request, PsychicResponse *response)
Expand Down
23 changes: 11 additions & 12 deletions examples/platformio/src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ const char* app_user = "admin";
const char* app_pass = "admin";
const char* app_name = "Your App";

LoggingMiddleware loggingMiddleware(Serial);
AuthenticationMiddleware basicAuth(app_user, app_pass, HTTPAuthMethod::BASIC_AUTH, app_name, "You must log in.");
AuthenticationMiddleware digestAuth(app_user, app_pass, HTTPAuthMethod::DIGEST_AUTH, app_name, "You must log in.");

// hostname for mdns (psychic.local)
const char* local_hostname = "psychic";

Expand All @@ -101,6 +105,7 @@ PsychicHttpServer server;
#endif
PsychicWebSocketHandler websocketHandler;
PsychicEventSource eventSource;
CorsMiddleware corsMiddleware;

// NTP server stuff
const char* ntpServer1 = "pool.ntp.org";
Expand Down Expand Up @@ -325,6 +330,10 @@ void setup()

DefaultHeaders::Instance().addHeader("Server", "PsychicHttp");

server.addMiddleware(&loggingMiddleware);
// this will send CORS headers on every HTTP_OPTIONS request that contains the Origin: header
server.addMiddleware(&corsMiddleware);

// rewrites!
server.rewrite("/rewrite", "/api?foo=rewrite");

Expand Down Expand Up @@ -485,18 +494,14 @@ void setup()
// how to do basic auth
// curl -i --user admin:admin http://psychic.local/auth-basic
server.on("/auth-basic", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
if (!request->authenticate(app_user, app_pass))
return request->requestAuthentication(BASIC_AUTH, app_name, "You must log in.");
return response->send("Auth Basic Success!");
});
})->addMiddleware(&basicAuth);

// how to do digest auth
// curl -i --user admin:admin http://psychic.local/auth-digest
server.on("/auth-digest", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
if (!request->authenticate(app_user, app_pass))
return request->requestAuthentication(DIGEST_AUTH, app_name, "You must log in.");
return response->send("Auth Digest Success!");
});
})->addMiddleware(&digestAuth);

// example of getting / setting cookies
// curl -i -b cookie.txt -c cookie.txt http://psychic.local/cookies
Expand Down Expand Up @@ -679,12 +684,6 @@ void setup()
return request->hasParam("secret");
});

// this will send CORS headers on every request that contains the Origin: header
server.addMiddleware(new PermissiveCorsMiddleware());

// this will respond to CORS requests (note: the global server filter will automatically add the CORS headers)
server.on("*", HTTP_OPTIONS, [](PsychicRequest* request, PsychicResponse* response) { return response->send(200); });

server.begin();
}
}
Expand Down
3 changes: 0 additions & 3 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,11 @@ lib_deps =
lib_ignore =
examples
build_flags =
-frtti
-Wall
-Wextra
-Og
-D CONFIG_ARDUHAL_LOG_COLORS
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
build_unflags =
-fno-rtti

[env:arduino2]
platform = [email protected]
Expand Down
20 changes: 19 additions & 1 deletion src/PsychicClient.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ IPAddress PsychicClient::localIP()
return address;
}

uint16_t PsychicClient::localPort() const
{
struct sockaddr_storage addr;
socklen_t len = sizeof addr;
getsockname(_socket, (struct sockaddr*)&addr, &len);
struct sockaddr_in* s = (struct sockaddr_in*)&addr;
return ntohs(s->sin_port);
}

IPAddress PsychicClient::remoteIP()
{
IPAddress address(0, 0, 0, 0);
Expand All @@ -72,4 +81,13 @@ IPAddress PsychicClient::remoteIP()
address.fromString(ipstr);

return address;
}
}

uint16_t PsychicClient::remotePort() const
{
struct sockaddr_storage addr;
socklen_t len = sizeof addr;
getpeername(_socket, (struct sockaddr*)&addr, &len);
struct sockaddr_in* s = (struct sockaddr_in*)&addr;
return ntohs(s->sin_port);
}
2 changes: 2 additions & 0 deletions src/PsychicClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ class PsychicClient
esp_err_t close();

IPAddress localIP();
uint16_t localPort() const;
IPAddress remoteIP();
uint16_t remotePort() const;
};

#endif
2 changes: 1 addition & 1 deletion src/PsychicCore.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ typedef std::function<bool(PsychicRequest* request)> PsychicRequestFilterFunctio

// middleware function definition
typedef std::function<esp_err_t(PsychicRequest* request, PsychicResponse* response)> PsychicMiddlewareCallback;
typedef std::function<esp_err_t(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response)> PsychicMiddlewareFunction;
typedef std::function<esp_err_t(PsychicRequest* request, PsychicResponse* response, PsychicMiddlewareCallback next)> PsychicMiddlewareFunction;

// client connect callback
typedef std::function<void(PsychicClient* client)> PsychicClientCallback;
Expand Down
4 changes: 2 additions & 2 deletions src/PsychicEndpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,9 @@ PsychicEndpoint* PsychicEndpoint::addMiddleware(PsychicMiddlewareFunction fn)
return this;
}

bool PsychicEndpoint::removeMiddleware(PsychicMiddleware* middleware)
void PsychicEndpoint::removeMiddleware(PsychicMiddleware* middleware)
{
return _handler->removeMiddleware(middleware);
_handler->removeMiddleware(middleware);
}

esp_err_t PsychicEndpoint::process(PsychicRequest* request, PsychicResponse* response)
Expand Down
2 changes: 1 addition & 1 deletion src/PsychicEndpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class PsychicEndpoint

PsychicEndpoint* addMiddleware(PsychicMiddleware* middleware);
PsychicEndpoint* addMiddleware(PsychicMiddlewareFunction fn);
bool removeMiddleware(PsychicMiddleware* middleware);
void removeMiddleware(PsychicMiddleware* middleware);

String uri();

Expand Down
27 changes: 19 additions & 8 deletions src/PsychicHandler.cpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
#include "PsychicHandler.h"

PsychicHandler::PsychicHandler() : _server(NULL),
_chain(new PsychicMiddlewareChain()),
_subprotocol("")
PsychicHandler::PsychicHandler()
{
}

Expand All @@ -26,7 +24,7 @@ bool PsychicHandler::filter(PsychicRequest* request)
// run through our filter chain.
for (auto& filter : _filters) {
if (!filter(request)) {
ESP_LOGD(PH_TAG, "Request %s refused by filter from handler %s", request->uri().c_str(), typeid(*this).name());
ESP_LOGD(PH_TAG, "Request %s refused by filter from handler", request->uri().c_str());
return false;
}
}
Expand Down Expand Up @@ -105,19 +103,27 @@ const std::list<PsychicClient*>& PsychicHandler::getClientList()

PsychicHandler* PsychicHandler::addMiddleware(PsychicMiddleware* middleware)
{
if (!_chain) {
_chain = new PsychicMiddlewareChain();
}
_chain->add(middleware);
return this;
}

PsychicHandler* PsychicHandler::addMiddleware(PsychicMiddlewareFunction fn)
{
if (!_chain) {
_chain = new PsychicMiddlewareChain();
}
_chain->add(fn);
return this;
}

bool PsychicHandler::removeMiddleware(PsychicMiddleware* middleware)
void PsychicHandler::removeMiddleware(PsychicMiddleware* middleware)
{
return _chain->remove(middleware);
if (_chain) {
_chain->remove(middleware);
}
}

esp_err_t PsychicHandler::process(PsychicRequest* request, PsychicResponse* response)
Expand All @@ -127,9 +133,14 @@ esp_err_t PsychicHandler::process(PsychicRequest* request, PsychicResponse* resp
}

if (!canHandle(request)) {
ESP_LOGD(PH_TAG, "Request %s refused by handler %s", request->uri().c_str(), typeid(*this).name());
ESP_LOGD(PH_TAG, "Request %s refused by handler", request->uri().c_str());
return HTTPD_404_NOT_FOUND;
}

return _chain->run(request, response, std::bind(&PsychicHandler::handleRequest, this, std::placeholders::_1, std::placeholders::_2));
if (_chain) {
return _chain->run(request, response, std::bind(&PsychicHandler::handleRequest, this, std::placeholders::_1, std::placeholders::_2));

} else {
return handleRequest(request, response);
}
}
6 changes: 3 additions & 3 deletions src/PsychicHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ class PsychicHandler
friend PsychicEndpoint;

protected:
PsychicHttpServer* _server;
PsychicMiddlewareChain* _chain;
PsychicHttpServer* _server = nullptr;
PsychicMiddlewareChain* _chain = nullptr;
std::list<PsychicRequestFilterFunction> _filters;

String _subprotocol;
Expand Down Expand Up @@ -58,7 +58,7 @@ class PsychicHandler

PsychicHandler* addMiddleware(PsychicMiddleware* middleware);
PsychicHandler* addMiddleware(PsychicMiddlewareFunction fn);
bool removeMiddleware(PsychicMiddleware *middleware);
void removeMiddleware(PsychicMiddleware *middleware);

// derived classes must implement these functions
virtual bool canHandle(PsychicRequest* request) { return true; };
Expand Down
23 changes: 17 additions & 6 deletions src/PsychicHttpServer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@
#include "ETH.h"
#endif

PsychicHttpServer::PsychicHttpServer(uint16_t port) : _onOpen(NULL),
_onClose(NULL),
_chain(new PsychicMiddlewareChain())
PsychicHttpServer::PsychicHttpServer(uint16_t port)
{
maxRequestBodySize = MAX_REQUEST_BODY_SIZE;
maxUploadSize = MAX_UPLOAD_SIZE;
Expand Down Expand Up @@ -401,19 +399,27 @@ bool PsychicHttpServer::_filter(PsychicRequest* request)

PsychicHttpServer* PsychicHttpServer::addMiddleware(PsychicMiddleware* middleware)
{
if (!_chain) {
_chain = new PsychicMiddlewareChain();
}
_chain->add(middleware);
return this;
}

PsychicHttpServer* PsychicHttpServer::addMiddleware(PsychicMiddlewareFunction fn)
{
if (!_chain) {
_chain = new PsychicMiddlewareChain();
}
_chain->add(fn);
return this;
}

bool PsychicHttpServer::removeMiddleware(PsychicMiddleware* middleware)
void PsychicHttpServer::removeMiddleware(PsychicMiddleware* middleware)
{
return _chain->remove(middleware);
if (_chain) {
_chain->remove(middleware);
}
}

void PsychicHttpServer::onNotFound(PsychicHttpRequestCallback fn)
Expand Down Expand Up @@ -452,7 +458,12 @@ esp_err_t PsychicHttpServer::requestHandler(httpd_req_t* req)
}

// then runs the request through the filter chain
esp_err_t ret = server->_chain->run(&request, &response, std::bind(&PsychicHttpServer::_process, server, std::placeholders::_1, std::placeholders::_2));
esp_err_t ret;
if (server->_chain) {
ret = server->_chain->run(&request, &response, std::bind(&PsychicHttpServer::_process, server, std::placeholders::_1, std::placeholders::_2));
} else {
ret = server->_process(&request, &response);
}
ESP_LOGD(PH_TAG, "Request %s processed by global middleware: %s", request.uri().c_str(), esp_err_to_name(ret));

if (ret == HTTPD_404_NOT_FOUND) {
Expand Down
8 changes: 4 additions & 4 deletions src/PsychicHttpServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ class PsychicHttpServer
std::list<PsychicRewrite*> _rewrites;
std::list<PsychicRequestFilterFunction> _filters;

PsychicClientCallback _onOpen;
PsychicClientCallback _onClose;
PsychicMiddlewareChain* _chain;
PsychicClientCallback _onOpen = nullptr;
PsychicClientCallback _onClose = nullptr;
PsychicMiddlewareChain* _chain = nullptr;

esp_err_t _start();
virtual esp_err_t _startServer();
Expand Down Expand Up @@ -107,7 +107,7 @@ class PsychicHttpServer

PsychicHttpServer* addMiddleware(PsychicMiddleware* middleware);
PsychicHttpServer* addMiddleware(PsychicMiddlewareFunction fn);
bool removeMiddleware(PsychicMiddleware *middleware);
void removeMiddleware(PsychicMiddleware *middleware);

static esp_err_t requestHandler(httpd_req_t* req);
static esp_err_t notFoundHandler(httpd_req_t* req, httpd_err_code_t err);
Expand Down
4 changes: 2 additions & 2 deletions src/PsychicMiddleware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ PsychicMiddlewareClosure::PsychicMiddlewareClosure(PsychicMiddlewareFunction fn)
{
assert(_fn);
}
esp_err_t PsychicMiddlewareClosure::run(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response)
esp_err_t PsychicMiddlewareClosure::run(PsychicRequest* request, PsychicResponse* response, PsychicMiddlewareCallback next)
{
return _fn(next, request, response);
return _fn(request, response, next);
}
9 changes: 7 additions & 2 deletions src/PsychicMiddleware.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
#include "PsychicRequest.h"
#include "PsychicResponse.h"

class PsychicMiddlewareChain;
/*
* PsychicMiddleware :: fancy callback wrapper for handling requests and responses.
* */

class PsychicMiddleware
{
private:
bool _managed = false;
friend PsychicMiddlewareChain;

public:
virtual ~PsychicMiddleware() {}
virtual esp_err_t run(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response) = 0;
virtual esp_err_t run(PsychicRequest* request, PsychicResponse* response, PsychicMiddlewareCallback next) = 0;
};

class PsychicMiddlewareClosure : public PsychicMiddleware
Expand All @@ -23,7 +28,7 @@ class PsychicMiddlewareClosure : public PsychicMiddleware

public:
PsychicMiddlewareClosure(PsychicMiddlewareFunction fn);
esp_err_t run(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response) override;
esp_err_t run(PsychicRequest* request, PsychicResponse* response, PsychicMiddlewareCallback next) override;
};

#endif
Loading

0 comments on commit 987ab3f

Please sign in to comment.