🆚 Updates psychic version to 1.2.1
This commit is contained in:
@@ -34,7 +34,6 @@ size_t ChunkPrinter::write(uint8_t c)
|
|||||||
|
|
||||||
size_t ChunkPrinter::write(const uint8_t *buffer, size_t size)
|
size_t ChunkPrinter::write(const uint8_t *buffer, size_t size)
|
||||||
{
|
{
|
||||||
esp_err_t err;
|
|
||||||
size_t written = 0;
|
size_t written = 0;
|
||||||
|
|
||||||
while (written < size)
|
while (written < size)
|
||||||
|
|||||||
@@ -2,24 +2,21 @@
|
|||||||
#include "PsychicHttpServer.h"
|
#include "PsychicHttpServer.h"
|
||||||
#include <lwip/sockets.h>
|
#include <lwip/sockets.h>
|
||||||
|
|
||||||
PsychicClient::PsychicClient(httpd_handle_t server, int socket) : _server(server),
|
PsychicClient::PsychicClient(httpd_handle_t server, int socket) :
|
||||||
_socket(socket),
|
_server(server),
|
||||||
_friend(NULL),
|
_socket(socket),
|
||||||
isNew(false)
|
_friend(NULL),
|
||||||
{
|
isNew(false)
|
||||||
|
{}
|
||||||
|
|
||||||
|
PsychicClient::~PsychicClient() {
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicClient::~PsychicClient()
|
httpd_handle_t PsychicClient::server() {
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
httpd_handle_t PsychicClient::server()
|
|
||||||
{
|
|
||||||
return _server;
|
return _server;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PsychicClient::socket()
|
int PsychicClient::socket() {
|
||||||
{
|
|
||||||
return _socket;
|
return _socket;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,28 +24,27 @@ int PsychicClient::socket()
|
|||||||
esp_err_t PsychicClient::close()
|
esp_err_t PsychicClient::close()
|
||||||
{
|
{
|
||||||
esp_err_t err = httpd_sess_trigger_close(_server, _socket);
|
esp_err_t err = httpd_sess_trigger_close(_server, _socket);
|
||||||
// PsychicHttpServer::closeCallback(_server, _socket); // call this immediately so the client is taken off the list.
|
//PsychicHttpServer::closeCallback(_server, _socket); // call this immediately so the client is taken off the list.
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress PsychicClient::localIP()
|
IPAddress PsychicClient::localIP()
|
||||||
{
|
{
|
||||||
IPAddress address(0, 0, 0, 0);
|
IPAddress address(0,0,0,0);
|
||||||
|
|
||||||
char ipstr[INET6_ADDRSTRLEN];
|
char ipstr[INET6_ADDRSTRLEN];
|
||||||
struct sockaddr_in6 addr; // esp_http_server uses IPv6 addressing
|
struct sockaddr_in6 addr; // esp_http_server uses IPv6 addressing
|
||||||
socklen_t addr_size = sizeof(addr);
|
socklen_t addr_size = sizeof(addr);
|
||||||
|
|
||||||
if (getsockname(_socket, (struct sockaddr *)&addr, &addr_size) < 0)
|
if (getsockname(_socket, (struct sockaddr *)&addr, &addr_size) < 0) {
|
||||||
{
|
|
||||||
ESP_LOGE(PH_TAG, "Error getting client IP");
|
ESP_LOGE(PH_TAG, "Error getting client IP");
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to IPv4 string
|
// Convert to IPv4 string
|
||||||
inet_ntop(AF_INET, &addr.sin6_addr.un.u32_addr[3], ipstr, sizeof(ipstr));
|
inet_ntop(AF_INET, &addr.sin6_addr.un.u32_addr[3], ipstr, sizeof(ipstr));
|
||||||
ESP_LOGI(PH_TAG, "Client Local IP => %s", ipstr);
|
//ESP_LOGD(PH_TAG, "Client Local IP => %s", ipstr);
|
||||||
address.fromString(ipstr);
|
address.fromString(ipstr);
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
@@ -56,21 +52,20 @@ IPAddress PsychicClient::localIP()
|
|||||||
|
|
||||||
IPAddress PsychicClient::remoteIP()
|
IPAddress PsychicClient::remoteIP()
|
||||||
{
|
{
|
||||||
IPAddress address(0, 0, 0, 0);
|
IPAddress address(0,0,0,0);
|
||||||
|
|
||||||
char ipstr[INET6_ADDRSTRLEN];
|
char ipstr[INET6_ADDRSTRLEN];
|
||||||
struct sockaddr_in6 addr; // esp_http_server uses IPv6 addressing
|
struct sockaddr_in6 addr; // esp_http_server uses IPv6 addressing
|
||||||
socklen_t addr_size = sizeof(addr);
|
socklen_t addr_size = sizeof(addr);
|
||||||
|
|
||||||
if (getpeername(_socket, (struct sockaddr *)&addr, &addr_size) < 0)
|
if (getpeername(_socket, (struct sockaddr *)&addr, &addr_size) < 0) {
|
||||||
{
|
|
||||||
ESP_LOGE(PH_TAG, "Error getting client IP");
|
ESP_LOGE(PH_TAG, "Error getting client IP");
|
||||||
return address;
|
return address;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to IPv4 string
|
// Convert to IPv4 string
|
||||||
inet_ntop(AF_INET, &addr.sin6_addr.un.u32_addr[3], ipstr, sizeof(ipstr));
|
inet_ntop(AF_INET, &addr.sin6_addr.un.u32_addr[3], ipstr, sizeof(ipstr));
|
||||||
ESP_LOGV(PH_TAG, "Client Remote IP => %s", ipstr);
|
//ESP_LOGD(PH_TAG, "Client Remote IP => %s", ipstr);
|
||||||
address.fromString(ipstr);
|
address.fromString(ipstr);
|
||||||
|
|
||||||
return address;
|
return address;
|
||||||
|
|||||||
@@ -30,7 +30,6 @@
|
|||||||
|
|
||||||
#ifdef ARDUINO
|
#ifdef ARDUINO
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <ArduinoTrace.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <esp_http_server.h>
|
#include <esp_http_server.h>
|
||||||
|
|||||||
@@ -96,7 +96,6 @@ void PsychicEventSource::openCallback(PsychicClient *client) {
|
|||||||
PsychicEventSourceClient *buddy = getClient(client);
|
PsychicEventSourceClient *buddy = getClient(client);
|
||||||
if (buddy == NULL)
|
if (buddy == NULL)
|
||||||
{
|
{
|
||||||
TRACE();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,7 +107,6 @@ void PsychicEventSource::closeCallback(PsychicClient *client) {
|
|||||||
PsychicEventSourceClient *buddy = getClient(client);
|
PsychicEventSourceClient *buddy = getClient(client);
|
||||||
if (buddy == NULL)
|
if (buddy == NULL)
|
||||||
{
|
{
|
||||||
TRACE();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -104,9 +104,16 @@ esp_err_t PsychicFileResponse::send()
|
|||||||
if (size < FILE_CHUNK_SIZE)
|
if (size < FILE_CHUNK_SIZE)
|
||||||
{
|
{
|
||||||
uint8_t *buffer = (uint8_t *)malloc(size);
|
uint8_t *buffer = (uint8_t *)malloc(size);
|
||||||
int readSize = _content.readBytes((char *)buffer, size);
|
if (buffer == NULL)
|
||||||
|
{
|
||||||
|
/* Respond with 500 Internal Server Error */
|
||||||
|
httpd_resp_send_err(this->_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory.");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
this->setContent(buffer, size);
|
size_t readSize = _content.readBytes((char *)buffer, size);
|
||||||
|
|
||||||
|
this->setContent(buffer, readSize);
|
||||||
err = PsychicResponse::send();
|
err = PsychicResponse::send();
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
@@ -143,7 +150,7 @@ esp_err_t PsychicFileResponse::send()
|
|||||||
|
|
||||||
if (err == ESP_OK)
|
if (err == ESP_OK)
|
||||||
{
|
{
|
||||||
ESP_LOGI(PH_TAG, "File sending complete");
|
ESP_LOGD(PH_TAG, "File sending complete");
|
||||||
this->finishChunking();
|
this->finishChunking();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ PsychicHandler::PsychicHandler() :
|
|||||||
_password(""),
|
_password(""),
|
||||||
_method(DIGEST_AUTH),
|
_method(DIGEST_AUTH),
|
||||||
_realm(""),
|
_realm(""),
|
||||||
_authFailMsg("")
|
_authFailMsg(""),
|
||||||
|
_subprotocol("")
|
||||||
{}
|
{}
|
||||||
|
|
||||||
PsychicHandler::~PsychicHandler() {
|
PsychicHandler::~PsychicHandler() {
|
||||||
@@ -26,6 +27,13 @@ bool PsychicHandler::filter(PsychicRequest *request){
|
|||||||
return _filter == NULL || _filter(request);
|
return _filter == NULL || _filter(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PsychicHandler::setSubprotocol(const String& subprotocol) {
|
||||||
|
this->_subprotocol = subprotocol;
|
||||||
|
}
|
||||||
|
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) {
|
PsychicHandler* PsychicHandler::setAuthentication(const char *username, const char *password, HTTPAuthMethod method, const char *realm, const char *authFailMsg) {
|
||||||
_username = String(username);
|
_username = String(username);
|
||||||
_password = String(password);
|
_password = String(password);
|
||||||
|
|||||||
@@ -24,11 +24,13 @@ class PsychicHandler {
|
|||||||
String _realm;
|
String _realm;
|
||||||
String _authFailMsg;
|
String _authFailMsg;
|
||||||
|
|
||||||
|
String _subprotocol;
|
||||||
|
|
||||||
std::list<PsychicClient*> _clients;
|
std::list<PsychicClient*> _clients;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PsychicHandler();
|
PsychicHandler();
|
||||||
~PsychicHandler();
|
virtual ~PsychicHandler();
|
||||||
|
|
||||||
PsychicHandler* setFilter(PsychicRequestFilterFunction fn);
|
PsychicHandler* setFilter(PsychicRequestFilterFunction fn);
|
||||||
bool filter(PsychicRequest *request);
|
bool filter(PsychicRequest *request);
|
||||||
@@ -39,6 +41,9 @@ class PsychicHandler {
|
|||||||
|
|
||||||
virtual bool isWebSocket() { return false; };
|
virtual bool isWebSocket() { return false; };
|
||||||
|
|
||||||
|
void setSubprotocol(const String& subprotocol);
|
||||||
|
const char* getSubprotocol() const;
|
||||||
|
|
||||||
PsychicClient * checkForNewClient(PsychicClient *client);
|
PsychicClient * checkForNewClient(PsychicClient *client);
|
||||||
void checkForClosedClient(PsychicClient *client);
|
void checkForClosedClient(PsychicClient *client);
|
||||||
|
|
||||||
|
|||||||
@@ -3,19 +3,19 @@
|
|||||||
|
|
||||||
//#define ENABLE_ASYNC // This is something added in ESP-IDF 5.1.x where each request can be handled in its own thread
|
//#define ENABLE_ASYNC // This is something added in ESP-IDF 5.1.x where each request can be handled in its own thread
|
||||||
|
|
||||||
#include "PsychicEndpoint.h"
|
#include <http_status.h>
|
||||||
#include "PsychicEventSource.h"
|
|
||||||
#include "PsychicFileResponse.h"
|
|
||||||
#include "PsychicHandler.h"
|
|
||||||
#include "PsychicHttpServer.h"
|
#include "PsychicHttpServer.h"
|
||||||
#include "PsychicJson.h"
|
|
||||||
#include "PsychicRequest.h"
|
#include "PsychicRequest.h"
|
||||||
#include "PsychicResponse.h"
|
#include "PsychicResponse.h"
|
||||||
|
#include "PsychicEndpoint.h"
|
||||||
|
#include "PsychicHandler.h"
|
||||||
#include "PsychicStaticFileHandler.h"
|
#include "PsychicStaticFileHandler.h"
|
||||||
|
#include "PsychicFileResponse.h"
|
||||||
#include "PsychicStreamResponse.h"
|
#include "PsychicStreamResponse.h"
|
||||||
#include "PsychicUploadHandler.h"
|
#include "PsychicUploadHandler.h"
|
||||||
#include "PsychicWebSocket.h"
|
#include "PsychicWebSocket.h"
|
||||||
#include <http_status.h>
|
#include "PsychicEventSource.h"
|
||||||
|
#include "PsychicJson.h"
|
||||||
|
|
||||||
#ifdef ENABLE_ASYNC
|
#ifdef ENABLE_ASYNC
|
||||||
#include "async_worker.h"
|
#include "async_worker.h"
|
||||||
|
|||||||
@@ -56,8 +56,7 @@ PsychicHttpServer::~PsychicHttpServer()
|
|||||||
|
|
||||||
void PsychicHttpServer::destroy(void *ctx)
|
void PsychicHttpServer::destroy(void *ctx)
|
||||||
{
|
{
|
||||||
PsychicHttpServer *temp = (PsychicHttpServer *)ctx;
|
// do not release any resource for PsychicHttpServer in order to be able to restart it after stopping
|
||||||
delete temp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t PsychicHttpServer::listen(uint16_t port)
|
esp_err_t PsychicHttpServer::listen(uint16_t port)
|
||||||
@@ -141,7 +140,8 @@ PsychicEndpoint* PsychicHttpServer::on(const char* uri, http_method method, Psyc
|
|||||||
.method = method,
|
.method = method,
|
||||||
.handler = PsychicEndpoint::requestCallback,
|
.handler = PsychicEndpoint::requestCallback,
|
||||||
.user_ctx = endpoint,
|
.user_ctx = endpoint,
|
||||||
.is_websocket = handler->isWebSocket()
|
.is_websocket = handler->isWebSocket(),
|
||||||
|
.supported_subprotocol = handler->getSubprotocol()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Register endpoint with ESP-IDF server
|
// Register endpoint with ESP-IDF server
|
||||||
@@ -186,7 +186,7 @@ PsychicEndpoint* PsychicHttpServer::on(const char* uri, http_method method, Psyc
|
|||||||
void PsychicHttpServer::onNotFound(PsychicHttpRequestCallback fn)
|
void PsychicHttpServer::onNotFound(PsychicHttpRequestCallback fn)
|
||||||
{
|
{
|
||||||
PsychicWebHandler *handler = new PsychicWebHandler();
|
PsychicWebHandler *handler = new PsychicWebHandler();
|
||||||
handler->onRequest(fn);
|
handler->onRequest(fn == nullptr ? PsychicHttpServer::defaultNotFoundHandler : fn);
|
||||||
|
|
||||||
this->defaultEndpoint->setHandler(handler);
|
this->defaultEndpoint->setHandler(handler);
|
||||||
}
|
}
|
||||||
@@ -232,7 +232,7 @@ void PsychicHttpServer::onOpen(PsychicClientCallback handler) {
|
|||||||
|
|
||||||
esp_err_t PsychicHttpServer::openCallback(httpd_handle_t hd, int sockfd)
|
esp_err_t PsychicHttpServer::openCallback(httpd_handle_t hd, int sockfd)
|
||||||
{
|
{
|
||||||
ESP_LOGI(PH_TAG, "New client connected %d", sockfd);
|
ESP_LOGD(PH_TAG, "New client connected %d", sockfd);
|
||||||
|
|
||||||
//get our global server reference
|
//get our global server reference
|
||||||
PsychicHttpServer *server = (PsychicHttpServer*)httpd_get_global_user_ctx(hd);
|
PsychicHttpServer *server = (PsychicHttpServer*)httpd_get_global_user_ctx(hd);
|
||||||
@@ -258,7 +258,7 @@ void PsychicHttpServer::onClose(PsychicClientCallback handler) {
|
|||||||
|
|
||||||
void PsychicHttpServer::closeCallback(httpd_handle_t hd, int sockfd)
|
void PsychicHttpServer::closeCallback(httpd_handle_t hd, int sockfd)
|
||||||
{
|
{
|
||||||
ESP_LOGI(PH_TAG, "Client disconnected %d", sockfd);
|
ESP_LOGD(PH_TAG, "Client disconnected %d", sockfd);
|
||||||
|
|
||||||
PsychicHttpServer *server = (PsychicHttpServer*)httpd_get_global_user_ctx(hd);
|
PsychicHttpServer *server = (PsychicHttpServer*)httpd_get_global_user_ctx(hd);
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class PsychicHttpServer
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
PsychicHttpServer();
|
PsychicHttpServer();
|
||||||
~PsychicHttpServer();
|
virtual ~PsychicHttpServer();
|
||||||
|
|
||||||
//esp-idf specific stuff
|
//esp-idf specific stuff
|
||||||
httpd_handle_t server;
|
httpd_handle_t server;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "PsychicHttpsServer.h"
|
#include "PsychicHttpsServer.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_HTTPS_SERVER_ENABLE
|
||||||
|
|
||||||
PsychicHttpsServer::PsychicHttpsServer() : PsychicHttpServer()
|
PsychicHttpsServer::PsychicHttpsServer() : PsychicHttpServer()
|
||||||
{
|
{
|
||||||
//for a SSL server
|
//for a SSL server
|
||||||
@@ -25,8 +27,15 @@ esp_err_t PsychicHttpsServer::listen(uint16_t port, const char *cert, const char
|
|||||||
this->_use_ssl = true;
|
this->_use_ssl = true;
|
||||||
|
|
||||||
this->ssl_config.port_secure = port;
|
this->ssl_config.port_secure = port;
|
||||||
this->ssl_config.cacert_pem = (uint8_t *)cert;
|
|
||||||
this->ssl_config.cacert_len = strlen(cert)+1;
|
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 2)
|
||||||
|
this->ssl_config.servercert = (uint8_t *)cert;
|
||||||
|
this->ssl_config.servercert_len = strlen(cert)+1;
|
||||||
|
#else
|
||||||
|
this->ssl_config.cacert_pem = (uint8_t *)cert;
|
||||||
|
this->ssl_config.cacert_len = strlen(cert)+1;
|
||||||
|
#endif
|
||||||
|
|
||||||
this->ssl_config.prvtkey_pem = (uint8_t *)private_key;
|
this->ssl_config.prvtkey_pem = (uint8_t *)private_key;
|
||||||
this->ssl_config.prvtkey_len = strlen(private_key)+1;
|
this->ssl_config.prvtkey_len = strlen(private_key)+1;
|
||||||
|
|
||||||
@@ -47,4 +56,6 @@ void PsychicHttpsServer::stop()
|
|||||||
httpd_ssl_stop(this->server);
|
httpd_ssl_stop(this->server);
|
||||||
else
|
else
|
||||||
httpd_stop(this->server);
|
httpd_stop(this->server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif // CONFIG_ESP_HTTPS_SERVER_ENABLE
|
||||||
@@ -1,10 +1,13 @@
|
|||||||
#ifndef PsychicHttpsServer_h
|
#ifndef PsychicHttpsServer_h
|
||||||
#define PsychicHttpsServer_h
|
#define PsychicHttpsServer_h
|
||||||
|
|
||||||
|
#include <sdkconfig.h>
|
||||||
|
|
||||||
|
#ifdef CONFIG_ESP_HTTPS_SERVER_ENABLE
|
||||||
|
|
||||||
#include "PsychicCore.h"
|
#include "PsychicCore.h"
|
||||||
#include "PsychicHttpServer.h"
|
#include "PsychicHttpServer.h"
|
||||||
#include <esp_https_server.h>
|
#include <esp_https_server.h>
|
||||||
|
|
||||||
#if !CONFIG_HTTPD_WS_SUPPORT
|
#if !CONFIG_HTTPD_WS_SUPPORT
|
||||||
#error PsychicHttpsServer cannot be used unless HTTPD_WS_SUPPORT is enabled in esp-http-server component configuration
|
#error PsychicHttpsServer cannot be used unless HTTPD_WS_SUPPORT is enabled in esp-http-server component configuration
|
||||||
#endif
|
#endif
|
||||||
@@ -29,4 +32,8 @@ class PsychicHttpsServer : public PsychicHttpServer
|
|||||||
virtual void stop() override final;
|
virtual void stop() override final;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PsychicHttpsServer_h
|
#endif // PsychicHttpsServer_h
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error ESP-IDF https server support not enabled.
|
||||||
|
#endif // CONFIG_ESP_HTTPS_SERVER_ENABLE
|
||||||
@@ -1,24 +1,25 @@
|
|||||||
#include "PsychicJson.h"
|
#include "PsychicJson.h"
|
||||||
|
|
||||||
#ifdef ARDUINOJSON_6_COMPATIBILITY
|
#ifdef ARDUINOJSON_6_COMPATIBILITY
|
||||||
PsychicJsonResponse::PsychicJsonResponse(PsychicRequest *request, bool isArray, size_t maxJsonBufferSize) : PsychicResponse(request),
|
PsychicJsonResponse::PsychicJsonResponse(PsychicRequest *request, bool isArray, size_t maxJsonBufferSize) :
|
||||||
_jsonBuffer(maxJsonBufferSize)
|
PsychicResponse(request),
|
||||||
{
|
_jsonBuffer(maxJsonBufferSize)
|
||||||
setContentType(JSON_MIMETYPE);
|
{
|
||||||
if (isArray)
|
setContentType(JSON_MIMETYPE);
|
||||||
_root = _jsonBuffer.createNestedArray();
|
if (isArray)
|
||||||
else
|
_root = _jsonBuffer.createNestedArray();
|
||||||
_root = _jsonBuffer.createNestedObject();
|
else
|
||||||
}
|
_root = _jsonBuffer.createNestedObject();
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
PsychicJsonResponse::PsychicJsonResponse(PsychicRequest *request, bool isArray) : PsychicResponse(request)
|
PsychicJsonResponse::PsychicJsonResponse(PsychicRequest *request, bool isArray) : PsychicResponse(request)
|
||||||
{
|
{
|
||||||
setContentType(JSON_MIMETYPE);
|
setContentType(JSON_MIMETYPE);
|
||||||
if (isArray)
|
if (isArray)
|
||||||
_root = _jsonBuffer.add<JsonArray>();
|
_root = _jsonBuffer.add<JsonArray>();
|
||||||
else
|
else
|
||||||
_root = _jsonBuffer.add<JsonObject>();
|
_root = _jsonBuffer.add<JsonObject>();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
JsonVariant &PsychicJsonResponse::getRoot() { return _root; }
|
JsonVariant &PsychicJsonResponse::getRoot() { return _root; }
|
||||||
@@ -35,28 +36,21 @@ esp_err_t PsychicJsonResponse::send()
|
|||||||
size_t buffer_size;
|
size_t buffer_size;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
|
|
||||||
// DUMP(length);
|
//how big of a buffer do we want?
|
||||||
|
|
||||||
// how big of a buffer do we want?
|
|
||||||
if (length < JSON_BUFFER_SIZE)
|
if (length < JSON_BUFFER_SIZE)
|
||||||
buffer_size = length + 1;
|
buffer_size = length+1;
|
||||||
else
|
else
|
||||||
buffer_size = JSON_BUFFER_SIZE;
|
buffer_size = JSON_BUFFER_SIZE;
|
||||||
|
|
||||||
// DUMP(buffer_size);
|
|
||||||
|
|
||||||
buffer = (char *)malloc(buffer_size);
|
buffer = (char *)malloc(buffer_size);
|
||||||
if (buffer == NULL)
|
if (buffer == NULL) {
|
||||||
{
|
|
||||||
httpd_resp_send_err(this->_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory.");
|
httpd_resp_send_err(this->_request->request(), HTTPD_500_INTERNAL_SERVER_ERROR, "Unable to allocate memory.");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send it in one shot or no?
|
//send it in one shot or no?
|
||||||
if (length < JSON_BUFFER_SIZE)
|
if (length < JSON_BUFFER_SIZE)
|
||||||
{
|
{
|
||||||
// TRACE();
|
|
||||||
|
|
||||||
serializeJson(_root, buffer, buffer_size);
|
serializeJson(_root, buffer, buffer_size);
|
||||||
|
|
||||||
this->setContent((uint8_t *)buffer, length);
|
this->setContent((uint8_t *)buffer, length);
|
||||||
@@ -66,67 +60,71 @@ esp_err_t PsychicJsonResponse::send()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// helper class that acts as a stream to print chunked responses
|
//helper class that acts as a stream to print chunked responses
|
||||||
ChunkPrinter dest(this, (uint8_t *)buffer, buffer_size);
|
ChunkPrinter dest(this, (uint8_t *)buffer, buffer_size);
|
||||||
|
|
||||||
// keep our headers
|
//keep our headers
|
||||||
this->sendHeaders();
|
this->sendHeaders();
|
||||||
|
|
||||||
serializeJson(_root, dest);
|
serializeJson(_root, dest);
|
||||||
|
|
||||||
// send the last bits
|
//send the last bits
|
||||||
dest.flush();
|
dest.flush();
|
||||||
|
|
||||||
// done with our chunked response too
|
//done with our chunked response too
|
||||||
err = this->finishChunking();
|
err = this->finishChunking();
|
||||||
}
|
}
|
||||||
|
|
||||||
// let the buffer go
|
//let the buffer go
|
||||||
free(buffer);
|
free(buffer);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ARDUINOJSON_6_COMPATIBILITY
|
#ifdef ARDUINOJSON_6_COMPATIBILITY
|
||||||
PsychicJsonHandler::PsychicJsonHandler(size_t maxJsonBufferSize) : _onRequest(NULL),
|
PsychicJsonHandler::PsychicJsonHandler(size_t maxJsonBufferSize) :
|
||||||
_maxJsonBufferSize(maxJsonBufferSize){};
|
_onRequest(NULL),
|
||||||
|
_maxJsonBufferSize(maxJsonBufferSize)
|
||||||
|
{};
|
||||||
|
|
||||||
PsychicJsonHandler::PsychicJsonHandler(PsychicJsonRequestCallback onRequest, size_t maxJsonBufferSize) : _onRequest(onRequest),
|
PsychicJsonHandler::PsychicJsonHandler(PsychicJsonRequestCallback onRequest, size_t maxJsonBufferSize) :
|
||||||
_maxJsonBufferSize(maxJsonBufferSize)
|
_onRequest(onRequest),
|
||||||
{
|
_maxJsonBufferSize(maxJsonBufferSize)
|
||||||
}
|
{}
|
||||||
#else
|
#else
|
||||||
PsychicJsonHandler::PsychicJsonHandler() : _onRequest(NULL){};
|
PsychicJsonHandler::PsychicJsonHandler() :
|
||||||
|
_onRequest(NULL)
|
||||||
|
{};
|
||||||
|
|
||||||
PsychicJsonHandler::PsychicJsonHandler(PsychicJsonRequestCallback onRequest) : _onRequest(onRequest)
|
PsychicJsonHandler::PsychicJsonHandler(PsychicJsonRequestCallback onRequest) :
|
||||||
{
|
_onRequest(onRequest)
|
||||||
}
|
{}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void PsychicJsonHandler::onRequest(PsychicJsonRequestCallback fn) { _onRequest = fn; }
|
void PsychicJsonHandler::onRequest(PsychicJsonRequestCallback fn) { _onRequest = fn; }
|
||||||
|
|
||||||
esp_err_t PsychicJsonHandler::handleRequest(PsychicRequest *request)
|
esp_err_t PsychicJsonHandler::handleRequest(PsychicRequest *request)
|
||||||
{
|
{
|
||||||
// process basic stuff
|
//process basic stuff
|
||||||
PsychicWebHandler::handleRequest(request);
|
PsychicWebHandler::handleRequest(request);
|
||||||
|
|
||||||
if (_onRequest)
|
if (_onRequest)
|
||||||
{
|
{
|
||||||
#ifdef ARDUINOJSON_6_COMPATIBILITY
|
#ifdef ARDUINOJSON_6_COMPATIBILITY
|
||||||
DynamicJsonDocument jsonBuffer(this->_maxJsonBufferSize);
|
DynamicJsonDocument jsonBuffer(this->_maxJsonBufferSize);
|
||||||
DeserializationError error = deserializeJson(jsonBuffer, request->body());
|
DeserializationError error = deserializeJson(jsonBuffer, request->body());
|
||||||
if (error)
|
if (error)
|
||||||
return request->reply(400);
|
return request->reply(400);
|
||||||
|
|
||||||
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
||||||
#else
|
#else
|
||||||
JsonDocument jsonBuffer;
|
JsonDocument jsonBuffer;
|
||||||
DeserializationError error = deserializeJson(jsonBuffer, request->body());
|
DeserializationError error = deserializeJson(jsonBuffer, request->body());
|
||||||
if (error)
|
if (error)
|
||||||
return request->reply(400);
|
return request->reply(400);
|
||||||
|
|
||||||
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
JsonVariant json = jsonBuffer.as<JsonVariant>();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return _onRequest(request, json);
|
return _onRequest(request, json);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,17 +2,19 @@
|
|||||||
#include "http_status.h"
|
#include "http_status.h"
|
||||||
#include "PsychicHttpServer.h"
|
#include "PsychicHttpServer.h"
|
||||||
|
|
||||||
PsychicRequest::PsychicRequest(PsychicHttpServer *server, httpd_req_t *req) : _server(server),
|
|
||||||
_req(req),
|
PsychicRequest::PsychicRequest(PsychicHttpServer *server, httpd_req_t *req) :
|
||||||
_method(HTTP_GET),
|
_server(server),
|
||||||
_query(""),
|
_req(req),
|
||||||
_body(""),
|
_method(HTTP_GET),
|
||||||
_tempObject(NULL)
|
_query(""),
|
||||||
|
_body(""),
|
||||||
|
_tempObject(NULL)
|
||||||
{
|
{
|
||||||
// load up our client.
|
//load up our client.
|
||||||
this->_client = server->getClient(req);
|
this->_client = server->getClient(req);
|
||||||
|
|
||||||
// handle our session data
|
//handle our session data
|
||||||
if (req->sess_ctx != NULL)
|
if (req->sess_ctx != NULL)
|
||||||
this->_session = (SessionData *)req->sess_ctx;
|
this->_session = (SessionData *)req->sess_ctx;
|
||||||
else
|
else
|
||||||
@@ -21,22 +23,22 @@ PsychicRequest::PsychicRequest(PsychicHttpServer *server, httpd_req_t *req) : _s
|
|||||||
req->sess_ctx = this->_session;
|
req->sess_ctx = this->_session;
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for freeing the session later
|
//callback for freeing the session later
|
||||||
req->free_ctx = this->freeSession;
|
req->free_ctx = this->freeSession;
|
||||||
|
|
||||||
// load up some data
|
//load up some data
|
||||||
this->_uri = String(this->_req->uri);
|
this->_uri = String(this->_req->uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicRequest::~PsychicRequest()
|
PsychicRequest::~PsychicRequest()
|
||||||
{
|
{
|
||||||
// temorary user object
|
//temorary user object
|
||||||
if (_tempObject != NULL)
|
if (_tempObject != NULL)
|
||||||
free(_tempObject);
|
free(_tempObject);
|
||||||
|
|
||||||
// our web parameters
|
//our web parameters
|
||||||
for (auto *param : _params)
|
for (auto *param : _params)
|
||||||
delete (param);
|
delete(param);
|
||||||
_params.clear();
|
_params.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,29 +46,26 @@ void PsychicRequest::freeSession(void *ctx)
|
|||||||
{
|
{
|
||||||
if (ctx != NULL)
|
if (ctx != NULL)
|
||||||
{
|
{
|
||||||
SessionData *session = (SessionData *)ctx;
|
SessionData *session = (SessionData*)ctx;
|
||||||
delete session;
|
delete session;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicHttpServer *PsychicRequest::server()
|
PsychicHttpServer * PsychicRequest::server() {
|
||||||
{
|
|
||||||
return _server;
|
return _server;
|
||||||
}
|
}
|
||||||
|
|
||||||
httpd_req_t *PsychicRequest::request()
|
httpd_req_t * PsychicRequest::request() {
|
||||||
{
|
|
||||||
return _req;
|
return _req;
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicClient *PsychicRequest::client()
|
PsychicClient * PsychicRequest::client() {
|
||||||
{
|
|
||||||
return _client;
|
return _client;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PsychicRequest::getFilename()
|
const String PsychicRequest::getFilename()
|
||||||
{
|
{
|
||||||
// parse the content-disposition header
|
//parse the content-disposition header
|
||||||
if (this->hasHeader("Content-Disposition"))
|
if (this->hasHeader("Content-Disposition"))
|
||||||
{
|
{
|
||||||
ContentDisposition cd = this->getContentDisposition();
|
ContentDisposition cd = this->getContentDisposition();
|
||||||
@@ -74,19 +73,19 @@ const String PsychicRequest::getFilename()
|
|||||||
return cd.filename;
|
return cd.filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fall back to passed in query string
|
//fall back to passed in query string
|
||||||
PsychicWebParameter *param = getParam("_filename");
|
PsychicWebParameter *param = getParam("_filename");
|
||||||
if (param != NULL)
|
if (param != NULL)
|
||||||
return param->name();
|
return param->name();
|
||||||
|
|
||||||
// fall back to parsing it from url (useful for wildcard uploads)
|
//fall back to parsing it from url (useful for wildcard uploads)
|
||||||
String uri = this->uri();
|
String uri = this->uri();
|
||||||
int filenameStart = uri.lastIndexOf('/') + 1;
|
int filenameStart = uri.lastIndexOf('/') + 1;
|
||||||
String filename = uri.substring(filenameStart);
|
String filename = uri.substring(filenameStart);
|
||||||
if (filename != "")
|
if (filename != "")
|
||||||
return filename;
|
return filename;
|
||||||
|
|
||||||
// finally, unknown.
|
//finally, unknown.
|
||||||
ESP_LOGE(PH_TAG, "Did not get a valid filename from the upload.");
|
ESP_LOGE(PH_TAG, "Did not get a valid filename from the upload.");
|
||||||
return "unknown.txt";
|
return "unknown.txt";
|
||||||
}
|
}
|
||||||
@@ -104,21 +103,21 @@ const ContentDisposition PsychicRequest::getContentDisposition()
|
|||||||
cd.disposition = ATTACHMENT;
|
cd.disposition = ATTACHMENT;
|
||||||
else if (header.indexOf("inline") == 0)
|
else if (header.indexOf("inline") == 0)
|
||||||
cd.disposition = INLINE;
|
cd.disposition = INLINE;
|
||||||
else
|
else
|
||||||
cd.disposition = NONE;
|
cd.disposition = NONE;
|
||||||
|
|
||||||
start = header.indexOf("filename=");
|
start = header.indexOf("filename=");
|
||||||
if (start)
|
if (start)
|
||||||
{
|
{
|
||||||
end = header.indexOf('"', start + 10);
|
end = header.indexOf('"', start+10);
|
||||||
cd.filename = header.substring(start + 10, end - 1);
|
cd.filename = header.substring(start+10, end-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
start = header.indexOf("name=");
|
start = header.indexOf("name=");
|
||||||
if (start)
|
if (start)
|
||||||
{
|
{
|
||||||
end = header.indexOf('"', start + 6);
|
end = header.indexOf('"', start+6);
|
||||||
cd.name = header.substring(start + 6, end - 1);
|
cd.name = header.substring(start+6, end-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cd;
|
return cd;
|
||||||
@@ -133,22 +132,18 @@ esp_err_t PsychicRequest::loadBody()
|
|||||||
size_t remaining = this->_req->content_len;
|
size_t remaining = this->_req->content_len;
|
||||||
size_t actuallyReceived = 0;
|
size_t actuallyReceived = 0;
|
||||||
char *buf = (char *)malloc(remaining + 1);
|
char *buf = (char *)malloc(remaining + 1);
|
||||||
if (buf == NULL)
|
if (buf == NULL) {
|
||||||
{
|
|
||||||
ESP_LOGE(PH_TAG, "Failed to allocate memory for body");
|
ESP_LOGE(PH_TAG, "Failed to allocate memory for body");
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (remaining > 0)
|
while (remaining > 0) {
|
||||||
{
|
|
||||||
int received = httpd_req_recv(this->_req, buf + actuallyReceived, remaining);
|
int received = httpd_req_recv(this->_req, buf + actuallyReceived, remaining);
|
||||||
|
|
||||||
if (received == HTTPD_SOCK_ERR_TIMEOUT)
|
if (received == HTTPD_SOCK_ERR_TIMEOUT) {
|
||||||
{
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (received == HTTPD_SOCK_ERR_FAIL)
|
else if (received == HTTPD_SOCK_ERR_FAIL) {
|
||||||
{
|
|
||||||
ESP_LOGE(PH_TAG, "Failed to receive data.");
|
ESP_LOGE(PH_TAG, "Failed to receive data.");
|
||||||
err = ESP_FAIL;
|
err = ESP_FAIL;
|
||||||
break;
|
break;
|
||||||
@@ -164,32 +159,27 @@ esp_err_t PsychicRequest::loadBody()
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
http_method PsychicRequest::method()
|
http_method PsychicRequest::method() {
|
||||||
{
|
|
||||||
return (http_method)this->_req->method;
|
return (http_method)this->_req->method;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PsychicRequest::methodStr()
|
const String PsychicRequest::methodStr() {
|
||||||
{
|
|
||||||
return String(http_method_str((http_method)this->_req->method));
|
return String(http_method_str((http_method)this->_req->method));
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PsychicRequest::path()
|
const String PsychicRequest::path() {
|
||||||
{
|
|
||||||
int index = _uri.indexOf("?");
|
int index = _uri.indexOf("?");
|
||||||
if (index == -1)
|
if(index == -1)
|
||||||
return _uri;
|
return _uri;
|
||||||
else
|
else
|
||||||
return _uri.substring(0, index);
|
return _uri.substring(0, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
const String &PsychicRequest::uri()
|
const String& PsychicRequest::uri() {
|
||||||
{
|
|
||||||
return this->_uri;
|
return this->_uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String &PsychicRequest::query()
|
const String& PsychicRequest::query() {
|
||||||
{
|
|
||||||
return this->_query;
|
return this->_query;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,10 +192,10 @@ const String PsychicRequest::header(const char *name)
|
|||||||
{
|
{
|
||||||
size_t header_len = httpd_req_get_hdr_value_len(this->_req, name);
|
size_t header_len = httpd_req_get_hdr_value_len(this->_req, name);
|
||||||
|
|
||||||
// if we've got one, allocated it and load it
|
//if we've got one, allocated it and load it
|
||||||
if (header_len)
|
if (header_len)
|
||||||
{
|
{
|
||||||
char header[header_len + 1];
|
char header[header_len+1];
|
||||||
httpd_req_get_hdr_value_str(this->_req, name, header, sizeof(header));
|
httpd_req_get_hdr_value_str(this->_req, name, header, sizeof(header));
|
||||||
return String(header);
|
return String(header);
|
||||||
}
|
}
|
||||||
@@ -218,29 +208,26 @@ bool PsychicRequest::hasHeader(const char *name)
|
|||||||
return httpd_req_get_hdr_value_len(this->_req, name) > 0;
|
return httpd_req_get_hdr_value_len(this->_req, name) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PsychicRequest::host()
|
const String PsychicRequest::host() {
|
||||||
{
|
|
||||||
return this->header("Host");
|
return this->header("Host");
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PsychicRequest::contentType()
|
const String PsychicRequest::contentType() {
|
||||||
{
|
|
||||||
return header("Content-Type");
|
return header("Content-Type");
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t PsychicRequest::contentLength()
|
size_t PsychicRequest::contentLength() {
|
||||||
{
|
|
||||||
return this->_req->content_len;
|
return this->_req->content_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String &PsychicRequest::body()
|
const String& PsychicRequest::body()
|
||||||
{
|
{
|
||||||
return this->_body;
|
return this->_body;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PsychicRequest::isMultipart()
|
bool PsychicRequest::isMultipart()
|
||||||
{
|
{
|
||||||
const String &type = this->contentType();
|
const String& type = this->contentType();
|
||||||
|
|
||||||
return (this->contentType().indexOf("multipart/form-data") >= 0);
|
return (this->contentType().indexOf("multipart/form-data") >= 0);
|
||||||
}
|
}
|
||||||
@@ -260,7 +247,7 @@ bool PsychicRequest::hasCookie(const char *key)
|
|||||||
size_t cookieSize = MAX_COOKIE_SIZE;
|
size_t cookieSize = MAX_COOKIE_SIZE;
|
||||||
esp_err_t err = httpd_req_get_cookie_val(this->_req, key, cookie, &cookieSize);
|
esp_err_t err = httpd_req_get_cookie_val(this->_req, key, cookie, &cookieSize);
|
||||||
|
|
||||||
// did we get anything?
|
//did we get anything?
|
||||||
if (err == ESP_OK)
|
if (err == ESP_OK)
|
||||||
return true;
|
return true;
|
||||||
else if (err == ESP_ERR_HTTPD_RESULT_TRUNC)
|
else if (err == ESP_ERR_HTTPD_RESULT_TRUNC)
|
||||||
@@ -275,7 +262,7 @@ const String PsychicRequest::getCookie(const char *key)
|
|||||||
size_t cookieSize = MAX_COOKIE_SIZE;
|
size_t cookieSize = MAX_COOKIE_SIZE;
|
||||||
esp_err_t err = httpd_req_get_cookie_val(this->_req, key, cookie, &cookieSize);
|
esp_err_t err = httpd_req_get_cookie_val(this->_req, key, cookie, &cookieSize);
|
||||||
|
|
||||||
// did we get anything?
|
//did we get anything?
|
||||||
if (err == ESP_OK)
|
if (err == ESP_OK)
|
||||||
return String(cookie);
|
return String(cookie);
|
||||||
else
|
else
|
||||||
@@ -284,54 +271,49 @@ const String PsychicRequest::getCookie(const char *key)
|
|||||||
|
|
||||||
void PsychicRequest::loadParams()
|
void PsychicRequest::loadParams()
|
||||||
{
|
{
|
||||||
// did we get a query string?
|
//did we get a query string?
|
||||||
size_t query_len = httpd_req_get_url_query_len(_req);
|
size_t query_len = httpd_req_get_url_query_len(_req);
|
||||||
if (query_len)
|
if (query_len)
|
||||||
{
|
{
|
||||||
char query[query_len + 1];
|
char query[query_len+1];
|
||||||
httpd_req_get_url_query_str(_req, query, sizeof(query));
|
httpd_req_get_url_query_str(_req, query, sizeof(query));
|
||||||
_query = "";
|
|
||||||
_query.concat(query);
|
_query.concat(query);
|
||||||
|
|
||||||
// parse them.
|
//parse them.
|
||||||
_addParams(_query);
|
_addParams(_query, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// did we get form data as body?
|
//did we get form data as body?
|
||||||
if (this->method() == HTTP_POST && this->contentType() == "application/x-www-form-urlencoded")
|
if (this->method() == HTTP_POST && this->contentType().startsWith("application/x-www-form-urlencoded"))
|
||||||
{
|
{
|
||||||
_addParams(_body);
|
_addParams(_body, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PsychicRequest::_addParams(const String ¶ms)
|
void PsychicRequest::_addParams(const String& params, bool post){
|
||||||
{
|
|
||||||
size_t start = 0;
|
size_t start = 0;
|
||||||
while (start < params.length())
|
while (start < params.length()){
|
||||||
{
|
|
||||||
int end = params.indexOf('&', start);
|
int end = params.indexOf('&', start);
|
||||||
if (end < 0)
|
if (end < 0) end = params.length();
|
||||||
end = params.length();
|
|
||||||
int equal = params.indexOf('=', start);
|
int equal = params.indexOf('=', start);
|
||||||
if (equal < 0 || equal > end)
|
if (equal < 0 || equal > end) equal = end;
|
||||||
equal = end;
|
|
||||||
String name = params.substring(start, equal);
|
String name = params.substring(start, equal);
|
||||||
String value = equal + 1 < end ? params.substring(equal + 1, end) : String();
|
String value = equal + 1 < end ? params.substring(equal + 1, end) : String();
|
||||||
addParam(name, value);
|
addParam(name, value, true, post);
|
||||||
start = end + 1;
|
start = end + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebParameter *PsychicRequest::addParam(const String &name, const String &value, bool decode)
|
PsychicWebParameter * PsychicRequest::addParam(const String &name, const String &value, bool decode, bool post)
|
||||||
{
|
{
|
||||||
if (decode)
|
if (decode)
|
||||||
return addParam(new PsychicWebParameter(urlDecode(name.c_str()), urlDecode(value.c_str())));
|
return addParam(new PsychicWebParameter(urlDecode(name.c_str()), urlDecode(value.c_str()), post));
|
||||||
else
|
else
|
||||||
return addParam(new PsychicWebParameter(name, value));
|
return addParam(new PsychicWebParameter(name, value, post));
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebParameter *PsychicRequest::addParam(PsychicWebParameter *param)
|
PsychicWebParameter * PsychicRequest::addParam(PsychicWebParameter *param) {
|
||||||
{
|
// ESP_LOGD(PH_TAG, "Adding param: '%s' = '%s'", param->name().c_str(), param->value().c_str());
|
||||||
_params.push_back(param);
|
_params.push_back(param);
|
||||||
return param;
|
return param;
|
||||||
}
|
}
|
||||||
@@ -341,7 +323,7 @@ bool PsychicRequest::hasParam(const char *key)
|
|||||||
return getParam(key) != NULL;
|
return getParam(key) != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebParameter *PsychicRequest::getParam(const char *key)
|
PsychicWebParameter * PsychicRequest::getParam(const char *key)
|
||||||
{
|
{
|
||||||
for (auto *param : _params)
|
for (auto *param : _params)
|
||||||
if (param->name().equals(key))
|
if (param->name().equals(key))
|
||||||
@@ -350,12 +332,12 @@ PsychicWebParameter *PsychicRequest::getParam(const char *key)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PsychicRequest::hasSessionKey(const String &key)
|
bool PsychicRequest::hasSessionKey(const String& key)
|
||||||
{
|
{
|
||||||
return this->_session->find(key) != this->_session->end();
|
return this->_session->find(key) != this->_session->end();
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PsychicRequest::getSessionKey(const String &key)
|
const String PsychicRequest::getSessionKey(const String& key)
|
||||||
{
|
{
|
||||||
auto it = this->_session->find(key);
|
auto it = this->_session->find(key);
|
||||||
if (it != this->_session->end())
|
if (it != this->_session->end())
|
||||||
@@ -364,13 +346,12 @@ const String PsychicRequest::getSessionKey(const String &key)
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void PsychicRequest::setSessionKey(const String &key, const String &value)
|
void PsychicRequest::setSessionKey(const String& key, const String& value)
|
||||||
{
|
{
|
||||||
this->_session->insert(std::pair<String, String>(key, value));
|
this->_session->insert(std::pair<String, String>(key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const String md5str(const String &in)
|
static const String md5str(const String &in){
|
||||||
{
|
|
||||||
MD5Builder md5 = MD5Builder();
|
MD5Builder md5 = MD5Builder();
|
||||||
md5.begin();
|
md5.begin();
|
||||||
md5.add(in);
|
md5.add(in);
|
||||||
@@ -378,32 +359,28 @@ static const String md5str(const String &in)
|
|||||||
return md5.toString();
|
return md5.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PsychicRequest::authenticate(const char *username, const char *password)
|
bool PsychicRequest::authenticate(const char * username, const char * password)
|
||||||
{
|
{
|
||||||
if (hasHeader("Authorization"))
|
if(hasHeader("Authorization"))
|
||||||
{
|
{
|
||||||
String authReq = header("Authorization");
|
String authReq = header("Authorization");
|
||||||
if (authReq.startsWith("Basic"))
|
if(authReq.startsWith("Basic")){
|
||||||
{
|
|
||||||
authReq = authReq.substring(6);
|
authReq = authReq.substring(6);
|
||||||
authReq.trim();
|
authReq.trim();
|
||||||
char toencodeLen = strlen(username) + strlen(password) + 1;
|
char toencodeLen = strlen(username)+strlen(password)+1;
|
||||||
char *toencode = new char[toencodeLen + 1];
|
char *toencode = new char[toencodeLen + 1];
|
||||||
if (toencode == NULL)
|
if(toencode == NULL){
|
||||||
{
|
|
||||||
authReq = "";
|
authReq = "";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
char *encoded = new char[base64_encode_expected_len(toencodeLen) + 1];
|
char *encoded = new char[base64_encode_expected_len(toencodeLen)+1];
|
||||||
if (encoded == NULL)
|
if(encoded == NULL){
|
||||||
{
|
|
||||||
authReq = "";
|
authReq = "";
|
||||||
delete[] toencode;
|
delete[] toencode;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
sprintf(toencode, "%s:%s", username, password);
|
sprintf(toencode, "%s:%s", username, password);
|
||||||
if (base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime(encoded))
|
if(base64_encode_chars(toencode, toencodeLen, encoded) > 0 && authReq.equalsConstantTime(encoded)) {
|
||||||
{
|
|
||||||
authReq = "";
|
authReq = "";
|
||||||
delete[] toencode;
|
delete[] toencode;
|
||||||
delete[] encoded;
|
delete[] encoded;
|
||||||
@@ -412,81 +389,63 @@ bool PsychicRequest::authenticate(const char *username, const char *password)
|
|||||||
delete[] toencode;
|
delete[] toencode;
|
||||||
delete[] encoded;
|
delete[] encoded;
|
||||||
}
|
}
|
||||||
else if (authReq.startsWith(F("Digest")))
|
else if(authReq.startsWith(F("Digest")))
|
||||||
{
|
{
|
||||||
authReq = authReq.substring(7);
|
authReq = authReq.substring(7);
|
||||||
String _username = _extractParam(authReq, F("username=\""), '\"');
|
String _username = _extractParam(authReq,F("username=\""),'\"');
|
||||||
if (!_username.length() || _username != String(username))
|
if(!_username.length() || _username != String(username)) {
|
||||||
{
|
|
||||||
authReq = "";
|
authReq = "";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// extracting required parameters for RFC 2069 simpler Digest
|
// extracting required parameters for RFC 2069 simpler Digest
|
||||||
String _realm = _extractParam(authReq, F("realm=\""), '\"');
|
String _realm = _extractParam(authReq, F("realm=\""),'\"');
|
||||||
String _nonce = _extractParam(authReq, F("nonce=\""), '\"');
|
String _nonce = _extractParam(authReq, F("nonce=\""),'\"');
|
||||||
String _uri = _extractParam(authReq, F("uri=\""), '\"');
|
String _uri = _extractParam(authReq, F("uri=\""),'\"');
|
||||||
String _resp = _extractParam(authReq, F("response=\""), '\"');
|
String _resp = _extractParam(authReq, F("response=\""),'\"');
|
||||||
String _opaque = _extractParam(authReq, F("opaque=\""), '\"');
|
String _opaque = _extractParam(authReq, F("opaque=\""),'\"');
|
||||||
|
|
||||||
if ((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_resp.length()) || (!_opaque.length()))
|
if((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_resp.length()) || (!_opaque.length())) {
|
||||||
{
|
|
||||||
authReq = "";
|
authReq = "";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if ((_opaque != this->getSessionKey("opaque")) || (_nonce != this->getSessionKey("nonce")) || (_realm != this->getSessionKey("realm")))
|
if((_opaque != this->getSessionKey("opaque")) || (_nonce != this->getSessionKey("nonce")) || (_realm != this->getSessionKey("realm")))
|
||||||
{
|
{
|
||||||
// DUMP(_opaque);
|
|
||||||
// DUMP(this->getSessionKey("opaque"));
|
|
||||||
// DUMP(_nonce);
|
|
||||||
// DUMP(this->getSessionKey("nonce"));
|
|
||||||
// DUMP(_realm);
|
|
||||||
// DUMP(this->getSessionKey("realm"));
|
|
||||||
authReq = "";
|
authReq = "";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// parameters for the RFC 2617 newer Digest
|
// parameters for the RFC 2617 newer Digest
|
||||||
String _nc, _cnonce;
|
String _nc,_cnonce;
|
||||||
if (authReq.indexOf("qop=auth") != -1 || authReq.indexOf("qop=\"auth\"") != -1)
|
if(authReq.indexOf("qop=auth") != -1 || authReq.indexOf("qop=\"auth\"") != -1) {
|
||||||
{
|
|
||||||
_nc = _extractParam(authReq, F("nc="), ',');
|
_nc = _extractParam(authReq, F("nc="), ',');
|
||||||
_cnonce = _extractParam(authReq, F("cnonce=\""), '\"');
|
_cnonce = _extractParam(authReq, F("cnonce=\""),'\"');
|
||||||
}
|
}
|
||||||
|
|
||||||
String _H1 = md5str(String(username) + ':' + _realm + ':' + String(password));
|
String _H1 = md5str(String(username) + ':' + _realm + ':' + String(password));
|
||||||
ESP_LOGD(PH_TAG, "Hash of user:realm:pass=%s", _H1.c_str());
|
//ESP_LOGD(PH_TAG, "Hash of user:realm:pass=%s", _H1.c_str());
|
||||||
|
|
||||||
String _H2 = "";
|
String _H2 = "";
|
||||||
if (_method == HTTP_GET)
|
if(_method == HTTP_GET){
|
||||||
{
|
_H2 = md5str(String(F("GET:")) + _uri);
|
||||||
_H2 = md5str(String(F("GET:")) + _uri);
|
}else if(_method == HTTP_POST){
|
||||||
|
_H2 = md5str(String(F("POST:")) + _uri);
|
||||||
|
}else if(_method == HTTP_PUT){
|
||||||
|
_H2 = md5str(String(F("PUT:")) + _uri);
|
||||||
|
}else if(_method == HTTP_DELETE){
|
||||||
|
_H2 = md5str(String(F("DELETE:")) + _uri);
|
||||||
|
}else{
|
||||||
|
_H2 = md5str(String(F("GET:")) + _uri);
|
||||||
}
|
}
|
||||||
else if (_method == HTTP_POST)
|
//ESP_LOGD(PH_TAG, "Hash of GET:uri=%s", _H2.c_str());
|
||||||
{
|
|
||||||
_H2 = md5str(String(F("POST:")) + _uri);
|
|
||||||
}
|
|
||||||
else if (_method == HTTP_PUT)
|
|
||||||
{
|
|
||||||
_H2 = md5str(String(F("PUT:")) + _uri);
|
|
||||||
}
|
|
||||||
else if (_method == HTTP_DELETE)
|
|
||||||
{
|
|
||||||
_H2 = md5str(String(F("DELETE:")) + _uri);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_H2 = md5str(String(F("GET:")) + _uri);
|
|
||||||
}
|
|
||||||
ESP_LOGD(PH_TAG, "Hash of GET:uri=%s", _H2.c_str());
|
|
||||||
String _responsecheck = "";
|
String _responsecheck = "";
|
||||||
if (authReq.indexOf("qop=auth") != -1 || authReq.indexOf("qop=\"auth\"") != -1)
|
if(authReq.indexOf("qop=auth") != -1 || authReq.indexOf("qop=\"auth\"") != -1) {
|
||||||
{
|
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2);
|
||||||
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _nc + ':' + _cnonce + F(":auth:") + _H2);
|
} else {
|
||||||
|
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _H2);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
//ESP_LOGD(PH_TAG, "The Proper response=%s", _responsecheck.c_str());
|
||||||
_responsecheck = md5str(_H1 + ':' + _nonce + ':' + _H2);
|
if(_resp == _responsecheck){
|
||||||
}
|
|
||||||
ESP_LOGD(PH_TAG, "The Proper response=%s", _responsecheck.c_str());
|
|
||||||
if (_resp == _responsecheck)
|
|
||||||
{
|
|
||||||
authReq = "";
|
authReq = "";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -496,29 +455,28 @@ bool PsychicRequest::authenticate(const char *username, const char *password)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PsychicRequest::_extractParam(const String &authReq, const String ¶m, const char delimit)
|
const String PsychicRequest::_extractParam(const String& authReq, const String& param, const char delimit)
|
||||||
{
|
{
|
||||||
int _begin = authReq.indexOf(param);
|
int _begin = authReq.indexOf(param);
|
||||||
if (_begin == -1)
|
if (_begin == -1)
|
||||||
return "";
|
return "";
|
||||||
return authReq.substring(_begin + param.length(), authReq.indexOf(delimit, _begin + param.length()));
|
return authReq.substring(_begin+param.length(),authReq.indexOf(delimit,_begin+param.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
const String PsychicRequest::_getRandomHexString()
|
const String PsychicRequest::_getRandomHexString()
|
||||||
{
|
{
|
||||||
char buffer[33]; // buffer to hold 32 Hex Digit + /0
|
char buffer[33]; // buffer to hold 32 Hex Digit + /0
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < 4; i++)
|
for(i = 0; i < 4; i++) {
|
||||||
{
|
sprintf (buffer + (i*8), "%08lx", (unsigned long int)esp_random());
|
||||||
sprintf(buffer + (i * 8), "%08lx", esp_random());
|
|
||||||
}
|
}
|
||||||
return String(buffer);
|
return String(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t PsychicRequest::requestAuthentication(HTTPAuthMethod mode, const char *realm, const char *authFailMsg)
|
esp_err_t PsychicRequest::requestAuthentication(HTTPAuthMethod mode, const char* realm, const char* authFailMsg)
|
||||||
{
|
{
|
||||||
// what is thy realm, sire?
|
//what is thy realm, sire?
|
||||||
if (!strcmp(realm, ""))
|
if(!strcmp(realm, ""))
|
||||||
this->setSessionKey("realm", "Login Required");
|
this->setSessionKey("realm", "Login Required");
|
||||||
else
|
else
|
||||||
this->setSessionKey("realm", realm);
|
this->setSessionKey("realm", realm);
|
||||||
@@ -526,17 +484,17 @@ esp_err_t PsychicRequest::requestAuthentication(HTTPAuthMethod mode, const char
|
|||||||
PsychicResponse response(this);
|
PsychicResponse response(this);
|
||||||
String authStr;
|
String authStr;
|
||||||
|
|
||||||
// what kind of auth?
|
//what kind of auth?
|
||||||
if (mode == BASIC_AUTH)
|
if(mode == BASIC_AUTH)
|
||||||
{
|
{
|
||||||
authStr = "Basic realm=\"" + this->getSessionKey("realm") + "\"";
|
authStr = "Basic realm=\"" + this->getSessionKey("realm") + "\"";
|
||||||
response.addHeader("WWW-Authenticate", authStr.c_str());
|
response.addHeader("WWW-Authenticate", authStr.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// only make new ones if we havent sent them yet
|
//only make new ones if we havent sent them yet
|
||||||
if (this->getSessionKey("nonce").isEmpty())
|
if (this->getSessionKey("nonce").isEmpty())
|
||||||
this->setSessionKey("nonce", _getRandomHexString());
|
this->setSessionKey("nonce", _getRandomHexString());
|
||||||
if (this->getSessionKey("opaque").isEmpty())
|
if (this->getSessionKey("opaque").isEmpty())
|
||||||
this->setSessionKey("opaque", _getRandomHexString());
|
this->setSessionKey("opaque", _getRandomHexString());
|
||||||
|
|
||||||
@@ -544,8 +502,6 @@ esp_err_t PsychicRequest::requestAuthentication(HTTPAuthMethod mode, const char
|
|||||||
response.addHeader("WWW-Authenticate", authStr.c_str());
|
response.addHeader("WWW-Authenticate", authStr.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// DUMP(authStr);
|
|
||||||
|
|
||||||
response.setCode(401);
|
response.setCode(401);
|
||||||
response.setContentType("text/html");
|
response.setContentType("text/html");
|
||||||
response.setContent(authStr.c_str());
|
response.setContent(authStr.c_str());
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ class PsychicRequest {
|
|||||||
|
|
||||||
std::list<PsychicWebParameter*> _params;
|
std::list<PsychicWebParameter*> _params;
|
||||||
|
|
||||||
void _addParams(const String& params);
|
void _addParams(const String& params, bool post);
|
||||||
void _parseGETParams();
|
void _parseGETParams();
|
||||||
void _parsePOSTParams();
|
void _parsePOSTParams();
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ class PsychicRequest {
|
|||||||
|
|
||||||
void loadParams();
|
void loadParams();
|
||||||
PsychicWebParameter * addParam(PsychicWebParameter *param);
|
PsychicWebParameter * addParam(PsychicWebParameter *param);
|
||||||
PsychicWebParameter * addParam(const String &name, const String &value, bool decode = true);
|
PsychicWebParameter * addParam(const String &name, const String &value, bool decode = true, bool post = false);
|
||||||
bool hasParam(const char *key);
|
bool hasParam(const char *key);
|
||||||
PsychicWebParameter * getParam(const char *name);
|
PsychicWebParameter * getParam(const char *name);
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ PsychicResponse::PsychicResponse(PsychicRequest *request) :
|
|||||||
|
|
||||||
PsychicResponse::~PsychicResponse()
|
PsychicResponse::~PsychicResponse()
|
||||||
{
|
{
|
||||||
//clean up our header variables. we have to do this since httpd_resp_send doesn't store copies
|
//clean up our header variables. we have to do this on desctruct since httpd_resp_send doesn't store copies
|
||||||
for (HTTPHeader header : _headers)
|
for (HTTPHeader header : _headers)
|
||||||
{
|
{
|
||||||
free(header.field);
|
free(header.field);
|
||||||
@@ -24,7 +24,7 @@ PsychicResponse::~PsychicResponse()
|
|||||||
|
|
||||||
void PsychicResponse::addHeader(const char *field, const char *value)
|
void PsychicResponse::addHeader(const char *field, const char *value)
|
||||||
{
|
{
|
||||||
//these get freed during send()
|
//these get freed after send by the destructor
|
||||||
HTTPHeader header;
|
HTTPHeader header;
|
||||||
header.field =(char *)malloc(strlen(field)+1);
|
header.field =(char *)malloc(strlen(field)+1);
|
||||||
header.value = (char *)malloc(strlen(value)+1);
|
header.value = (char *)malloc(strlen(value)+1);
|
||||||
@@ -65,9 +65,6 @@ void PsychicResponse::setCookie(const char *name, const char *value, unsigned lo
|
|||||||
addHeader("Set-Cookie", output.c_str());
|
addHeader("Set-Cookie", output.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// time_t now = time(nullptr);
|
|
||||||
// // Set the cookie with the "expires" attribute
|
|
||||||
|
|
||||||
void PsychicResponse::setCode(int code)
|
void PsychicResponse::setCode(int code)
|
||||||
{
|
{
|
||||||
_code = code;
|
_code = code;
|
||||||
@@ -128,6 +125,16 @@ void PsychicResponse::sendHeaders()
|
|||||||
//now do our individual headers
|
//now do our individual headers
|
||||||
for (HTTPHeader header : _headers)
|
for (HTTPHeader header : _headers)
|
||||||
httpd_resp_set_hdr(this->_request->request(), header.field, header.value);
|
httpd_resp_set_hdr(this->_request->request(), header.field, header.value);
|
||||||
|
|
||||||
|
// DO NOT RELEASE HEADERS HERE... released in the PsychicResponse destructor after they have been sent.
|
||||||
|
// httpd_resp_set_hdr just passes on the pointer, but its needed after this call.
|
||||||
|
// clean up our header variables after send
|
||||||
|
// for (HTTPHeader header : _headers)
|
||||||
|
// {
|
||||||
|
// free(header.field);
|
||||||
|
// free(header.value);
|
||||||
|
// }
|
||||||
|
// _headers.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t PsychicResponse::sendChunk(uint8_t *chunk, size_t chunksize)
|
esp_err_t PsychicResponse::sendChunk(uint8_t *chunk, size_t chunksize)
|
||||||
|
|||||||
@@ -141,24 +141,16 @@ esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest *request)
|
|||||||
{
|
{
|
||||||
if (_file == true)
|
if (_file == true)
|
||||||
{
|
{
|
||||||
DUMP(_filename);
|
|
||||||
|
|
||||||
//is it not modified?
|
//is it not modified?
|
||||||
String etag = String(_file.size());
|
String etag = String(_file.size());
|
||||||
if (_last_modified.length() && _last_modified == request->header("If-Modified-Since"))
|
if (_last_modified.length() && _last_modified == request->header("If-Modified-Since"))
|
||||||
{
|
{
|
||||||
DUMP("Last Modified Hit");
|
|
||||||
TRACE();
|
|
||||||
_file.close();
|
_file.close();
|
||||||
request->reply(304); // Not modified
|
request->reply(304); // Not modified
|
||||||
}
|
}
|
||||||
//does our Etag match?
|
//does our Etag match?
|
||||||
else if (_cache_control.length() && request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag))
|
else if (_cache_control.length() && request->hasHeader("If-None-Match") && request->header("If-None-Match").equals(etag))
|
||||||
{
|
{
|
||||||
DUMP("Etag Hit");
|
|
||||||
DUMP(etag);
|
|
||||||
DUMP(_cache_control);
|
|
||||||
|
|
||||||
_file.close();
|
_file.close();
|
||||||
|
|
||||||
PsychicResponse response(request);
|
PsychicResponse response(request);
|
||||||
@@ -170,10 +162,6 @@ esp_err_t PsychicStaticFileHandler::handleRequest(PsychicRequest *request)
|
|||||||
//nope, send them the full file.
|
//nope, send them the full file.
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DUMP("No cache hit");
|
|
||||||
DUMP(_last_modified);
|
|
||||||
DUMP(_cache_control);
|
|
||||||
|
|
||||||
PsychicFileResponse response(request, _fs, _filename);
|
PsychicFileResponse response(request, _fs, _filename);
|
||||||
|
|
||||||
if (_last_modified.length())
|
if (_last_modified.length())
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ PsychicStreamResponse::PsychicStreamResponse(PsychicRequest *request, const Stri
|
|||||||
setContentType(contentType.c_str());
|
setContentType(contentType.c_str());
|
||||||
|
|
||||||
char buf[26+name.length()];
|
char buf[26+name.length()];
|
||||||
snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", name);
|
snprintf(buf, sizeof (buf), "attachment; filename=\"%s\"", name.c_str());
|
||||||
addHeader("Content-Disposition", buf);
|
addHeader("Content-Disposition", buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,6 @@ esp_err_t PsychicUploadHandler::handleRequest(PsychicRequest *request)
|
|||||||
//save it for later (multipart)
|
//save it for later (multipart)
|
||||||
_request = request;
|
_request = request;
|
||||||
_parsedLength = 0;
|
_parsedLength = 0;
|
||||||
|
|
||||||
/* File cannot be larger than a limit */
|
/* File cannot be larger than a limit */
|
||||||
if (request->contentLength() > request->server()->maxUploadSize)
|
if (request->contentLength() > request->server()->maxUploadSize)
|
||||||
{
|
{
|
||||||
@@ -37,7 +36,7 @@ esp_err_t PsychicUploadHandler::handleRequest(PsychicRequest *request)
|
|||||||
|
|
||||||
/* Respond with 400 Bad Request */
|
/* Respond with 400 Bad Request */
|
||||||
char error[50];
|
char error[50];
|
||||||
sprintf(error, "File size must be less than %u bytes!", request->server()->maxUploadSize);
|
sprintf(error, "File size must be less than %lu bytes!", request->server()->maxUploadSize);
|
||||||
httpd_resp_send_err(request->request(), HTTPD_400_BAD_REQUEST, error);
|
httpd_resp_send_err(request->request(), HTTPD_400_BAD_REQUEST, error);
|
||||||
|
|
||||||
/* Return failure to close underlying connection else the incoming file content will keep the socket busy */
|
/* Return failure to close underlying connection else the incoming file content will keep the socket busy */
|
||||||
@@ -94,7 +93,7 @@ esp_err_t PsychicUploadHandler::_basicUploadHandler(PsychicRequest *request)
|
|||||||
httpd_sess_update_lru_counter(request->server()->server, request->client()->socket());
|
httpd_sess_update_lru_counter(request->server()->server, request->client()->socket());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ESP_LOGI(PH_TAG, "Remaining size : %d", remaining);
|
//ESP_LOGD(PH_TAG, "Remaining size : %d", remaining);
|
||||||
|
|
||||||
/* Receive the file part by part into a buffer */
|
/* Receive the file part by part into a buffer */
|
||||||
if ((received = httpd_req_recv(request->request(), buf, min(remaining, FILE_CHUNK_SIZE))) <= 0)
|
if ((received = httpd_req_recv(request->request(), buf, min(remaining, FILE_CHUNK_SIZE))) <= 0)
|
||||||
@@ -162,7 +161,7 @@ esp_err_t PsychicUploadHandler::_multipartUploadHandler(PsychicRequest *request)
|
|||||||
httpd_sess_update_lru_counter(request->server()->server, request->client()->socket());
|
httpd_sess_update_lru_counter(request->server()->server, request->client()->socket());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ESP_LOGI(PH_TAG, "Remaining size : %d", remaining);
|
//ESP_LOGD(PH_TAG, "Remaining size : %d", remaining);
|
||||||
|
|
||||||
/* Receive the file part by part into a buffer */
|
/* Receive the file part by part into a buffer */
|
||||||
if ((received = httpd_req_recv(request->request(), buf, min(remaining, FILE_CHUNK_SIZE))) <= 0)
|
if ((received = httpd_req_recv(request->request(), buf, min(remaining, FILE_CHUNK_SIZE))) <= 0)
|
||||||
@@ -393,4 +392,4 @@ void PsychicUploadHandler::_parseMultipartPostByte(uint8_t data, bool last)
|
|||||||
itemWriteByte('\r'); _parseMultipartPostByte(data, last);
|
itemWriteByte('\r'); _parseMultipartPostByte(data, last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ esp_err_t PsychicWebHandler::handleRequest(PsychicRequest *request)
|
|||||||
|
|
||||||
/* Respond with 400 Bad Request */
|
/* Respond with 400 Bad Request */
|
||||||
char error[60];
|
char error[60];
|
||||||
sprintf(error, "Request body must be less than %u bytes!", request->server()->maxRequestBodySize);
|
sprintf(error, "Request body must be less than %lu bytes!", request->server()->maxRequestBodySize);
|
||||||
httpd_resp_send_err(request->request(), HTTPD_400_BAD_REQUEST, error);
|
httpd_resp_send_err(request->request(), HTTPD_400_BAD_REQUEST, error);
|
||||||
|
|
||||||
/* Return failure to close underlying connection else the incoming file content will keep the socket busy */
|
/* Return failure to close underlying connection else the incoming file content will keep the socket busy */
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
/* PsychicWebSocketRequest */
|
/* PsychicWebSocketRequest */
|
||||||
/*************************************/
|
/*************************************/
|
||||||
|
|
||||||
PsychicWebSocketRequest::PsychicWebSocketRequest(PsychicRequest *req) : PsychicRequest(req->server(), req->request()),
|
PsychicWebSocketRequest::PsychicWebSocketRequest(PsychicRequest *req) :
|
||||||
_client(req->client())
|
PsychicRequest(req->server(), req->request()),
|
||||||
|
_client(req->client())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -13,22 +14,21 @@ PsychicWebSocketRequest::~PsychicWebSocketRequest()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebSocketClient *PsychicWebSocketRequest::client()
|
PsychicWebSocketClient * PsychicWebSocketRequest::client() {
|
||||||
{
|
|
||||||
return &_client;
|
return &_client;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t PsychicWebSocketRequest::reply(httpd_ws_frame_t *ws_pkt)
|
esp_err_t PsychicWebSocketRequest::reply(httpd_ws_frame_t * ws_pkt)
|
||||||
{
|
{
|
||||||
return httpd_ws_send_frame(this->_req, ws_pkt);
|
return httpd_ws_send_frame(this->_req, ws_pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t PsychicWebSocketRequest::reply(httpd_ws_type_t op, const void *data, size_t len)
|
esp_err_t PsychicWebSocketRequest::reply(httpd_ws_type_t op, const void *data, size_t len)
|
||||||
{
|
{
|
||||||
httpd_ws_frame_t ws_pkt;
|
httpd_ws_frame_t ws_pkt;
|
||||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||||
|
|
||||||
ws_pkt.payload = (uint8_t *)data;
|
ws_pkt.payload = (uint8_t*)data;
|
||||||
ws_pkt.len = len;
|
ws_pkt.len = len;
|
||||||
ws_pkt.type = op;
|
ws_pkt.type = op;
|
||||||
|
|
||||||
@@ -45,25 +45,24 @@ esp_err_t PsychicWebSocketRequest::reply(const char *buf)
|
|||||||
/*************************************/
|
/*************************************/
|
||||||
|
|
||||||
PsychicWebSocketClient::PsychicWebSocketClient(PsychicClient *client)
|
PsychicWebSocketClient::PsychicWebSocketClient(PsychicClient *client)
|
||||||
: PsychicClient(client->server(), client->socket())
|
: PsychicClient(client->server(), client->socket())
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebSocketClient::~PsychicWebSocketClient()
|
PsychicWebSocketClient::~PsychicWebSocketClient() {
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t PsychicWebSocketClient::sendMessage(httpd_ws_frame_t *ws_pkt)
|
esp_err_t PsychicWebSocketClient::sendMessage(httpd_ws_frame_t * ws_pkt)
|
||||||
{
|
{
|
||||||
return httpd_ws_send_frame_async(this->server(), this->socket(), ws_pkt);
|
return httpd_ws_send_frame_async(this->server(), this->socket(), ws_pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t PsychicWebSocketClient::sendMessage(httpd_ws_type_t op, const void *data, size_t len)
|
esp_err_t PsychicWebSocketClient::sendMessage(httpd_ws_type_t op, const void *data, size_t len)
|
||||||
{
|
{
|
||||||
httpd_ws_frame_t ws_pkt;
|
httpd_ws_frame_t ws_pkt;
|
||||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||||
|
|
||||||
ws_pkt.payload = (uint8_t *)data;
|
ws_pkt.payload = (uint8_t*)data;
|
||||||
ws_pkt.len = len;
|
ws_pkt.len = len;
|
||||||
ws_pkt.type = op;
|
ws_pkt.type = op;
|
||||||
|
|
||||||
@@ -75,18 +74,18 @@ esp_err_t PsychicWebSocketClient::sendMessage(const char *buf)
|
|||||||
return this->sendMessage(HTTPD_WS_TYPE_TEXT, buf, strlen(buf));
|
return this->sendMessage(HTTPD_WS_TYPE_TEXT, buf, strlen(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebSocketHandler::PsychicWebSocketHandler() : PsychicHandler(),
|
PsychicWebSocketHandler::PsychicWebSocketHandler() :
|
||||||
_onOpen(NULL),
|
PsychicHandler(),
|
||||||
_onFrame(NULL),
|
_onOpen(NULL),
|
||||||
_onClose(NULL)
|
_onFrame(NULL),
|
||||||
{
|
_onClose(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
PsychicWebSocketHandler::~PsychicWebSocketHandler() {
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebSocketHandler::~PsychicWebSocketHandler()
|
PsychicWebSocketClient * PsychicWebSocketHandler::getClient(int socket)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
PsychicWebSocketClient *PsychicWebSocketHandler::getClient(int socket)
|
|
||||||
{
|
{
|
||||||
PsychicClient *client = PsychicHandler::getClient(socket);
|
PsychicClient *client = PsychicHandler::getClient(socket);
|
||||||
if (client == NULL)
|
if (client == NULL)
|
||||||
@@ -94,37 +93,31 @@ PsychicWebSocketClient *PsychicWebSocketHandler::getClient(int socket)
|
|||||||
|
|
||||||
if (client->_friend == NULL)
|
if (client->_friend == NULL)
|
||||||
{
|
{
|
||||||
DUMP(socket);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (PsychicWebSocketClient *)client->_friend;
|
return (PsychicWebSocketClient *)client->_friend;
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebSocketClient *PsychicWebSocketHandler::getClient(PsychicClient *client)
|
PsychicWebSocketClient * PsychicWebSocketHandler::getClient(PsychicClient *client) {
|
||||||
{
|
|
||||||
return getClient(client->socket());
|
return getClient(client->socket());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PsychicWebSocketHandler::addClient(PsychicClient *client)
|
void PsychicWebSocketHandler::addClient(PsychicClient *client) {
|
||||||
{
|
|
||||||
client->_friend = new PsychicWebSocketClient(client);
|
client->_friend = new PsychicWebSocketClient(client);
|
||||||
PsychicHandler::addClient(client);
|
PsychicHandler::addClient(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PsychicWebSocketHandler::removeClient(PsychicClient *client)
|
void PsychicWebSocketHandler::removeClient(PsychicClient *client) {
|
||||||
{
|
|
||||||
PsychicHandler::removeClient(client);
|
PsychicHandler::removeClient(client);
|
||||||
delete (PsychicWebSocketClient *)client->_friend;
|
delete (PsychicWebSocketClient*)client->_friend;
|
||||||
client->_friend = NULL;
|
client->_friend = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PsychicWebSocketHandler::openCallback(PsychicClient *client)
|
void PsychicWebSocketHandler::openCallback(PsychicClient *client) {
|
||||||
{
|
|
||||||
PsychicWebSocketClient *buddy = getClient(client);
|
PsychicWebSocketClient *buddy = getClient(client);
|
||||||
if (buddy == NULL)
|
if (buddy == NULL)
|
||||||
{
|
{
|
||||||
TRACE();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -132,12 +125,10 @@ void PsychicWebSocketHandler::openCallback(PsychicClient *client)
|
|||||||
_onOpen(getClient(buddy));
|
_onOpen(getClient(buddy));
|
||||||
}
|
}
|
||||||
|
|
||||||
void PsychicWebSocketHandler::closeCallback(PsychicClient *client)
|
void PsychicWebSocketHandler::closeCallback(PsychicClient *client) {
|
||||||
{
|
|
||||||
PsychicWebSocketClient *buddy = getClient(client);
|
PsychicWebSocketClient *buddy = getClient(client);
|
||||||
if (buddy == NULL)
|
if (buddy == NULL)
|
||||||
{
|
{
|
||||||
TRACE();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,7 +140,7 @@ bool PsychicWebSocketHandler::isWebSocket() { return true; }
|
|||||||
|
|
||||||
esp_err_t PsychicWebSocketHandler::handleRequest(PsychicRequest *request)
|
esp_err_t PsychicWebSocketHandler::handleRequest(PsychicRequest *request)
|
||||||
{
|
{
|
||||||
// lookup our client
|
//lookup our client
|
||||||
PsychicClient *client = checkForNewClient(request->client());
|
PsychicClient *client = checkForNewClient(request->client());
|
||||||
|
|
||||||
// beginning of the ws URI handler and our onConnect hook
|
// beginning of the ws URI handler and our onConnect hook
|
||||||
@@ -161,10 +152,10 @@ esp_err_t PsychicWebSocketHandler::handleRequest(PsychicRequest *request)
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// prep our request
|
//prep our request
|
||||||
PsychicWebSocketRequest wsRequest(request);
|
PsychicWebSocketRequest wsRequest(request);
|
||||||
|
|
||||||
// init our memory for storing the packet
|
//init our memory for storing the packet
|
||||||
httpd_ws_frame_t ws_pkt;
|
httpd_ws_frame_t ws_pkt;
|
||||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||||
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||||
@@ -172,33 +163,29 @@ esp_err_t PsychicWebSocketHandler::handleRequest(PsychicRequest *request)
|
|||||||
|
|
||||||
/* Set max_len = 0 to get the frame len */
|
/* Set max_len = 0 to get the frame len */
|
||||||
esp_err_t ret = httpd_ws_recv_frame(wsRequest.request(), &ws_pkt, 0);
|
esp_err_t ret = httpd_ws_recv_frame(wsRequest.request(), &ws_pkt, 0);
|
||||||
if (ret != ESP_OK)
|
if (ret != ESP_OK) {
|
||||||
{
|
|
||||||
ESP_LOGE(PH_TAG, "httpd_ws_recv_frame failed to get frame len with %s", esp_err_to_name(ret));
|
ESP_LOGE(PH_TAG, "httpd_ws_recv_frame failed to get frame len with %s", esp_err_to_name(ret));
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// okay, now try to load the packet
|
//okay, now try to load the packet
|
||||||
ESP_LOGV(PH_TAG, "frame len is %d", ws_pkt.len);
|
//ESP_LOGD(PH_TAG, "frame len is %d", ws_pkt.len);
|
||||||
if (ws_pkt.len)
|
if (ws_pkt.len) {
|
||||||
{
|
|
||||||
/* ws_pkt.len + 1 is for NULL termination as we are expecting a string */
|
/* ws_pkt.len + 1 is for NULL termination as we are expecting a string */
|
||||||
buf = (uint8_t *)calloc(1, ws_pkt.len + 1);
|
buf = (uint8_t*) calloc(1, ws_pkt.len + 1);
|
||||||
if (buf == NULL)
|
if (buf == NULL) {
|
||||||
{
|
|
||||||
ESP_LOGE(PH_TAG, "Failed to calloc memory for buf");
|
ESP_LOGE(PH_TAG, "Failed to calloc memory for buf");
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
ws_pkt.payload = buf;
|
ws_pkt.payload = buf;
|
||||||
/* Set max_len = ws_pkt.len to get the frame payload */
|
/* Set max_len = ws_pkt.len to get the frame payload */
|
||||||
ret = httpd_ws_recv_frame(wsRequest.request(), &ws_pkt, ws_pkt.len);
|
ret = httpd_ws_recv_frame(wsRequest.request(), &ws_pkt, ws_pkt.len);
|
||||||
if (ret != ESP_OK)
|
if (ret != ESP_OK) {
|
||||||
{
|
|
||||||
ESP_LOGE(PH_TAG, "httpd_ws_recv_frame failed with %s", esp_err_to_name(ret));
|
ESP_LOGE(PH_TAG, "httpd_ws_recv_frame failed with %s", esp_err_to_name(ret));
|
||||||
free(buf);
|
free(buf);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ESP_LOGV(PH_TAG, "Got packet with message: %s", ws_pkt.payload);
|
//ESP_LOGD(PH_TAG, "Got packet with message: %s", ws_pkt.payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text messages are our payload.
|
// Text messages are our payload.
|
||||||
@@ -208,49 +195,47 @@ esp_err_t PsychicWebSocketHandler::handleRequest(PsychicRequest *request)
|
|||||||
ret = this->_onFrame(&wsRequest, &ws_pkt);
|
ret = this->_onFrame(&wsRequest, &ws_pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// logging housekeeping
|
//logging housekeeping
|
||||||
if (ret != ESP_OK)
|
if (ret != ESP_OK)
|
||||||
ESP_LOGE(PH_TAG, "httpd_ws_send_frame failed with %s", esp_err_to_name(ret));
|
ESP_LOGE(PH_TAG, "httpd_ws_send_frame failed with %s", esp_err_to_name(ret));
|
||||||
// ESP_LOGI(PH_TAG, "ws_handler: httpd_handle_t=%p, sockfd=%d, client_info:%d", request->server(),
|
// ESP_LOGD(PH_TAG, "ws_handler: httpd_handle_t=%p, sockfd=%d, client_info:%d",
|
||||||
// httpd_req_to_sockfd(request->request()), httpd_ws_get_fd_info(request->server(), httpd_req_to_sockfd(request->request())));
|
// request->server(),
|
||||||
|
// httpd_req_to_sockfd(request->request()),
|
||||||
|
// httpd_ws_get_fd_info(request->server()->server, httpd_req_to_sockfd(request->request())));
|
||||||
|
|
||||||
// dont forget to release our buffer memory
|
//dont forget to release our buffer memory
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebSocketHandler *PsychicWebSocketHandler::onOpen(PsychicWebSocketClientCallback fn)
|
PsychicWebSocketHandler * PsychicWebSocketHandler::onOpen(PsychicWebSocketClientCallback fn) {
|
||||||
{
|
|
||||||
_onOpen = fn;
|
_onOpen = fn;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebSocketHandler *PsychicWebSocketHandler::onFrame(PsychicWebSocketFrameCallback fn)
|
PsychicWebSocketHandler * PsychicWebSocketHandler::onFrame(PsychicWebSocketFrameCallback fn) {
|
||||||
{
|
|
||||||
_onFrame = fn;
|
_onFrame = fn;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
PsychicWebSocketHandler *PsychicWebSocketHandler::onClose(PsychicWebSocketClientCallback fn)
|
PsychicWebSocketHandler * PsychicWebSocketHandler::onClose(PsychicWebSocketClientCallback fn) {
|
||||||
{
|
|
||||||
_onClose = fn;
|
_onClose = fn;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PsychicWebSocketHandler::sendAll(httpd_ws_frame_t *ws_pkt)
|
void PsychicWebSocketHandler::sendAll(httpd_ws_frame_t * ws_pkt)
|
||||||
{
|
{
|
||||||
for (PsychicClient *client : _clients)
|
for (PsychicClient *client : _clients)
|
||||||
{
|
{
|
||||||
ESP_LOGD(PH_TAG, "Active client (fd=%d) -> sending async message", client->socket());
|
//ESP_LOGD(PH_TAG, "Active client (fd=%d) -> sending async message", client->socket());
|
||||||
|
|
||||||
if (client->_friend == NULL)
|
if (client->_friend == NULL)
|
||||||
{
|
{
|
||||||
TRACE();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (((PsychicWebSocketClient *)client->_friend)->sendMessage(ws_pkt) != ESP_OK)
|
if (((PsychicWebSocketClient*)client->_friend)->sendMessage(ws_pkt) != ESP_OK)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -260,7 +245,7 @@ void PsychicWebSocketHandler::sendAll(httpd_ws_type_t op, const void *data, size
|
|||||||
httpd_ws_frame_t ws_pkt;
|
httpd_ws_frame_t ws_pkt;
|
||||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||||
|
|
||||||
ws_pkt.payload = (uint8_t *)data;
|
ws_pkt.payload = (uint8_t*)data;
|
||||||
ws_pkt.len = len;
|
ws_pkt.len = len;
|
||||||
ws_pkt.type = op;
|
ws_pkt.type = op;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/************************************************************
|
||||||
|
|
||||||
|
TemplatePrinter Class
|
||||||
|
|
||||||
|
A basic templating engine for a stream of text.
|
||||||
|
This wraps the Arduino Print interface and writes to any
|
||||||
|
Print interface.
|
||||||
|
|
||||||
|
Written by Christopher Andrews (https://github.com/Chris--A)
|
||||||
|
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
#include "TemplatePrinter.h"
|
||||||
|
|
||||||
|
void TemplatePrinter::resetParam(bool flush){
|
||||||
|
if(flush && _inParam){
|
||||||
|
_stream.write(_delimiter);
|
||||||
|
|
||||||
|
if(_paramPos)
|
||||||
|
_stream.print(_paramBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(_paramBuffer, 0, sizeof(_paramBuffer));
|
||||||
|
_paramPos = 0;
|
||||||
|
_inParam = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TemplatePrinter::flush(){
|
||||||
|
resetParam(true);
|
||||||
|
_stream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t TemplatePrinter::write(uint8_t data){
|
||||||
|
|
||||||
|
if(data == _delimiter){
|
||||||
|
|
||||||
|
// End of parameter, send to callback
|
||||||
|
if(_inParam){
|
||||||
|
|
||||||
|
// On false, return the parameter place holder as is: not a parameter
|
||||||
|
// Bug fix: ignore parameters that are zero length.
|
||||||
|
if(!_paramPos || !_cb(_stream, _paramBuffer)){
|
||||||
|
resetParam(true);
|
||||||
|
_stream.write(data);
|
||||||
|
}else{
|
||||||
|
resetParam(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start collecting parameter
|
||||||
|
}else{
|
||||||
|
_inParam = true;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
|
||||||
|
// Are we collecting
|
||||||
|
if(_inParam){
|
||||||
|
|
||||||
|
// Is param still valid
|
||||||
|
if(isalnum(data) || data == '_'){
|
||||||
|
|
||||||
|
// Total param len must be 63, 1 for null.
|
||||||
|
if(_paramPos < sizeof(_paramBuffer) - 1){
|
||||||
|
_paramBuffer[_paramPos++] = data;
|
||||||
|
|
||||||
|
// Not a valid param
|
||||||
|
}else{
|
||||||
|
resetParam(true);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
resetParam(true);
|
||||||
|
_stream.write(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just output
|
||||||
|
}else{
|
||||||
|
_stream.write(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t TemplatePrinter::copyFrom(Stream &stream){
|
||||||
|
size_t count = 0;
|
||||||
|
|
||||||
|
while(stream.available())
|
||||||
|
count += this->write(stream.read());
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
#ifndef TemplatePrinter_h
|
||||||
|
#define TemplatePrinter_h
|
||||||
|
|
||||||
|
#include "PsychicCore.h"
|
||||||
|
#include <Print.h>
|
||||||
|
|
||||||
|
/************************************************************
|
||||||
|
|
||||||
|
TemplatePrinter Class
|
||||||
|
|
||||||
|
A basic templating engine for a stream of text.
|
||||||
|
This wraps the Arduino Print interface and writes to any
|
||||||
|
Print interface.
|
||||||
|
|
||||||
|
Written by Christopher Andrews (https://github.com/Chris--A)
|
||||||
|
|
||||||
|
************************************************************/
|
||||||
|
|
||||||
|
class TemplatePrinter;
|
||||||
|
|
||||||
|
typedef std::function<bool(Print &output, const char *parameter)> TemplateCallback;
|
||||||
|
typedef std::function<void(TemplatePrinter &printer)> TemplateSourceCallback;
|
||||||
|
|
||||||
|
class TemplatePrinter : public Print{
|
||||||
|
private:
|
||||||
|
bool _inParam;
|
||||||
|
char _paramBuffer[64];
|
||||||
|
uint8_t _paramPos;
|
||||||
|
Print &_stream;
|
||||||
|
TemplateCallback _cb;
|
||||||
|
char _delimiter;
|
||||||
|
|
||||||
|
void resetParam(bool flush);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using Print::write;
|
||||||
|
|
||||||
|
static void start(Print &stream, TemplateCallback cb, TemplateSourceCallback entry){
|
||||||
|
TemplatePrinter printer(stream, cb);
|
||||||
|
entry(printer);
|
||||||
|
}
|
||||||
|
|
||||||
|
TemplatePrinter(Print &stream, TemplateCallback cb, const char delimeter = '%') : _stream(stream), _cb(cb), _delimiter(delimeter) { resetParam(false); }
|
||||||
|
~TemplatePrinter(){ flush(); }
|
||||||
|
|
||||||
|
void flush() override;
|
||||||
|
size_t write(uint8_t data) override;
|
||||||
|
size_t copyFrom(Stream &stream);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -166,7 +166,7 @@ esp_err_t httpd_req_async_handler_begin(httpd_req_t *r, httpd_req_t **out)
|
|||||||
if (async == NULL) {
|
if (async == NULL) {
|
||||||
return ESP_ERR_NO_MEM;
|
return ESP_ERR_NO_MEM;
|
||||||
}
|
}
|
||||||
memcpy(async, r, sizeof(httpd_req_t));
|
memcpy((void *)async, (void *)r, sizeof(httpd_req_t));
|
||||||
|
|
||||||
// alloc async aux
|
// alloc async aux
|
||||||
async->aux = (httpd_req_aux *)malloc(sizeof(struct httpd_req_aux));
|
async->aux = (httpd_req_aux *)malloc(sizeof(struct httpd_req_aux));
|
||||||
|
|||||||
Reference in New Issue
Block a user