diff --git a/README.md b/README.md
index ee71b77..5997092 100644
--- a/README.md
+++ b/README.md
@@ -136,7 +136,7 @@ If you have existing code using ESPAsyncWebserver, you will feel right at home w
## Requests / Responses
-* request->send is now request->reply()
+* request->send is now response->send()
* if you create a response, call response->send() directly, not request->send(reply)
* request->headers() is not supported by ESP-IDF, you have to just check for the header you need.
* No AsyncCallbackJsonWebHandler (for now... can add if needed)
@@ -195,7 +195,7 @@ The ```server.on(...)``` returns a pointer to the endpoint, which can be used to
```cpp
//respond to /url only from requests to the AP
-server.on("/url", HTTP_GET, request_callback)->setFilter(ON_AP_FILTER);
+server.on("/url", HTTP_GET, request_callback)->addFilter(ON_AP_FILTER);
//require authentication on /url
server.on("/url", HTTP_GET, request_callback)->setAuthentication("user", "pass");
@@ -209,7 +209,7 @@ server.on("/ws")->attachHandler(&websocketHandler);
The ```PsychicWebHandler``` class is for handling standard web requests. It provides a single callback: ```onRequest()```. This callback is called when the handler receives a valid HTTP request.
-One major difference from ESPAsyncWebserver is that this callback needs to return an esp_err_t variable to let the server know the result of processing the request. The ```response->reply()``` and ```request->send()``` functions will return this. It is a good habit to return the result of these functions as sending the response will close the connection.
+One major difference from ESPAsyncWebserver is that this callback needs to return an esp_err_t variable to let the server know the result of processing the request. The ```response->send()``` and ```request->send()``` functions will return this. It is a good habit to return the result of these functions as sending the response will close the connection.
The function definition for the onRequest callback is:
@@ -223,7 +223,7 @@ Here is a simple example that sends back the client's IP on the URL /ip
server.on("/ip", [](PsychicRequest *request)
{
String output = "Your IP is: " + request->client()->remoteIP().toString();
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
```
@@ -291,7 +291,7 @@ It's worth noting that there is no standard way of passing in a filename for thi
String url = "/" + request->getFilename();
String output = "" + url + "";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
//wildcard basic file upload - POST to /upload/filename.ext
@@ -349,7 +349,7 @@ Very similar to the basic upload, with 2 key differences:
output += "Param 1: " + request->getParam("param1")->value() + "
\n";
output += "Param 2: " + request->getParam("param2")->value() + "
\n";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
//upload to /multipart url
@@ -371,11 +371,11 @@ The ```server.serveStatic()``` function handles creating the handler and assigni
```cpp
//serve static files from LittleFS/www on / only to clients on same wifi network
//this is where our /index.html file lives
-server.serveStatic("/", LittleFS, "/www/")->setFilter(ON_STA_FILTER);
+server.serveStatic("/", LittleFS, "/www/")->addFilter(ON_STA_FILTER);
//serve static files from LittleFS/www-ap on / only to clients on SoftAP
//this is where our /index.html file lives
-server.serveStatic("/", LittleFS, "/www-ap/")->setFilter(ON_AP_FILTER);
+server.serveStatic("/", LittleFS, "/www-ap/")->addFilter(ON_AP_FILTER);
//serve static files from LittleFS/img on /img
//it's more efficient to serve everything from a single www directory, but this is also possible.
@@ -429,7 +429,7 @@ Here is a basic example of using WebSockets:
websocketHandler.onFrame([](PsychicWebSocketRequest *request, httpd_ws_frame *frame) {
Serial.printf("[socket] #%d sent: %s\n", request->client()->socket(), (char *)frame->payload);
- return request->reply(frame);
+ return response->send(frame);
});
websocketHandler.onClose([](PsychicWebSocketClient *client) {
@@ -449,7 +449,7 @@ The onFrame() callback has 2 parameters:
For sending data on the websocket connection, there are 3 methods:
-* ```request->reply()``` - only available in the onFrame() callback context.
+* ```response->send()``` - only available in the onFrame() callback context.
* ```webSocketHandler.sendAll()``` - can be used anywhere to send websocket messages to all connected clients.
* ```client->send()``` - can be used anywhere* to send a websocket message to a specific client
diff --git a/benchmark/psychichttp/src/main.cpp b/benchmark/psychichttp/src/main.cpp
index 93b40eb..6f91624 100644
--- a/benchmark/psychichttp/src/main.cpp
+++ b/benchmark/psychichttp/src/main.cpp
@@ -170,7 +170,7 @@ void setup()
}
// our index
- server.on("/", HTTP_GET, [](PsychicRequest* request) { return request->reply(200, "text/html", htmlContent); });
+ server.on("/", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) { return response->send(200, "text/html", htmlContent); });
// serve static files from LittleFS/www on /
server.serveStatic("/", LittleFS, "/www/");
@@ -180,7 +180,7 @@ void setup()
// client->sendMessage("Hello!");
});
websocketHandler.onFrame([](PsychicWebSocketRequest* request, httpd_ws_frame* frame) {
- request->reply(frame);
+ response->send(frame);
return ESP_OK; });
server.on("/ws", &websocketHandler);
@@ -189,7 +189,7 @@ void setup()
server.on("/events", &eventSource);
// api - parameters passed in via query eg. /api/endpoint?foo=bar
- server.on("/api", HTTP_GET, [](PsychicRequest* request) {
+ server.on("/api", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
//create a response object
JsonDocument output;
output["msg"] = "status";
@@ -206,7 +206,7 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
- return request->reply(200, "application/json", jsonBuffer.c_str()); });
+ return response->send(200, "application/json", jsonBuffer.c_str()); });
server.begin();
}
diff --git a/benchmark/psychichttps/src/main.cpp b/benchmark/psychichttps/src/main.cpp
index 000f84e..9915c8e 100644
--- a/benchmark/psychichttps/src/main.cpp
+++ b/benchmark/psychichttps/src/main.cpp
@@ -196,7 +196,7 @@ void setup()
// our index
server.on("/", HTTP_GET, [](PsychicRequest* request)
- { return request->reply(200, "text/html", htmlContent); });
+ { return response->send(200, "text/html", htmlContent); });
// serve static files from LittleFS/www on /
server.serveStatic("/", LittleFS, "/www/");
@@ -204,7 +204,7 @@ void setup()
// a websocket echo server
websocketHandler.onFrame([](PsychicWebSocketRequest* request, httpd_ws_frame* frame)
{
- request->reply(frame);
+ response->send(frame);
return ESP_OK; });
server.on("/ws", &websocketHandler);
@@ -227,7 +227,7 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
- return request->reply(200, "application/json", jsonBuffer.c_str()); });
+ return response->send(200, "application/json", jsonBuffer.c_str()); });
}
}
diff --git a/examples/arduino/arduino.ino b/examples/arduino/arduino.ino
index c8c5b5b..03cd955 100644
--- a/examples/arduino/arduino.ino
+++ b/examples/arduino/arduino.ino
@@ -220,11 +220,11 @@ void setup()
//serve static files from LittleFS/www on / only to clients on same wifi network
//this is where our /index.html file lives
- server.serveStatic("/", LittleFS, "/www/")->setFilter(ON_STA_FILTER);
+ server.serveStatic("/", LittleFS, "/www/")->addFilter(ON_STA_FILTER);
//serve static files from LittleFS/www-ap on / only to clients on SoftAP
//this is where our /index.html file lives
- server.serveStatic("/", LittleFS, "/www-ap/")->setFilter(ON_AP_FILTER);
+ server.serveStatic("/", LittleFS, "/www-ap/")->addFilter(ON_AP_FILTER);
//serve static files from LittleFS/img on /img
//it's more efficient to serve everything from a single www directory, but this is also possible.
@@ -267,14 +267,14 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
- return request->reply(200, "application/json", jsonBuffer.c_str());
+ return response->send(200, "application/json", jsonBuffer.c_str());
});
//api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/ip", HTTP_GET, [](PsychicRequest *request)
{
String output = "Your IP is: " + request->client()->remoteIP().toString();
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
//api - parameters passed in via query eg. /api/endpoint?foo=bar
@@ -296,7 +296,7 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
- return request->reply(200, "application/json", jsonBuffer.c_str());
+ return response->send(200, "application/json", jsonBuffer.c_str());
});
//how to redirect a request
@@ -310,7 +310,7 @@ void setup()
{
if (!request->authenticate(app_user, app_pass))
return request->requestAuthentication(BASIC_AUTH, app_name, "You must log in.");
- return request->reply("Auth Basic Success!");
+ return response->send("Auth Basic Success!");
});
//how to do digest auth
@@ -318,7 +318,7 @@ void setup()
{
if (!request->authenticate(app_user, app_pass))
return request->requestAuthentication(DIGEST_AUTH, app_name, "You must log in.");
- return request->reply("Auth Digest Success!");
+ return response->send("Auth Digest Success!");
});
//example of getting / setting cookies
@@ -349,13 +349,13 @@ void setup()
output += "Param 1: " + request->getParam("param1")->value() + "
\n";
output += "Param 2: " + request->getParam("param2")->value() + "
\n";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
//you can set up a custom 404 handler.
server.onNotFound([](PsychicRequest *request)
{
- return request->reply(404, "text/html", "Custom 404 Handler");
+ return response->send(404, "text/html", "Custom 404 Handler");
});
//handle a very basic upload as post body
@@ -394,7 +394,7 @@ void setup()
String url = "/" + request->getFilename();
String output = "" + url + "";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
//wildcard basic file upload - POST to /upload/filename.ext
@@ -443,7 +443,7 @@ void setup()
output += "Param 1: " + request->getParam("param1")->value() + "
\n";
output += "Param 2: " + request->getParam("param2")->value() + "
\n";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
//wildcard basic file upload - POST to /upload/filename.ext
@@ -456,7 +456,7 @@ void setup()
});
websocketHandler.onFrame([](PsychicWebSocketRequest *request, httpd_ws_frame *frame) {
Serial.printf("[socket] #%d sent: %s\n", request->client()->socket(), (char *)frame->payload);
- return request->reply(frame);
+ return response->send(frame);
});
websocketHandler.onClose([](PsychicWebSocketClient *client) {
Serial.printf("[socket] connection #%u closed from %s\n", client->socket(), client->localIP().toString());
diff --git a/examples/arduino/arduino_captive_portal/README.md b/examples/arduino/arduino_captive_portal/README.md
index f965eda..f9bbaae 100644
--- a/examples/arduino/arduino_captive_portal/README.md
+++ b/examples/arduino/arduino_captive_portal/README.md
@@ -28,7 +28,7 @@ public:
esp_err_t handleRequest(PsychicRequest *request) {
//PsychicFileResponse response(request, LittleFS, "/captiveportal.html"); // uncomment : for captive portal page, if any, eg "captiveportal.html"
//return response.send(); // uncomment : return captive portal page
- return request->reply(200,"text/html","Welcome to captive portal !"); // simple text, comment if captive portal page
+ return response->send(200,"text/html","Welcome to captive portal !"); // simple text, comment if captive portal page
}
};
CaptiveRequestHandler *captivehandler=NULL; // handler for captive portal
diff --git a/examples/arduino/arduino_captive_portal/arduino_captive_portal.ino b/examples/arduino/arduino_captive_portal/arduino_captive_portal.ino
index 13dc9c8..4b59f7e 100644
--- a/examples/arduino/arduino_captive_portal/arduino_captive_portal.ino
+++ b/examples/arduino/arduino_captive_portal/arduino_captive_portal.ino
@@ -32,7 +32,7 @@ public:
esp_err_t handleRequest(PsychicRequest *request) {
//PsychicFileResponse response(request, LittleFS, "/captiveportal.html"); // uncomment : for captive portal page, if any, eg "captiveportal.html"
//return response.send(); // uncomment : return captive portal page
- return request->reply(200,"text/html","Welcome to captive portal !"); // simple text, comment if captive portal page
+ return response->send(200,"text/html","Welcome to captive portal !"); // simple text, comment if captive portal page
}
};
CaptiveRequestHandler *captivehandler=NULL; // handler for captive portal
diff --git a/examples/arduino/arduino_ota/arduino_ota.ino b/examples/arduino/arduino_ota/arduino_ota.ino
index c22c80e..6f88d14 100644
--- a/examples/arduino/arduino_ota/arduino_ota.ino
+++ b/examples/arduino/arduino_ota/arduino_ota.ino
@@ -109,7 +109,7 @@ void setup()
//you can set up a custom 404 handler.
// curl -i http://psychic.local/404
server.onNotFound([](PsychicRequest *request) {
- return request->reply(404, "text/html", "Custom 404 Handler");
+ return response->send(404, "text/html", "Custom 404 Handler");
});
// OTA
@@ -182,13 +182,13 @@ void setup()
if (!Update.hasError()) { // update is OK
ESP_LOGI(TAG,"Update code or data OK Update.errorString() %s", Update.errorString());
result = "Update done for file.";
- return request->reply(200,"text/html",result.c_str());
+ return response->send(200,"text/html",result.c_str());
// ESP.restart(); // restart ESP if needed
} // end update is OK
else { // update is KO, send request with pretty print error
result = " Update.errorString() " + String(Update.errorString());
ESP_LOGE(TAG,"ERROR : error %s",result.c_str());
- return request->reply(500, "text/html", result.c_str());
+ return response->send(500, "text/html", result.c_str());
} // end update is KO
});
@@ -203,7 +203,7 @@ void setup()
String output = "Restarting ...";
ESP_LOGI(TAG,"%s",output.c_str());
esprestart=true;
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
} // end onRequest
diff --git a/examples/esp-idf/main/main.cpp b/examples/esp-idf/main/main.cpp
index 5b7843b..20e41f4 100644
--- a/examples/esp-idf/main/main.cpp
+++ b/examples/esp-idf/main/main.cpp
@@ -223,11 +223,11 @@ void setup()
// serve static files from LittleFS/www on / only to clients on same wifi network
// this is where our /index.html file lives
- server.serveStatic("/", LittleFS, "/www/")->setFilter(ON_STA_FILTER);
+ server.serveStatic("/", LittleFS, "/www/")->addFilter(ON_STA_FILTER);
// serve static files from LittleFS/www-ap on / only to clients on SoftAP
// this is where our /index.html file lives
- server.serveStatic("/", LittleFS, "/www-ap/")->setFilter(ON_AP_FILTER);
+ server.serveStatic("/", LittleFS, "/www-ap/")->addFilter(ON_AP_FILTER);
// serve static files from LittleFS/img on /img
// it's more efficient to serve everything from a single www directory, but this is also possible.
@@ -278,13 +278,13 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
- return request->reply(200, "application/json", jsonBuffer.c_str()); });
+ return response->send(200, "application/json", jsonBuffer.c_str()); });
// api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/ip", HTTP_GET, [](PsychicRequest* request)
{
String output = "Your IP is: " + request->client()->remoteIP().toString();
- return request->reply(output.c_str()); });
+ return response->send(output.c_str()); });
// api - parameters passed in via query eg. /api/endpoint?foo=bar
server.on("/api", HTTP_GET, [](PsychicRequest* request)
@@ -305,7 +305,7 @@ void setup()
//serialize and return
String jsonBuffer;
serializeJson(output, jsonBuffer);
- return request->reply(200, "application/json", jsonBuffer.c_str()); });
+ return response->send(200, "application/json", jsonBuffer.c_str()); });
// how to redirect a request
server.on("/redirect", HTTP_GET, [](PsychicRequest* request)
@@ -316,14 +316,14 @@ void setup()
{
if (!request->authenticate(app_user, app_pass))
return request->requestAuthentication(BASIC_AUTH, app_name, "You must log in.");
- return request->reply("Auth Basic Success!"); });
+ return response->send("Auth Basic Success!"); });
// how to do digest auth
server.on("/auth-digest", HTTP_GET, [](PsychicRequest* request)
{
if (!request->authenticate(app_user, app_pass))
return request->requestAuthentication(DIGEST_AUTH, app_name, "You must log in.");
- return request->reply("Auth Digest Success!"); });
+ return response->send("Auth Digest Success!"); });
// example of getting / setting cookies
server.on("/cookies", HTTP_GET, [](PsychicRequest* request)
@@ -352,11 +352,11 @@ void setup()
output += "Param 1: " + request->getParam("param1")->value() + "
\n";
output += "Param 2: " + request->getParam("param2")->value() + "
\n";
- return request->reply(output.c_str()); });
+ return response->send(output.c_str()); });
// you can set up a custom 404 handler.
server.onNotFound([](PsychicRequest* request)
- { return request->reply(404, "text/html", "Custom 404 Handler"); });
+ { return response->send(404, "text/html", "Custom 404 Handler"); });
// handle a very basic upload as post body
PsychicUploadHandler* uploadHandler = new PsychicUploadHandler();
@@ -394,7 +394,7 @@ void setup()
String url = "/" + request->getFilename();
String output = "" + url + "";
- return request->reply(output.c_str()); });
+ return response->send(output.c_str()); });
// wildcard basic file upload - POST to /upload/filename.ext
server.on("/upload/*", HTTP_POST, uploadHandler);
@@ -442,7 +442,7 @@ void setup()
output += "Param 1: " + request->getParam("param1")->value() + "
\n";
output += "Param 2: " + request->getParam("param2")->value() + "
\n";
- return request->reply(output.c_str()); });
+ return response->send(output.c_str()); });
// wildcard basic file upload - POST to /upload/filename.ext
server.on("/multipart", HTTP_POST, multipartHandler);
@@ -455,7 +455,7 @@ void setup()
websocketHandler.onFrame([](PsychicWebSocketRequest* request, httpd_ws_frame* frame)
{
Serial.printf("[socket] #%d sent: %s\n", request->client()->socket(), (char *)frame->payload);
- return request->reply(frame); });
+ return response->send(frame); });
websocketHandler.onClose([](PsychicWebSocketClient* client)
{ Serial.printf("[socket] connection #%u closed from %s\n", client->socket(), client->localIP().toString().c_str()); });
server.on("/ws", &websocketHandler);
diff --git a/examples/platformio/src/main.cpp b/examples/platformio/src/main.cpp
index 67b3f71..d19e0af 100644
--- a/examples/platformio/src/main.cpp
+++ b/examples/platformio/src/main.cpp
@@ -241,18 +241,6 @@ bool setupSDCard()
}
#endif
-bool PERMISSIVE_CORS(PsychicRequest* request)
-{
- if (request->hasHeader("Origin")) {
- request->addResponseHeader("Access-Control-Allow-Origin", "*");
- request->addResponseHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
- request->addResponseHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
- request->addResponseHeader("Access-Control-Max-Age", "86400");
- }
-
- return true;
-}
-
void setup()
{
esp_log_level_set(PH_TAG, ESP_LOG_DEBUG);
@@ -328,7 +316,7 @@ void setup()
// this creates a 2nd server listening on port 80 and redirects all requests HTTPS
PsychicHttpServer* redirectServer = new PsychicHttpServer();
redirectServer->config.ctrl_port = 20424; // just a random port different from the default one
- redirectServer->onNotFound([](PsychicRequest* request) {
+ redirectServer->onNotFound([](PsychicRequest* request, PsychicResponse* response) {
String url = "https://" + request->host() + request->url();
return request->redirect(url.c_str()); });
}
@@ -344,11 +332,11 @@ void setup()
// curl -i http://psychic.local/
PsychicStaticFileHandler* handler = server.serveStatic("/", LittleFS, "/www/");
handler->setCacheControl("max-age=60");
- handler->setFilter(ON_STA_FILTER);
+ handler->addFilter(ON_STA_FILTER);
// serve static files from LittleFS/www-ap on / only to clients on SoftAP
// this is where our /index.html file lives
- server.serveStatic("/", LittleFS, "/www-ap/")->setFilter(ON_AP_FILTER);
+ server.serveStatic("/", LittleFS, "/www-ap/")->addFilter(ON_AP_FILTER);
// serve static files from LittleFS/img on /img
// it's more efficient to serve everything from a single www directory, but this is also possible.
@@ -373,11 +361,11 @@ void setup()
// api - json message passed in as post body
// curl -i -X POST -H "Content-Type: application/json" -d '{"foo":"bar"}' http://psychic.local/api
- server.on("/api", HTTP_POST, [](PsychicRequest* request, JsonVariant& json) {
+ server.on("/api", HTTP_POST, [](PsychicRequest* request, PsychicResponse* resp, JsonVariant& json) {
JsonObject input = json.as();
// create our response json
- PsychicJsonResponse response = PsychicJsonResponse(request);
+ PsychicJsonResponse response(resp);
JsonObject output = response.getRoot();
output["msg"] = "status";
@@ -396,15 +384,15 @@ void setup()
// ip - get info about the client
// curl -i http://psychic.local/ip
- server.on("/ip", HTTP_GET, [](PsychicRequest* request) {
+ server.on("/ip", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
String output = "Your IP is: " + request->client()->remoteIP().toString();
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
// client connect/disconnect to a url
// curl -i http://psychic.local/handler
PsychicWebHandler* connectionHandler = new PsychicWebHandler();
- connectionHandler->onRequest([](PsychicRequest* request) { return request->reply("OK"); });
+ connectionHandler->onRequest([](PsychicRequest* request, PsychicResponse* response) { return response->send("OK"); });
connectionHandler->onOpen([](PsychicClient* client) { Serial.printf("[handler] connection #%u connected from %s\n", client->socket(), client->remoteIP().toString().c_str()); });
connectionHandler->onClose([](PsychicClient* client) { Serial.printf("[handler] connection #%u closed\n", client->socket()); });
@@ -413,9 +401,9 @@ void setup()
// api - parameters passed in via query eg. /api?foo=bar
// curl -i 'http://psychic.local/api?foo=bar'
- server.on("/api", HTTP_GET, [](PsychicRequest* request) {
+ server.on("/api", HTTP_GET, [](PsychicRequest* request, PsychicResponse* resp) {
// create our response json
- PsychicJsonResponse response = PsychicJsonResponse(request);
+ PsychicJsonResponse response = PsychicJsonResponse(resp);
JsonObject output = response.getRoot();
output["msg"] = "status";
@@ -434,9 +422,9 @@ void setup()
// curl -i -X GET 'http://psychic.local/any'
// curl -i -X POST 'http://psychic.local/any'
- server.on("/any", HTTP_ANY, [](PsychicRequest* request) {
+ server.on("/any", HTTP_ANY, [](PsychicRequest* request, PsychicResponse* resp) {
// create our response json
- PsychicJsonResponse response = PsychicJsonResponse(request);
+ PsychicJsonResponse response = PsychicJsonResponse(resp);
JsonObject output = response.getRoot();
output["msg"] = "status";
@@ -448,15 +436,15 @@ void setup()
});
// curl -i 'http://psychic.local/simple'
- server.on("/simple", HTTP_GET, [](PsychicRequest* request) {
- return request->reply("Simple");
+ server.on("/simple", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
+ return response->send("Simple");
})
->setURIMatchFunction(MATCH_SIMPLE);
#ifdef PSY_ENABLE_REGEX
// curl -i 'http://psychic.local/regex/23'
// curl -i 'http://psychic.local/regex/4223'
- server.on("^/regex/([\\d]+)/?$", HTTP_GET, [](PsychicRequest* request) {
+ server.on("^/regex/([\\d]+)/?$", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
// look up our regex matches
std::smatch matches;
if (request->getRegexMatches(matches)) {
@@ -465,55 +453,53 @@ void setup()
output += "Matched URI: " + String(matches.str(0).c_str()) + "
\n";
output += "Match 1: " + String(matches.str(1).c_str()) + "
\n";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
} else
- return request->reply("No regex match.");
+ return response->send("No regex match.");
})
->setURIMatchFunction(MATCH_REGEX);
#endif
// JsonResponse example
// curl -i http://psychic.local/json
- server.on("/json", HTTP_GET, [](PsychicRequest* request) {
- PsychicJsonResponse response = PsychicJsonResponse(request);
+ server.on("/json", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
+ PsychicJsonResponse jsonResponse = PsychicJsonResponse(response);
char key[16];
char value[32];
- JsonObject root = response.getRoot();
+ JsonObject root = jsonResponse.getRoot();
for (int i = 0; i < 100; i++) {
sprintf(key, "key%d", i);
sprintf(value, "value is %d", i);
root[key] = value;
}
- return response.send();
+ return jsonResponse.send();
});
// how to redirect a request
// curl -i http://psychic.local/redirect
- server.on("/redirect", HTTP_GET, [](PsychicRequest* request) { return request->redirect("/alien.png"); });
+ server.on("/redirect", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) { return response->redirect("/alien.png"); });
// how to do basic auth
// curl -i --user admin:admin http://psychic.local/auth-basic
- server.on("/auth-basic", HTTP_GET, [](PsychicRequest* request) {
+ 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 request->reply("Auth Basic Success!");
+ return response->send("Auth Basic Success!");
});
// how to do digest auth
// curl -i --user admin:admin http://psychic.local/auth-digest
- server.on("/auth-digest", HTTP_GET, [](PsychicRequest* request) {
+ 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 request->reply("Auth Digest Success!");
+ return response->send("Auth Digest Success!");
});
// example of getting / setting cookies
// curl -i -b cookie.txt -c cookie.txt http://psychic.local/cookies
- server.on("/cookies", HTTP_GET, [](PsychicRequest* request) {
- PsychicResponse response(request);
-
+ server.on("/cookies", HTTP_GET, [](PsychicRequest* request, PsychicResponse* response) {
int counter = 0;
char cookie[14];
size_t size = sizeof(cookie);
@@ -524,25 +510,25 @@ void setup()
}
sprintf(cookie, "%d", counter);
- response.setCookie("counter", cookie);
- response.setContent(cookie);
- return response.send();
+ response->setCookie("counter", cookie);
+ response->setContent(cookie);
+ return response->send();
});
// example of getting POST variables
// curl -i -d "param1=value1¶m2=value2" -X POST http://psychic.local/post
// curl -F "param1=value1" -F "param2=value2" -X POST http://psychic.local/post
- server.on("/post", HTTP_POST, [](PsychicRequest* request) {
+ server.on("/post", HTTP_POST, [](PsychicRequest* request, PsychicResponse* response) {
String output;
output += "Param 1: " + request->getParam("param1")->value() + "
\n";
output += "Param 2: " + request->getParam("param2")->value() + "
\n";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
// you can set up a custom 404 handler.
// curl -i http://psychic.local/404
- server.onNotFound([](PsychicRequest* request) { return request->reply(404, "text/html", "Custom 404 Handler"); });
+ server.onNotFound([](PsychicRequest* request, PsychicResponse* response) { return response->send(404, "text/html", "Custom 404 Handler"); });
// handle a very basic upload as post body
PsychicUploadHandler* uploadHandler = new PsychicUploadHandler();
@@ -575,11 +561,11 @@ void setup()
});
// gets called after upload has been handled
- uploadHandler->onRequest([](PsychicRequest* request) {
+ uploadHandler->onRequest([](PsychicRequest* request, PsychicResponse* response) {
String url = "/" + request->getFilename();
String output = "" + url + "";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
// wildcard basic file upload - POST to /upload/filename.ext
@@ -617,7 +603,7 @@ void setup()
});
// gets called after upload has been handled
- multipartHandler->onRequest([](PsychicRequest* request) {
+ multipartHandler->onRequest([](PsychicRequest* request, PsychicResponse* response) {
String output;
if (request->hasParam("file_upload")) {
PsychicWebParameter* file = request->getParam("file_upload");
@@ -632,7 +618,7 @@ void setup()
if (request->hasParam("param2"))
output += "Param 2: " + request->getParam("param2")->value() + "
\n";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
// wildcard basic file upload - POST to /upload/filename.ext
@@ -643,14 +629,14 @@ void setup()
// form only multipart handler
// curl -F "param1=multi" -F "param2=part" http://psychic.local/multipart-data
PsychicUploadHandler* multipartFormHandler = new PsychicUploadHandler();
- multipartFormHandler->onRequest([](PsychicRequest* request) {
+ multipartFormHandler->onRequest([](PsychicRequest* request, PsychicResponse* response) {
String output;
if (request->hasParam("param1"))
output += "Param 1: " + request->getParam("param1")->value() + "
\n";
if (request->hasParam("param2"))
output += "Param 2: " + request->getParam("param2")->value() + "
\n";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
});
server.on("/multipart-data", HTTP_POST, multipartFormHandler);
@@ -681,22 +667,22 @@ void setup()
// example of using POST data inside the filter
// works: curl -F "secret=password" http://psychic.local/post-filter
// 404: curl -F "foo=bar" http://psychic.local/post-filter
- server.on("/post-filter", HTTP_POST, [](PsychicRequest* request) {
+ server.on("/post-filter", HTTP_POST, [](PsychicRequest* request, PsychicResponse* response) {
String output;
output += "Secret: " + request->getParam("secret")->value() + "
\n";
- return request->reply(output.c_str());
+ return response->send(output.c_str());
})
- ->setFilter([](PsychicRequest* request) {
+ ->addFilter([](PsychicRequest* request) {
request->loadParams();
return request->hasParam("secret");
});
// this will send CORS headers on every request that contains the Origin: header
- server.setFilter(PERMISSIVE_CORS);
+ 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) { return request->reply(200); });
+ server.on("*", HTTP_OPTIONS, [](PsychicRequest* request, PsychicResponse* response) { return response->send(200); });
server.begin();
}
diff --git a/examples/websockets/src/main.cpp b/examples/websockets/src/main.cpp
index be14621..63cc778 100644
--- a/examples/websockets/src/main.cpp
+++ b/examples/websockets/src/main.cpp
@@ -179,7 +179,7 @@ void setup()
//send a throttle message if we're full
if (!uxQueueSpacesAvailable(wsMessages))
- return request->reply("Queue Full");
+ return response->send("Queue Full");
return ESP_OK; });
websocketHandler.onClose([](PsychicWebSocketClient* client)
diff --git a/src/PsychicCore.h b/src/PsychicCore.h
index fd6e5cb..6109eb3 100644
--- a/src/PsychicCore.h
+++ b/src/PsychicCore.h
@@ -49,20 +49,20 @@ class PsychicRequest;
class PsychicResponse;
class PsychicWebSocketRequest;
class PsychicClient;
-class PsychicMiddlewareChain;
// filter function definition
typedef std::function PsychicRequestFilterFunction;
// middleware function definition
-typedef std::function PsychicMiddlewareFunction;
+typedef std::function PsychicMiddlewareCallback;
+typedef std::function PsychicMiddlewareFunction;
// client connect callback
typedef std::function PsychicClientCallback;
// callback definitions
-typedef std::function PsychicHttpRequestCallback;
-typedef std::function PsychicJsonRequestCallback;
+typedef std::function PsychicHttpRequestCallback;
+typedef std::function PsychicJsonRequestCallback;
typedef std::function PsychicUploadCallback;
struct HTTPHeader {
diff --git a/src/PsychicEndpoint.cpp b/src/PsychicEndpoint.cpp
index ffd0be9..4e9c8dd 100644
--- a/src/PsychicEndpoint.cpp
+++ b/src/PsychicEndpoint.cpp
@@ -55,24 +55,18 @@ esp_err_t PsychicEndpoint::requestCallback(httpd_req_t* req)
#endif
PsychicEndpoint* self = (PsychicEndpoint*)req->user_ctx;
- PsychicHandler* handler = self->handler();
PsychicRequest request(self->_server, req);
+ PsychicResponse response(&request);
- // make sure we have a handler
- if (handler != NULL) {
- if (handler->filter(&request) && handler->canHandle(&request)) {
- // check our credentials
- if (handler->needsAuthentication(&request))
- return handler->authenticate(&request);
+ esp_err_t err = self->process(&request, &response);
- // pass it to our handler
- return handler->handleRequest(&request);
- }
- // pass it to our generic handlers
- else
- return PsychicHttpServer::requestHandler(req);
- } else
- return request.reply(500, "text/html", "No handler registered.");
+ if (err == HTTPD_404_NOT_FOUND)
+ return PsychicHttpServer::requestHandler(req);
+
+ if (err == ESP_ERR_HTTPD_INVALID_REQ)
+ return response.error(HTTPD_500_INTERNAL_SERVER_ERROR, "No handler registered.");
+
+ return err;
}
bool PsychicEndpoint::matches(const char* uri)
@@ -114,14 +108,33 @@ void PsychicEndpoint::setURIMatchFunction(httpd_uri_match_func_t match_fn)
_uri_match_fn = match_fn;
}
-PsychicEndpoint* PsychicEndpoint::setFilter(PsychicRequestFilterFunction fn)
+PsychicEndpoint* PsychicEndpoint::addFilter(PsychicRequestFilterFunction fn)
+{
+ _handler->addFilter(fn);
+ return this;
+}
+
+PsychicEndpoint* PsychicEndpoint::addMiddleware(PsychicMiddleware* middleware)
{
- _handler->setFilter(fn);
+ _handler->addMiddleware(middleware);
return this;
}
-PsychicEndpoint* PsychicEndpoint::setAuthentication(const char* username, const char* password, HTTPAuthMethod method, const char* realm, const char* authFailMsg)
+PsychicEndpoint* PsychicEndpoint::addMiddleware(PsychicMiddlewareFunction fn)
{
- _handler->setAuthentication(username, password, method, realm, authFailMsg);
+ _handler->addMiddleware(fn);
return this;
-};
\ No newline at end of file
+}
+
+bool PsychicEndpoint::removeMiddleware(PsychicMiddleware* middleware)
+{
+ return _handler->removeMiddleware(middleware);
+}
+
+esp_err_t PsychicEndpoint::process(PsychicRequest* request, PsychicResponse* response)
+{
+ if (_handler == NULL)
+ return ESP_ERR_HTTPD_INVALID_REQ;
+
+ return _handler->process(request, response);
+}
diff --git a/src/PsychicEndpoint.h b/src/PsychicEndpoint.h
index b729eed..6811621 100644
--- a/src/PsychicEndpoint.h
+++ b/src/PsychicEndpoint.h
@@ -4,6 +4,7 @@
#include "PsychicCore.h"
class PsychicHandler;
+class PsychicMiddleware;
#ifdef ENABLE_ASYNC
#include "async_worker.h"
@@ -32,8 +33,14 @@ class PsychicEndpoint
bool matches(const char* uri);
- PsychicEndpoint* setFilter(PsychicRequestFilterFunction fn);
- PsychicEndpoint* setAuthentication(const char* username, const char* password, HTTPAuthMethod method = BASIC_AUTH, const char* realm = "", const char* authFailMsg = "");
+ // called to process this endpoint with its middleware chain
+ esp_err_t process(PsychicRequest* request, PsychicResponse* response);
+
+ PsychicEndpoint* addFilter(PsychicRequestFilterFunction fn);
+
+ PsychicEndpoint* addMiddleware(PsychicMiddleware* middleware);
+ PsychicEndpoint* addMiddleware(PsychicMiddlewareFunction fn);
+ bool removeMiddleware(PsychicMiddleware* middleware);
String uri();
diff --git a/src/PsychicEventSource.cpp b/src/PsychicEventSource.cpp
index b7b0441..d6b9e83 100644
--- a/src/PsychicEventSource.cpp
+++ b/src/PsychicEventSource.cpp
@@ -50,10 +50,10 @@ PsychicEventSourceClient* PsychicEventSource::getClient(PsychicClient* client)
return getClient(client->socket());
}
-esp_err_t PsychicEventSource::handleRequest(PsychicRequest* request)
+esp_err_t PsychicEventSource::handleRequest(PsychicRequest* request, PsychicResponse* resp)
{
// start our open ended HTTP response
- PsychicEventSourceResponse response(request);
+ PsychicEventSourceResponse response(resp);
esp_err_t err = response.send();
// lookup our client
@@ -234,8 +234,7 @@ void PsychicEventSourceClient::_sendEventSentCallback(esp_err_t err, int socket,
// PsychicEventSourceResponse
/*****************************************/
-PsychicEventSourceResponse::PsychicEventSourceResponse(PsychicRequest* request)
- : PsychicResponse(request)
+PsychicEventSourceResponse::PsychicEventSourceResponse(PsychicResponse* response) : _response(response)
{
}
@@ -258,7 +257,7 @@ esp_err_t PsychicEventSourceResponse::send()
int result;
do {
- result = httpd_send(_request->request(), out.c_str(), out.length());
+ result = httpd_send(_response->request(), out.c_str(), out.length());
} while (result == HTTPD_SOCK_ERR_TIMEOUT);
if (result < 0)
diff --git a/src/PsychicEventSource.h b/src/PsychicEventSource.h
index 0f8a67f..b55cfb6 100644
--- a/src/PsychicEventSource.h
+++ b/src/PsychicEventSource.h
@@ -80,16 +80,19 @@ class PsychicEventSource : public PsychicHandler
PsychicEventSource* onOpen(PsychicEventSourceClientCallback fn);
PsychicEventSource* onClose(PsychicEventSourceClientCallback fn);
- esp_err_t handleRequest(PsychicRequest* request) override final;
+ esp_err_t handleRequest(PsychicRequest* request, PsychicResponse* response) override final;
void send(const char* message, const char* event = NULL, uint32_t id = 0, uint32_t reconnect = 0);
};
-class PsychicEventSourceResponse : public PsychicResponse
+class PsychicEventSourceResponse
{
+ protected:
+ PsychicResponse* _response;
+
public:
- PsychicEventSourceResponse(PsychicRequest* request);
- virtual esp_err_t send() override;
+ PsychicEventSourceResponse(PsychicResponse* response);
+ esp_err_t send();
};
String generateEventMessage(const char* message, const char* event, uint32_t id, uint32_t reconnect);
diff --git a/src/PsychicHandler.cpp b/src/PsychicHandler.cpp
index 001c254..f1c4eab 100644
--- a/src/PsychicHandler.cpp
+++ b/src/PsychicHandler.cpp
@@ -1,24 +1,21 @@
#include "PsychicHandler.h"
PsychicHandler::PsychicHandler() : _server(NULL),
- _username(""),
- _password(""),
- _method(DIGEST_AUTH),
- _realm(""),
- _authFailMsg(""),
+ _chain(new PsychicMiddlewareChain()),
_subprotocol("")
{
}
PsychicHandler::~PsychicHandler()
{
+ delete _chain;
// actual PsychicClient deletion handled by PsychicServer
// for (PsychicClient *client : _clients)
// delete(client);
_clients.clear();
}
-PsychicHandler* PsychicHandler::setFilter(PsychicRequestFilterFunction fn)
+PsychicHandler* PsychicHandler::addFilter(PsychicRequestFilterFunction fn)
{
_filters.push_back(fn);
return this;
@@ -44,26 +41,6 @@ const char* PsychicHandler::getSubprotocol() const
return _subprotocol.c_str();
}
-PsychicHandler* PsychicHandler::setAuthentication(const char* username, const char* password, HTTPAuthMethod method, const char* realm, const char* authFailMsg)
-{
- _username = String(username);
- _password = String(password);
- _method = method;
- _realm = String(realm);
- _authFailMsg = String(authFailMsg);
- return this;
-};
-
-bool PsychicHandler::needsAuthentication(PsychicRequest* request)
-{
- return (_username != "" && _password != "") && !request->authenticate(_username.c_str(), _password.c_str());
-}
-
-esp_err_t PsychicHandler::authenticate(PsychicRequest* request)
-{
- return request->requestAuthentication(_method, _realm.c_str(), _authFailMsg.c_str());
-}
-
PsychicClient* PsychicHandler::checkForNewClient(PsychicClient* client)
{
PsychicClient* c = PsychicHandler::getClient(client);
@@ -125,7 +102,7 @@ const std::list& PsychicHandler::getClientList()
return _clients;
}
-PsychicHandler* PsychicHandler::addMiddleware(PsychicMiddleware *middleware)
+PsychicHandler* PsychicHandler::addMiddleware(PsychicMiddleware* middleware)
{
_chain->add(middleware);
return this;
@@ -133,12 +110,22 @@ PsychicHandler* PsychicHandler::addMiddleware(PsychicMiddleware *middleware)
PsychicHandler* PsychicHandler::addMiddleware(PsychicMiddlewareFunction fn)
{
- PsychicMiddleware *mw = new PsychicMiddleware(fn);
- _chain->add(mw);
+ _chain->add(fn);
return this;
}
-bool PsychicHandler::runMiddleware(PsychicRequest* request, PsychicResponse* response)
+bool PsychicHandler::removeMiddleware(PsychicMiddleware* middleware)
{
- return _chain->run(request, response);
+ return _chain->remove(middleware);
+}
+
+esp_err_t PsychicHandler::process(PsychicRequest* request, PsychicResponse* response)
+{
+ if (!filter(request))
+ return HTTPD_404_NOT_FOUND;
+
+ if (!canHandle(request))
+ return HTTPD_404_NOT_FOUND;
+
+ return _chain->run(request, response, std::bind(&PsychicHandler::handleRequest, this, std::placeholders::_1, std::placeholders::_2));
}
\ No newline at end of file
diff --git a/src/PsychicHandler.h b/src/PsychicHandler.h
index c3e4363..702462c 100644
--- a/src/PsychicHandler.h
+++ b/src/PsychicHandler.h
@@ -3,11 +3,11 @@
#include "PsychicCore.h"
#include "PsychicRequest.h"
-#include "PsychicMiddleware.h"
-#include "PsychicMiddlewareChain.h"
class PsychicEndpoint;
class PsychicHttpServer;
+class PsychicMiddleware;
+class PsychicMiddlewareChain;
/*
* HANDLER :: Can be attached to any endpoint or as a generic request handler.
@@ -18,15 +18,9 @@ class PsychicHandler
friend PsychicEndpoint;
protected:
- std::list _filters;
- PsychicMiddlewareChain* _chain;
PsychicHttpServer* _server;
-
- String _username;
- String _password;
- HTTPAuthMethod _method;
- String _realm;
- String _authFailMsg;
+ PsychicMiddlewareChain* _chain;
+ std::list _filters;
String _subprotocol;
@@ -36,10 +30,6 @@ class PsychicHandler
PsychicHandler();
virtual ~PsychicHandler();
- PsychicHandler* setAuthentication(const char* username, const char* password, HTTPAuthMethod method = BASIC_AUTH, const char* realm = "", const char* authFailMsg = "");
- bool needsAuthentication(PsychicRequest* request);
- esp_err_t authenticate(PsychicRequest* request);
-
virtual bool isWebSocket() { return false; };
void setSubprotocol(const String& subprotocol);
@@ -59,16 +49,20 @@ class PsychicHandler
int count() { return _clients.size(); };
const std::list& getClientList();
- PsychicHandler* setFilter(PsychicRequestFilterFunction fn);
+ // called to process this handler with its middleware chain and filers
+ esp_err_t process(PsychicRequest* request, PsychicResponse* response);
+
+ //bool filter(PsychicRequest* request);
+ PsychicHandler* addFilter(PsychicRequestFilterFunction fn);
bool filter(PsychicRequest* request);
PsychicHandler* addMiddleware(PsychicMiddleware* middleware);
PsychicHandler* addMiddleware(PsychicMiddlewareFunction fn);
- bool runMiddleware(PsychicRequest* request, PsychicResponse* response);
+ bool removeMiddleware(PsychicMiddleware *middleware);
// derived classes must implement these functions
virtual bool canHandle(PsychicRequest* request) { return true; };
- virtual esp_err_t handleRequest(PsychicRequest* request) = 0;
+ virtual esp_err_t handleRequest(PsychicRequest* request, PsychicResponse* response) { return HTTPD_404_NOT_FOUND; };
};
#endif
\ No newline at end of file
diff --git a/src/PsychicHttp.h b/src/PsychicHttp.h
index 91f80ff..dca1e5a 100644
--- a/src/PsychicHttp.h
+++ b/src/PsychicHttp.h
@@ -19,6 +19,7 @@
#include "PsychicUploadHandler.h"
#include "PsychicWebSocket.h"
#include
+#include "PsychicMiddlewares.h"
#ifdef ENABLE_ASYNC
#include "async_worker.h"
diff --git a/src/PsychicHttpServer.cpp b/src/PsychicHttpServer.cpp
index 71b5834..3fc1260 100644
--- a/src/PsychicHttpServer.cpp
+++ b/src/PsychicHttpServer.cpp
@@ -11,7 +11,8 @@
#endif
PsychicHttpServer::PsychicHttpServer(uint16_t port) : _onOpen(NULL),
- _onClose(NULL)
+ _onClose(NULL),
+ _chain(new PsychicMiddlewareChain())
{
maxRequestBodySize = MAX_REQUEST_BODY_SIZE;
maxUploadSize = MAX_UPLOAD_SIZE;
@@ -65,6 +66,7 @@ PsychicHttpServer::~PsychicHttpServer()
_rewrites.clear();
delete defaultEndpoint;
+ delete _chain;
}
void PsychicHttpServer::destroy(void* ctx)
@@ -379,14 +381,14 @@ bool PsychicHttpServer::removeEndpoint(PsychicEndpoint* endpoint)
return true;
}
-PsychicHttpServer* PsychicHttpServer::setFilter(PsychicRequestFilterFunction fn)
+PsychicHttpServer* PsychicHttpServer::addFilter(PsychicRequestFilterFunction fn)
{
_filters.push_back(fn);
return this;
}
-bool PsychicHttpServer::filter(PsychicRequest* request)
+bool PsychicHttpServer::_filter(PsychicRequest* request)
{
// run through our filter chain.
for (auto& filter : _filters) {
@@ -405,14 +407,13 @@ PsychicHttpServer* PsychicHttpServer::addMiddleware(PsychicMiddleware *middlewar
PsychicHttpServer* PsychicHttpServer::addMiddleware(PsychicMiddlewareFunction fn)
{
- PsychicMiddleware *mw = new PsychicMiddleware(fn);
- _chain->add(mw);
+ _chain->add(fn);
return this;
}
-bool PsychicHttpServer::runMiddleware(PsychicRequest* request, PsychicResponse* response)
+bool PsychicHttpServer::removeMiddleware(PsychicMiddleware* middleware)
{
- return _chain->run(request, response);
+ return _chain->remove(middleware);
}
void PsychicHttpServer::onNotFound(PsychicHttpRequestCallback fn)
@@ -445,64 +446,65 @@ esp_err_t PsychicHttpServer::requestHandler(httpd_req_t* req)
server->_rewriteRequest(&request);
// run it through our global server filter list
- if (!server->filter(&request))
- return request.reply(400);
+ if(!server->_filter(&request))
+ return response.send(400);
- // run it through our global server middleware.
- // false means the chain didnt complete and a response was sent.
- if (!server->runMiddleware(&request, &response))
- return ESP_OK;
+ // 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));
+
+ if (ret == HTTPD_404_NOT_FOUND) {
+ return PsychicHttpServer::notFoundHandler(req, HTTPD_404_NOT_FOUND);
+ }
+ return ret;
+}
+
+esp_err_t PsychicHttpServer::_process(PsychicRequest* request, PsychicResponse* response)
+{
// loop through our endpoints and see if anyone wants it.
- for (auto* endpoint : server->_endpoints) {
- if (endpoint->matches(request.uri().c_str())) {
- if (endpoint->_method == request.method() || endpoint->_method == HTTP_ANY) {
- request.setEndpoint(endpoint);
+ for (auto* endpoint : _endpoints) {
+ if (endpoint->matches(request->uri().c_str())) {
+ if (endpoint->_method == request->method() || endpoint->_method == HTTP_ANY) {
+ request->setEndpoint(endpoint);
PsychicHandler* handler = endpoint->handler();
- if (handler->filter(&request)) {
- if (handler->runMiddleware(&request, &response))
- return handler->handleRequest(&request);
- else
- return ESP_OK;
- }
+ return handler->process(request, response);
}
}
}
// loop through our global handlers and see if anyone wants it
- for (auto* handler : server->_handlers) {
- if (handler->filter(&request)) {
- if (handler->runMiddleware(&request, &response))
- return handler->handleRequest(&request);
- else
- return ESP_OK;
- }
+ for (auto* handler : _handlers) {
+ esp_err_t ret = handler->process(request, response);
+ if (ret != HTTPD_404_NOT_FOUND)
+ return ret;
}
- //if nothing hits, then try our 404 handler.
- return PsychicHttpServer::notFoundHandler(req, HTTPD_404_NOT_FOUND);
+ return HTTPD_404_NOT_FOUND;
}
esp_err_t PsychicHttpServer::notFoundHandler(httpd_req_t* req, httpd_err_code_t err)
{
PsychicHttpServer* server = (PsychicHttpServer*)httpd_get_global_user_ctx(req->handle);
PsychicRequest request(server, req);
+ PsychicResponse response(&request);
// pull up our default handler / endpoint
PsychicHandler* handler = server->defaultEndpoint->handler();
- if (handler->filter(&request) && handler->canHandle(&request))
- return handler->handleRequest(&request);
+ if (!handler)
+ return response.send(404);
+
+ esp_err_t ret = handler->process(&request, &response);
+ if (ret != HTTPD_404_NOT_FOUND)
+ return ret;
// not sure how we got this far.
- return ESP_ERR_HTTPD_INVALID_REQ;
+ return response.send(404);
}
-esp_err_t PsychicHttpServer::defaultNotFoundHandler(PsychicRequest* request)
+esp_err_t PsychicHttpServer::defaultNotFoundHandler(PsychicRequest* request, PsychicResponse* response)
{
- request->reply(404, "text/html", "That URI does not exist.");
-
- return ESP_OK;
+ return response->send(404, "text/html", "That URI does not exist.");
}
void PsychicHttpServer::onOpen(PsychicClientCallback handler)
diff --git a/src/PsychicHttpServer.h b/src/PsychicHttpServer.h
index ed08f45..72155d7 100644
--- a/src/PsychicHttpServer.h
+++ b/src/PsychicHttpServer.h
@@ -4,6 +4,8 @@
#include "PsychicClient.h"
#include "PsychicCore.h"
#include "PsychicHandler.h"
+#include "PsychicMiddleware.h"
+#include "PsychicMiddlewareChain.h"
#include "PsychicRewrite.h"
#ifdef PSY_ENABLE_REGEX
@@ -17,8 +19,6 @@ enum PsychicHttpMethod {
class PsychicEndpoint;
class PsychicHandler;
class PsychicStaticFileHandler;
-class PsychicMiddleware;
-class PsychicMiddlewareChain;
class PsychicHttpServer
{
@@ -29,10 +29,10 @@ class PsychicHttpServer
std::list _clients;
std::list _rewrites;
std::list _filters;
- PsychicMiddlewareChain* _chain;
PsychicClientCallback _onOpen;
PsychicClientCallback _onClose;
+ PsychicMiddlewareChain* _chain;
esp_err_t _start();
virtual esp_err_t _startServer();
@@ -41,6 +41,8 @@ class PsychicHttpServer
httpd_uri_match_func_t _uri_match_fn = nullptr;
bool _rewriteRequest(PsychicRequest* request);
+ esp_err_t _process(PsychicRequest* request, PsychicResponse* response);
+ bool _filter(PsychicRequest* request);
public:
PsychicHttpServer(uint16_t port = 80);
@@ -101,16 +103,15 @@ class PsychicHttpServer
bool removeEndpoint(const char* uri, int method);
bool removeEndpoint(PsychicEndpoint* endpoint);
- PsychicHttpServer* setFilter(PsychicRequestFilterFunction fn);
- bool filter(PsychicRequest* request);
+ PsychicHttpServer* addFilter(PsychicRequestFilterFunction fn);
PsychicHttpServer* addMiddleware(PsychicMiddleware* middleware);
PsychicHttpServer* addMiddleware(PsychicMiddlewareFunction fn);
- bool runMiddleware(PsychicRequest* request, PsychicResponse* response);
+ bool 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);
- static esp_err_t defaultNotFoundHandler(PsychicRequest* request);
+ static esp_err_t defaultNotFoundHandler(PsychicRequest* request, PsychicResponse* response);
static esp_err_t openCallback(httpd_handle_t hd, int sockfd);
static void closeCallback(httpd_handle_t hd, int sockfd);
diff --git a/src/PsychicJson.cpp b/src/PsychicJson.cpp
index 2f58607..cc68bff 100644
--- a/src/PsychicJson.cpp
+++ b/src/PsychicJson.cpp
@@ -1,19 +1,19 @@
#include "PsychicJson.h"
#ifdef ARDUINOJSON_6_COMPATIBILITY
-PsychicJsonResponse::PsychicJsonResponse(PsychicRequest* request, bool isArray, size_t maxJsonBufferSize) : PsychicResponse(request),
- _jsonBuffer(maxJsonBufferSize)
+PsychicJsonResponse::PsychicJsonResponse(PsychicResponse* response, bool isArray, size_t maxJsonBufferSize) : __response(response),
+ _jsonBuffer(maxJsonBufferSize)
{
- setContentType(JSON_MIMETYPE);
+ response->setContentType(JSON_MIMETYPE);
if (isArray)
_root = _jsonBuffer.createNestedArray();
else
_root = _jsonBuffer.createNestedObject();
}
#else
-PsychicJsonResponse::PsychicJsonResponse(PsychicRequest* request, bool isArray) : PsychicResponse(request)
+PsychicJsonResponse::PsychicJsonResponse(PsychicResponse* response, bool isArray) : _response(response)
{
- setContentType(JSON_MIMETYPE);
+ _response->setContentType(JSON_MIMETYPE);
if (isArray)
_root = _jsonBuffer.add();
else
@@ -45,29 +45,24 @@ esp_err_t PsychicJsonResponse::send()
buffer_size = JSON_BUFFER_SIZE;
buffer = (char*)malloc(buffer_size);
- if (buffer == NULL)
- {
- httpd_resp_send_err(this->_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory.");
- return ESP_FAIL;
+ if (buffer == NULL) {
+ return _response->error(HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory.");
}
// send it in one shot or no?
- if (length < JSON_BUFFER_SIZE)
- {
+ if (length < JSON_BUFFER_SIZE) {
serializeJson(_root, buffer, buffer_size);
- this->setContent((uint8_t*)buffer, length);
- this->setContentType(JSON_MIMETYPE);
+ _response->setContent((uint8_t*)buffer, length);
+ _response->setContentType(JSON_MIMETYPE);
- err = PsychicResponse::send();
- }
- else
- {
+ err = _response->send();
+ } else {
// helper class that acts as a stream to print chunked responses
- ChunkPrinter dest(this, (uint8_t*)buffer, buffer_size);
+ ChunkPrinter dest(_response, (uint8_t*)buffer, buffer_size);
// keep our headers
- this->sendHeaders();
+ _response->sendHeaders();
serializeJson(_root, dest);
@@ -75,7 +70,7 @@ esp_err_t PsychicJsonResponse::send()
dest.flush();
// done with our chunked response too
- err = this->finishChunking();
+ err = _response->finishChunking();
}
// let the buffer go
@@ -86,14 +81,14 @@ esp_err_t PsychicJsonResponse::send()
#ifdef ARDUINOJSON_6_COMPATIBILITY
PsychicJsonHandler::PsychicJsonHandler(size_t maxJsonBufferSize) : _onRequest(NULL),
- _maxJsonBufferSize(maxJsonBufferSize){};
+ _maxJsonBufferSize(maxJsonBufferSize) {};
PsychicJsonHandler::PsychicJsonHandler(PsychicJsonRequestCallback onRequest, size_t maxJsonBufferSize) : _onRequest(onRequest),
_maxJsonBufferSize(maxJsonBufferSize)
{
}
#else
-PsychicJsonHandler::PsychicJsonHandler() : _onRequest(NULL){};
+PsychicJsonHandler::PsychicJsonHandler() : _onRequest(NULL) {};
PsychicJsonHandler::PsychicJsonHandler(PsychicJsonRequestCallback onRequest) : _onRequest(onRequest)
{
@@ -105,31 +100,29 @@ void PsychicJsonHandler::onRequest(PsychicJsonRequestCallback fn)
_onRequest = fn;
}
-esp_err_t PsychicJsonHandler::handleRequest(PsychicRequest* request)
+esp_err_t PsychicJsonHandler::handleRequest(PsychicRequest* request, PsychicResponse* response)
{
// process basic stuff
- PsychicWebHandler::handleRequest(request);
+ PsychicWebHandler::handleRequest(request, response);
- if (_onRequest)
- {
+ if (_onRequest) {
#ifdef ARDUINOJSON_6_COMPATIBILITY
DynamicJsonDocument jsonBuffer(this->_maxJsonBufferSize);
DeserializationError error = deserializeJson(jsonBuffer, request->body());
if (error)
- return request->reply(400);
+ return response->send(400);
JsonVariant json = jsonBuffer.as();
#else
JsonDocument jsonBuffer;
DeserializationError error = deserializeJson(jsonBuffer, request->body());
if (error)
- return request->reply(400);
+ return response->send(400);
JsonVariant json = jsonBuffer.as();
#endif
- return _onRequest(request, json);
- }
- else
- return request->reply(500);
+ return _onRequest(request, response, json);
+ } else
+ return response->send(500);
}
\ No newline at end of file
diff --git a/src/PsychicJson.h b/src/PsychicJson.h
index 5698909..ee2455c 100644
--- a/src/PsychicJson.h
+++ b/src/PsychicJson.h
@@ -30,7 +30,7 @@ constexpr const char* JSON_MIMETYPE = "application/json";
* Json Response
* */
-class PsychicJsonResponse : public PsychicResponse
+class PsychicJsonResponse
{
protected:
#ifdef ARDUINOJSON_5_COMPATIBILITY
@@ -41,16 +41,17 @@ class PsychicJsonResponse : public PsychicResponse
JsonDocument _jsonBuffer;
#endif
+ PsychicResponse* _response;
JsonVariant _root;
size_t _contentLength;
public:
#ifdef ARDUINOJSON_5_COMPATIBILITY
- PsychicJsonResponse(PsychicRequest* request, bool isArray = false);
+ PsychicJsonResponse(PsychicResponse* response, bool isArray = false);
#elif ARDUINOJSON_VERSION_MAJOR == 6
- PsychicJsonResponse(PsychicRequest* request, bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE);
+ PsychicJsonResponse(PsychicResponse* response, bool isArray = false, size_t maxJsonBufferSize = DYNAMIC_JSON_DOCUMENT_SIZE);
#else
- PsychicJsonResponse(PsychicRequest* request, bool isArray = false);
+ PsychicJsonResponse(PsychicResponse* response, bool isArray = false);
#endif
~PsychicJsonResponse()
@@ -60,7 +61,7 @@ class PsychicJsonResponse : public PsychicResponse
JsonVariant& getRoot();
size_t getLength();
- virtual esp_err_t send() override;
+ esp_err_t send();
};
class PsychicJsonHandler : public PsychicWebHandler
@@ -84,7 +85,7 @@ class PsychicJsonHandler : public PsychicWebHandler
#endif
void onRequest(PsychicJsonRequestCallback fn);
- virtual esp_err_t handleRequest(PsychicRequest* request) override;
+ virtual esp_err_t handleRequest(PsychicRequest* request, PsychicResponse* response) override;
};
#endif
\ No newline at end of file
diff --git a/src/PsychicMiddleware.cpp b/src/PsychicMiddleware.cpp
index 18ff663..7aeff91 100644
--- a/src/PsychicMiddleware.cpp
+++ b/src/PsychicMiddleware.cpp
@@ -3,15 +3,11 @@
#include "PsychicRequest.h"
#include "PsychicResponse.h"
-PsychicMiddleware::PsychicMiddleware(PsychicMiddlewareFunction callback) :
- _callback(callback)
- {
- }
-
-PsychicMiddleware::~PsychicMiddleware() {}
-
-void PsychicMiddleware::run(PsychicMiddlewareChain *chain, PsychicRequest *request, PsychicResponse *response)
+PsychicMiddlewareClosure::PsychicMiddlewareClosure(PsychicMiddlewareFunction fn) : _fn(fn)
+{
+ assert(_fn);
+}
+esp_err_t PsychicMiddlewareClosure::run(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response)
{
- if (_callback)
- _callback(chain, request, response);
+ return _fn(next, request, response);
}
\ No newline at end of file
diff --git a/src/PsychicMiddleware.h b/src/PsychicMiddleware.h
index 46f9815..2af5520 100644
--- a/src/PsychicMiddleware.h
+++ b/src/PsychicMiddleware.h
@@ -4,22 +4,26 @@
#include "PsychicCore.h"
#include "PsychicRequest.h"
#include "PsychicResponse.h"
-#include "PsychicMiddlewareChain.h"
/*
* PsychicMiddleware :: fancy callback wrapper for handling requests and responses.
* */
-class PsychicMiddleware {
+class PsychicMiddleware
+{
public:
- //void *_context;
- String _name;
- PsychicMiddlewareFunction _callback;
+ virtual ~PsychicMiddleware() {}
+ virtual esp_err_t run(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response) = 0;
+};
- PsychicMiddleware(PsychicMiddlewareFunction middleware);
- virtual ~PsychicMiddleware();
+class PsychicMiddlewareClosure : public PsychicMiddleware
+{
+ protected:
+ PsychicMiddlewareFunction _fn;
- void run(PsychicMiddlewareChain *chain, PsychicRequest *request, PsychicResponse *response);
+ public:
+ PsychicMiddlewareClosure(PsychicMiddlewareFunction fn);
+ esp_err_t run(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response) override;
};
#endif
\ No newline at end of file
diff --git a/src/PsychicMiddlewareChain.cpp b/src/PsychicMiddlewareChain.cpp
index ff5f048..7139e16 100644
--- a/src/PsychicMiddlewareChain.cpp
+++ b/src/PsychicMiddlewareChain.cpp
@@ -1,52 +1,47 @@
#include "PsychicMiddlewareChain.h"
-PsychicMiddlewareChain::PsychicMiddlewareChain() :
- _request(nullptr),
- _response(nullptr)
- {
- }
+PsychicMiddlewareChain::PsychicMiddlewareChain() {}
-//TODO: memory management
-PsychicMiddlewareChain::~PsychicMiddlewareChain() {}
+PsychicMiddlewareChain::~PsychicMiddlewareChain()
+{
+ for (auto middleware : _middleware) {
+ delete middleware;
+ }
+ _middleware.clear();
+}
-void PsychicMiddlewareChain::add(PsychicMiddleware *middleware)
+void PsychicMiddlewareChain::add(PsychicMiddleware* middleware)
{
_middleware.push_back(middleware);
}
-bool PsychicMiddlewareChain::run(PsychicRequest *request, PsychicResponse *response)
+void PsychicMiddlewareChain::add(PsychicMiddlewareFunction fn)
{
- //save our in/out objects
- _request = request;
- _response = response;
- _finished = false;
-
- //start at the beginning.
- auto _iterator = _middleware.begin();
-
- //is it valid?
- if (_iterator != _middleware.end())
- {
- PsychicMiddleware* mw = *_iterator;
- mw->run(this, _request, _response);
- }
+ _middleware.push_back(new PsychicMiddlewareClosure(fn));
+}
- //let them know if we finished or not.
- return _finished;
+bool PsychicMiddlewareChain::remove(PsychicMiddleware* middleware)
+{
+ _middleware.remove(middleware);
+ return true;
}
-void PsychicMiddlewareChain::next()
+esp_err_t PsychicMiddlewareChain::run(PsychicRequest* request, PsychicResponse* response, PsychicMiddlewareCallback finalizer)
{
- //get the next one!
- _iterator++;
-
- //is there a next one?
- if (_iterator != _middleware.end())
- {
- PsychicMiddleware* mw = *_iterator;
- mw->run(this, _request, _response);
+ if (_middleware.size() == 0) {
+ return finalizer(request, response);
}
- //nope, we're done.
- else
- _finished = true;
+
+ PsychicMiddlewareCallback next;
+ std::list::iterator it = _middleware.begin();
+
+ next = [this, &next, &it, finalizer](PsychicRequest* request, PsychicResponse* response) {
+ if (it != _middleware.end()) {
+ return (*it++)->run(next, request, response);
+ } else {
+ return finalizer(request, response);
+ }
+ };
+
+ return (*it)->run(next, request, response);
}
\ No newline at end of file
diff --git a/src/PsychicMiddlewareChain.h b/src/PsychicMiddlewareChain.h
index a3702ae..f24373b 100644
--- a/src/PsychicMiddlewareChain.h
+++ b/src/PsychicMiddlewareChain.h
@@ -6,27 +6,24 @@
#include "PsychicResponse.h"
#include "PsychicMiddleware.h"
-class PsychicMiddleware;
-
/*
* PsychicMiddlewareChain - handle tracking and executing our chain of middleware objects
* */
-class PsychicMiddlewareChain {
+class PsychicMiddlewareChain
+{
protected:
std::list _middleware;
- std::list::iterator _iterator;
- PsychicRequest* _request;
- PsychicResponse* _response;
- boolean _finished = false;
public:
PsychicMiddlewareChain();
virtual ~PsychicMiddlewareChain();
void add(PsychicMiddleware* middleware);
- bool run(PsychicRequest *request, PsychicResponse *response);
- void next();
+ void add(PsychicMiddlewareFunction fn);
+ bool remove(PsychicMiddleware* middleware);
+
+ esp_err_t run(PsychicRequest* request, PsychicResponse* response, PsychicMiddlewareCallback finalizer);
};
#endif
\ No newline at end of file
diff --git a/src/PsychicMiddlewares.h b/src/PsychicMiddlewares.h
new file mode 100644
index 0000000..494af38
--- /dev/null
+++ b/src/PsychicMiddlewares.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#include "PsychicMiddleware.h"
+
+class AuthcMiddleware : public PsychicMiddleware
+{
+ protected:
+ String _username;
+ String _password;
+ HTTPAuthMethod _method;
+ String _realm;
+ String _authFailMsg;
+ bool _authc = false;
+
+ public:
+ AuthcMiddleware(const char* username, const char* password, HTTPAuthMethod method = BASIC_AUTH, const char* realm = "", const char* authFailMsg = "")
+ : _username(username), _password(password), _method(method), _realm(realm), _authFailMsg(authFailMsg), _authc(!_username.isEmpty() && !_password.isEmpty()) {}
+
+ esp_err_t run(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response) override
+ {
+ if (_authc && !request->authenticate(_username.c_str(), _password.c_str())) {
+ return request->requestAuthentication(_method, _realm.c_str(), _authFailMsg.c_str());
+ }
+ return next(request, response);
+ }
+};
+
+class PermissiveCorsMiddleware : public PsychicMiddleware
+{
+ public:
+ esp_err_t run(PsychicMiddlewareCallback next, PsychicRequest* request, PsychicResponse* response) override
+ {
+ // gives the chance to other most important middleware to run first
+ esp_err_t ret = next(request, response);
+ // add CORS headers
+ if (ret == ESP_OK && request->hasHeader("Origin")) {
+ response->addHeader("Access-Control-Allow-Origin", "*");
+ response->addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
+ response->addHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
+ response->addHeader("Access-Control-Max-Age", "86400");
+ }
+ return ret;
+ }
+};
diff --git a/src/PsychicRequest.cpp b/src/PsychicRequest.cpp
index 3715648..f1fc89f 100644
--- a/src/PsychicRequest.cpp
+++ b/src/PsychicRequest.cpp
@@ -272,15 +272,6 @@ bool PsychicRequest::isMultipart()
return (this->contentType().indexOf("multipart/form-data") >= 0);
}
-esp_err_t PsychicRequest::redirect(const char* url)
-{
- PsychicResponse response(this);
- response.setCode(301);
- response.addHeader("Location", url);
-
- return response.send();
-}
-
bool PsychicRequest::hasCookie(const char* key, size_t* size)
{
char buffer;
@@ -602,87 +593,3 @@ esp_err_t PsychicRequest::requestAuthentication(HTTPAuthMethod mode, const char*
response.setContent(authStr.c_str());
return response.send();
}
-
-esp_err_t PsychicRequest::reply(int code)
-{
- PsychicResponse response(this);
-
- response.setCode(code);
- response.setContentType("text/plain");
- response.setContent(http_status_reason(code));
-
- return response.send();
-}
-
-esp_err_t PsychicRequest::reply(const char* content)
-{
- PsychicResponse response(this);
-
- response.setCode(200);
- response.setContentType("text/html");
- response.setContent(content);
-
- return response.send();
-}
-
-esp_err_t PsychicRequest::reply(int code, const char* contentType, const char* content)
-{
- PsychicResponse response(this);
-
- response.setCode(code);
- response.setContentType(contentType);
- response.setContent(content);
-
- return response.send();
-}
-
-esp_err_t PsychicRequest::reply(int code, const char* contentType, const uint8_t* content, size_t len)
-{
- PsychicResponse response(this);
-
- response.setCode(code);
- response.setContentType(contentType);
- response.setContent(content, len);
-
- return response.send();
-}
-
-esp_err_t PsychicRequest::reply(PsychicResponse* response)
-{
- esp_err_t err = response->send();
- delete response;
- return err;
-}
-
-PsychicResponse* PsychicRequest::beginReply(int code)
-{
- PsychicResponse* response = new PsychicResponse(this);
- response->setCode(code);
- return response;
-}
-
-PsychicResponse* PsychicRequest::beginReply(int code, const char* contentType)
-{
- PsychicResponse* response = new PsychicResponse(this);
- response->setCode(code);
- response->setContentType(contentType);
- return response;
-}
-
-PsychicResponse* PsychicRequest::beginReply(int code, const char* contentType, const char* content)
-{
- PsychicResponse* response = new PsychicResponse(this);
- response->setCode(code);
- response->setContentType(contentType);
- response->setContent(content);
- return response;
-}
-
-PsychicResponse* PsychicRequest::beginReply(int code, const char* contentType, const uint8_t* content, size_t len)
-{
- PsychicResponse* response = new PsychicResponse(this);
- response->setCode(code);
- response->setContentType(contentType);
- response->setContent(content, len);
- return response;
-}
diff --git a/src/PsychicRequest.h b/src/PsychicRequest.h
index ba9484b..369cc49 100644
--- a/src/PsychicRequest.h
+++ b/src/PsychicRequest.h
@@ -5,7 +5,6 @@
#include "PsychicCore.h"
#include "PsychicEndpoint.h"
#include "PsychicHttpServer.h"
-#include "PsychicResponse.h"
#include "PsychicWebParameter.h"
#ifdef PSY_ENABLE_REGEX
@@ -137,18 +136,6 @@ class PsychicRequest
bool authenticate(const char* username, const char* password);
esp_err_t requestAuthentication(HTTPAuthMethod mode, const char* realm, const char* authFailMsg);
-
- esp_err_t redirect(const char* url);
- esp_err_t reply(int code);
- esp_err_t reply(const char* content);
- esp_err_t reply(int code, const char* contentType, const char* content);
- esp_err_t reply(int code, const char* contentType, const uint8_t* content, size_t len);
- esp_err_t reply(PsychicResponse* response);
-
- PsychicResponse* beginReply(int code);
- PsychicResponse* beginReply(int code, const char* contentType);
- PsychicResponse* beginReply(int code, const char* contentType, const char* content);
- PsychicResponse* beginReply(int code, const char* contentType, const uint8_t* content, size_t len);
};
#endif // PsychicRequest_h
\ No newline at end of file
diff --git a/src/PsychicResponse.cpp b/src/PsychicResponse.cpp
index 5777998..a64528f 100644
--- a/src/PsychicResponse.cpp
+++ b/src/PsychicResponse.cpp
@@ -5,6 +5,7 @@
PsychicResponse::PsychicResponse(PsychicRequest* request) : _request(request),
_code(200),
_status(""),
+ _contentType(emptyString),
_contentLength(0),
_body("")
{
@@ -72,7 +73,7 @@ void PsychicResponse::setCode(int code)
void PsychicResponse::setContentType(const char* contentType)
{
- httpd_resp_set_type(_request->request(), contentType);
+ _contentType = contentType;
}
void PsychicResponse::setContent(const char* content)
@@ -103,6 +104,9 @@ esp_err_t PsychicResponse::send()
sprintf(_status, "%u %s", _code, http_status_reason(_code));
httpd_resp_set_status(_request->request(), _status);
+ // set the content type
+ httpd_resp_set_type(_request->request(), _contentType.c_str());
+
// our headers too
this->sendHeaders();
@@ -144,4 +148,63 @@ esp_err_t PsychicResponse::finishChunking()
{
/* Respond with an empty chunk to signal HTTP response completion */
return httpd_resp_send_chunk(this->_request->request(), NULL, 0);
-}
\ No newline at end of file
+}
+
+esp_err_t PsychicResponse::redirect(const char* url)
+{
+ if (!_code)
+ setCode(301);
+ addHeader("Location", url);
+ return send();
+}
+
+esp_err_t PsychicResponse::send(int code)
+{
+ setCode(code);
+ return send();
+}
+
+esp_err_t PsychicResponse::send(const char* content)
+{
+ if (!_code)
+ setCode(200);
+ if (_contentType.isEmpty())
+ setContentType("text/html");
+ setContent(content);
+ return send();
+}
+
+esp_err_t PsychicResponse::send(const char* contentType, const char* content)
+{
+ if (!_code)
+ setCode(200);
+ setContentType(contentType);
+ setContent(content);
+ return send();
+}
+
+esp_err_t PsychicResponse::send(int code, const char* contentType, const char* content)
+{
+ setCode(code);
+ setContentType(contentType);
+ setContent(content);
+ return send();
+}
+
+esp_err_t PsychicResponse::send(int code, const char* contentType, const uint8_t* content, size_t len)
+{
+ setCode(code);
+ setContentType(contentType);
+ setContent(content, len);
+ return send();
+}
+
+esp_err_t PsychicResponse::error(httpd_err_code_t code, const char* message)
+{
+ return httpd_resp_send_err(_request->_req, code, message);
+}
+
+httpd_req_t* PsychicResponse::request()
+{
+ return _request->_req;
+}
diff --git a/src/PsychicResponse.h b/src/PsychicResponse.h
index c11dbe5..3f2cefd 100644
--- a/src/PsychicResponse.h
+++ b/src/PsychicResponse.h
@@ -14,6 +14,7 @@ class PsychicResponse
int _code;
char _status[60];
std::list _headers;
+ String _contentType;
int64_t _contentLength;
const char* _body;
@@ -24,6 +25,8 @@ class PsychicResponse
void setCode(int code);
void setContentType(const char* contentType);
+ String& getContentType() { return _contentType; }
+
void setContentLength(int64_t contentLength) { _contentLength = contentLength; }
int64_t getContentLength(int64_t contentLength) { return _contentLength; }
@@ -41,6 +44,18 @@ class PsychicResponse
void sendHeaders();
esp_err_t sendChunk(uint8_t* chunk, size_t chunksize);
esp_err_t finishChunking();
+
+ esp_err_t redirect(const char* url);
+ esp_err_t send(int code);
+ esp_err_t send(const char* content);
+ esp_err_t send(const char* contentType, const char* content);
+ esp_err_t send(int code, const char* contentType, const char* content);
+ esp_err_t send(int code, const char* contentType, const uint8_t* content, size_t len);
+ esp_err_t error(httpd_err_code_t code, const char* message);
+
+ httpd_req_t* request();
};
+
+
#endif // PsychicResponse_h
\ No newline at end of file
diff --git a/src/PsychicStaticFileHander.cpp b/src/PsychicStaticFileHander.cpp
index dae6937..649bcb5 100644
--- a/src/PsychicStaticFileHander.cpp
+++ b/src/PsychicStaticFileHander.cpp
@@ -155,7 +155,7 @@ uint8_t PsychicStaticFileHandler::_countBits(const uint8_t value) const
return n;
}
-esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest* request)
+esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest* request, PsychicResponse* response)
{
if (_file == true)
{
@@ -164,7 +164,7 @@ esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest* request)
if (_last_modified.length() && _last_modified == request->header("If-Modified-Since"))
{
_file.close();
- request->reply(304); // Not modified
+ response->send(304); // Not modified
}
// does our Etag match?
else if (_cache_control.length() && request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag))
@@ -195,7 +195,7 @@ esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest* request)
}
else
{
- return request->reply(404);
+ return response->send(404);
}
return ESP_OK;
diff --git a/src/PsychicStaticFileHandler.h b/src/PsychicStaticFileHandler.h
index c17249e..1cbe5f7 100644
--- a/src/PsychicStaticFileHandler.h
+++ b/src/PsychicStaticFileHandler.h
@@ -33,7 +33,7 @@ class PsychicStaticFileHandler : public PsychicWebHandler
public:
PsychicStaticFileHandler(const char* uri, FS& fs, const char* path, const char* cache_control);
bool canHandle(PsychicRequest* request) override;
- esp_err_t handleRequest(PsychicRequest* request) override;
+ esp_err_t handleRequest(PsychicRequest* request, PsychicResponse* response) override;
PsychicStaticFileHandler* setIsDir(bool isDir);
PsychicStaticFileHandler* setDefaultFile(const char* filename);
PsychicStaticFileHandler* setCacheControl(const char* cache_control);
diff --git a/src/PsychicUploadHandler.cpp b/src/PsychicUploadHandler.cpp
index 9fef9e6..85c50fe 100644
--- a/src/PsychicUploadHandler.cpp
+++ b/src/PsychicUploadHandler.cpp
@@ -10,7 +10,7 @@ bool PsychicUploadHandler::canHandle(PsychicRequest* request)
return true;
}
-esp_err_t PsychicUploadHandler::handleRequest(PsychicRequest* request)
+esp_err_t PsychicUploadHandler::handleRequest(PsychicRequest* request, PsychicResponse* response)
{
esp_err_t err = ESP_OK;
@@ -45,14 +45,14 @@ esp_err_t PsychicUploadHandler::handleRequest(PsychicRequest* request)
if (err == ESP_OK)
{
if (_requestCallback != NULL)
- err = _requestCallback(request);
+ err = _requestCallback(request, response);
else
- err = request->reply("Upload Successful.");
+ err = response->send("Upload Successful.");
}
else if (err == ESP_ERR_HTTPD_INVALID_REQ)
- request->reply(400, "text/html", "No multipart boundary found.");
+ response->send(400, "text/html", "No multipart boundary found.");
else
- request->reply(500, "text/html", "Error processing upload.");
+ response->send(500, "text/html", "Error processing upload.");
return err;
}
diff --git a/src/PsychicUploadHandler.h b/src/PsychicUploadHandler.h
index 8391df1..ef19a19 100644
--- a/src/PsychicUploadHandler.h
+++ b/src/PsychicUploadHandler.h
@@ -24,7 +24,7 @@ class PsychicUploadHandler : public PsychicWebHandler
~PsychicUploadHandler();
bool canHandle(PsychicRequest* request) override;
- esp_err_t handleRequest(PsychicRequest* request) override;
+ esp_err_t handleRequest(PsychicRequest* request, PsychicResponse* response) override;
PsychicUploadHandler* onUpload(PsychicUploadCallback fn);
};
diff --git a/src/PsychicWebHandler.cpp b/src/PsychicWebHandler.cpp
index 65ba597..9bdcaca 100644
--- a/src/PsychicWebHandler.cpp
+++ b/src/PsychicWebHandler.cpp
@@ -13,7 +13,7 @@ bool PsychicWebHandler::canHandle(PsychicRequest* request)
return true;
}
-esp_err_t PsychicWebHandler::handleRequest(PsychicRequest* request)
+esp_err_t PsychicWebHandler::handleRequest(PsychicRequest* request, PsychicResponse* response)
{
// lookup our client
PsychicClient* client = checkForNewClient(request->client());
@@ -28,7 +28,7 @@ esp_err_t PsychicWebHandler::handleRequest(PsychicRequest* request)
/* Respond with 400 Bad Request */
char error[60];
sprintf(error, "Request body must be less than %lu bytes!", request->server()->maxRequestBodySize);
- request->reply(400, "text/html", error);
+ response->send(400, "text/html", error);
/* Return failure to close underlying connection else the incoming file content will keep the socket busy */
return ESP_FAIL;
@@ -37,14 +37,14 @@ esp_err_t PsychicWebHandler::handleRequest(PsychicRequest* request)
// get our body loaded up.
esp_err_t err = request->loadBody();
if (err != ESP_OK)
- return request->reply(400, "text/html", "Error loading request body.");
+ return response->send(400, "text/html", "Error loading request body.");
// load our params in.
request->loadParams();
// okay, pass on to our callback.
if (this->_requestCallback != NULL)
- err = this->_requestCallback(request);
+ err = this->_requestCallback(request, response);
return err;
}
diff --git a/src/PsychicWebHandler.h b/src/PsychicWebHandler.h
index 4dafa9c..db640f7 100644
--- a/src/PsychicWebHandler.h
+++ b/src/PsychicWebHandler.h
@@ -22,7 +22,7 @@ class PsychicWebHandler : public PsychicHandler
~PsychicWebHandler();
virtual bool canHandle(PsychicRequest* request) override;
- virtual esp_err_t handleRequest(PsychicRequest* request) override;
+ virtual esp_err_t handleRequest(PsychicRequest* request, PsychicResponse* response) override;
PsychicWebHandler* onRequest(PsychicHttpRequestCallback fn);
virtual void openCallback(PsychicClient* client);
diff --git a/src/PsychicWebSocket.cpp b/src/PsychicWebSocket.cpp
index cf51d6f..a553f9c 100644
--- a/src/PsychicWebSocket.cpp
+++ b/src/PsychicWebSocket.cpp
@@ -181,7 +181,7 @@ void PsychicWebSocketHandler::closeCallback(PsychicClient* client)
bool PsychicWebSocketHandler::isWebSocket() { return true; }
-esp_err_t PsychicWebSocketHandler::handleRequest(PsychicRequest* request)
+esp_err_t PsychicWebSocketHandler::handleRequest(PsychicRequest* request, PsychicResponse* response)
{
// lookup our client
PsychicClient* client = checkForNewClient(request->client());
diff --git a/src/PsychicWebSocket.h b/src/PsychicWebSocket.h
index 8817c40..a3541f4 100644
--- a/src/PsychicWebSocket.h
+++ b/src/PsychicWebSocket.h
@@ -60,7 +60,7 @@ class PsychicWebSocketHandler : public PsychicHandler
void closeCallback(PsychicClient* client) override;
bool isWebSocket() override final;
- esp_err_t handleRequest(PsychicRequest* request) override;
+ esp_err_t handleRequest(PsychicRequest* request, PsychicResponse* response) override;
PsychicWebSocketHandler* onOpen(PsychicWebSocketClientCallback fn);
PsychicWebSocketHandler* onFrame(PsychicWebSocketFrameCallback fn);