wifi webserver works again

This commit is contained in:
technyon
2022-04-29 20:48:33 +02:00
parent 0dd94a97a3
commit 0e9baed3a4
50 changed files with 440 additions and 466 deletions

View File

@@ -4,6 +4,11 @@ set(ARDUINO_BOARD "ESP32 Dev Module [esp32.esp32]")
project(nuki_hub CXX) project(nuki_hub CXX)
# ARDUHAL_LOG_LEVEL_NONE, define ARDUHAL_LOG_LEVEL_ERROR, define ARDUHAL_LOG_LEVEL_WARN, define ARDUHAL_LOG_LEVEL_INFO,
# define ARDUHAL_LOG_LEVEL_DEBUG, define ARDUHAL_LOG_LEVEL_VERBOSE
set(LOG_LEVEL ARDUHAL_LOG_LEVEL_NONE)
include_directories(${PROJECT_NAME} include_directories(${PROJECT_NAME}
PRIVATE PRIVATE
lib/Crc16 lib/Crc16
@@ -12,10 +17,12 @@ include_directories(${PROJECT_NAME}
lib/ESP32_BLE_Arduino-1.0.1/src lib/ESP32_BLE_Arduino-1.0.1/src
lib/WiFiManager lib/WiFiManager
lib/pubsubclient/src lib/pubsubclient/src
lib/EthernetWebServer/src lib/WebServer/src
) )
file(GLOB SRCFILES file(GLOB SRCFILES
# "Lib/FreeRTOS/src/*.c"
# "Lib/FreeRTOS/src/*.cpp"
Pins.h Pins.h
Network.cpp Network.cpp
networkDevices/NetworkDevice.h networkDevices/NetworkDevice.h
@@ -28,9 +35,6 @@ file(GLOB SRCFILES
PreferencesKeys.h PreferencesKeys.h
SpiffsCookie.cpp SpiffsCookie.cpp
Version.h Version.h
webserver/AbstractWebServer.h
webserver/EthWebServer.cpp
webserver/WifiWebServer.cpp
lib/ESP32_BLE_Arduino-1.0.1/src/*.cpp lib/ESP32_BLE_Arduino-1.0.1/src/*.cpp
lib/ESP32_BLE_Arduino-1.0.1/src/*.h lib/ESP32_BLE_Arduino-1.0.1/src/*.h
lib/WiFiManager/WiFiManager.cpp lib/WiFiManager/WiFiManager.cpp
@@ -47,8 +51,8 @@ file(GLOB_RECURSE SRCFILESREC
lib/NimBLE-Arduino/src/*.c lib/NimBLE-Arduino/src/*.c
lib/NimBLE-Arduino/src/*.cpp lib/NimBLE-Arduino/src/*.cpp
lib/NimBLE-Arduino/src/*.h lib/NimBLE-Arduino/src/*.h
lib/EthernetWebServer/src/*.cpp lib/WebServer/src/*.cpp
lib/EthernetWebServer/src/*.h lib/WebServer/src/*.h
) )
add_executable(${PROJECT_NAME} add_executable(${PROJECT_NAME}
@@ -57,13 +61,19 @@ add_executable(${PROJECT_NAME}
${SRCFILESREC} ${SRCFILESREC}
) )
# Arduino.h is included in hello_world.cpp, so link with Arduino core target_compile_definitions(${PROJECT_NAME}
PRIVATE
ARDUHAL_LOG_LEVEL=${LOG_LEVEL}
CORE_DEBUG_LEVEL=${LOG_LEVEL}
CONFIG_NIMBLE_CPP_LOG_LEVEL=0
)
target_link_arduino_libraries(${PROJECT_NAME} target_link_arduino_libraries(${PROJECT_NAME}
PRIVATE PRIVATE
core core
WiFi WiFi
Update Update
WebServer # WebServer
DNSServer DNSServer
Preferences Preferences
SPIFFS SPIFFS

View File

@@ -1,4 +1,5 @@
#include "Network.h" #include "Network.h"
#include <WiFiManager.h> // https://github.com/tzapu/WiFiManager
#include "Arduino.h" #include "Arduino.h"
#include "MqttTopics.h" #include "MqttTopics.h"
#include "PreferencesKeys.h" #include "PreferencesKeys.h"

View File

@@ -1,10 +1,10 @@
#include "WebCfgServer.h" #include "WebCfgServer.h"
#include "PreferencesKeys.h" #include "PreferencesKeys.h"
#include "Version.h" #include "Version.h"
#include "webserver/EthWebServer.h" #include "WifiEthServer.h"
WebCfgServer::WebCfgServer(NukiWrapper* nuki, Network* network, Preferences* preferences) WebCfgServer::WebCfgServer(NukiWrapper* nuki, Network* network, Preferences* preferences)
: _server(new EthWebServer(80)), : _server(new WifiEthServer(80)),
_nuki(nuki), _nuki(nuki),
_network(network), _network(network),
_preferences(preferences) _preferences(preferences)
@@ -26,43 +26,43 @@ WebCfgServer::WebCfgServer(NukiWrapper* nuki, Network* network, Preferences* pre
void WebCfgServer::initialize() void WebCfgServer::initialize()
{ {
_server->on("/", [&]() { _server.on("/", [&]() {
if (_hasCredentials && !_server->authenticate(_credUser, _credPassword)) { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server->requestAuthentication(); return _server.requestAuthentication();
} }
String response = ""; String response = "";
buildHtml(response); buildHtml(response);
_server->send(200, "text/html", response); _server.send(200, "text/html", response);
}); });
_server->on("/cred", [&]() { _server.on("/cred", [&]() {
if (_hasCredentials && !_server->authenticate(_credUser, _credPassword)) { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server->requestAuthentication(); return _server.requestAuthentication();
} }
String response = ""; String response = "";
buildCredHtml(response); buildCredHtml(response);
_server->send(200, "text/html", response); _server.send(200, "text/html", response);
}); });
_server->on("/wifi", [&]() { _server.on("/wifi", [&]() {
if (_hasCredentials && !_server->authenticate(_credUser, _credPassword)) { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server->requestAuthentication(); return _server.requestAuthentication();
} }
String response = ""; String response = "";
buildConfigureWifiHtml(response); buildConfigureWifiHtml(response);
_server->send(200, "text/html", response); _server.send(200, "text/html", response);
}); });
_server->on("/wifimanager", [&]() { _server.on("/wifimanager", [&]() {
if (_hasCredentials && !_server->authenticate(_credUser, _credPassword)) { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server->requestAuthentication(); return _server.requestAuthentication();
} }
String response = ""; String response = "";
buildConfirmHtml(response, "Restarting. Connect to ESP access point to reconfigure WiFi.", 0); buildConfirmHtml(response, "Restarting. Connect to ESP access point to reconfigure WiFi.", 0);
_server->send(200, "text/html", response); _server.send(200, "text/html", response);
waitAndProcess(true, 2000); waitAndProcess(true, 2000);
_network->restartAndConfigureWifi(); _network->restartAndConfigureWifi();
}); });
_server->on("/method=get", [&]() { _server.on("/method=get", [&]() {
if (_hasCredentials && !_server->authenticate(_credUser, _credPassword)) { if (_hasCredentials && !_server.authenticate(_credUser, _credPassword)) {
return _server->requestAuthentication(); return _server.requestAuthentication();
} }
String message = ""; String message = "";
bool restartEsp = processArgs(message); bool restartEsp = processArgs(message);
@@ -70,7 +70,7 @@ void WebCfgServer::initialize()
{ {
String response = ""; String response = "";
buildConfirmHtml(response, message); buildConfirmHtml(response, message);
_server->send(200, "text/html", response); _server.send(200, "text/html", response);
Serial.println(F("Restarting")); Serial.println(F("Restarting"));
waitAndProcess(true, 1000); waitAndProcess(true, 1000);
@@ -80,12 +80,12 @@ void WebCfgServer::initialize()
{ {
String response = ""; String response = "";
buildConfirmHtml(response, message, 3); buildConfirmHtml(response, message, 3);
_server->send(200, "text/html", response); _server.send(200, "text/html", response);
waitAndProcess(false, 1000); waitAndProcess(false, 1000);
} }
}); });
_server->begin(); _server.begin();
} }
bool WebCfgServer::processArgs(String& message) bool WebCfgServer::processArgs(String& message)
@@ -94,11 +94,11 @@ bool WebCfgServer::processArgs(String& message)
bool clearMqttCredentials = false; bool clearMqttCredentials = false;
bool clearCredentials = false; bool clearCredentials = false;
int count = _server->args(); int count = _server.args();
for(int index = 0; index < count; index++) for(int index = 0; index < count; index++)
{ {
String key = _server->argName(index); String key = _server.argName(index);
String value = _server->arg(index); String value = _server.arg(index);
if(key == "MQTTSERVER") if(key == "MQTTSERVER")
{ {
@@ -215,7 +215,7 @@ void WebCfgServer::update()
{ {
if(!_enabled) return; if(!_enabled) return;
_server->handleClient(); _server.handleClient();
} }
void WebCfgServer::buildHtml(String& response) void WebCfgServer::buildHtml(String& response)
@@ -399,7 +399,7 @@ void WebCfgServer::waitAndProcess(const bool blocking, const uint32_t duration)
unsigned long timeout = millis() + duration; unsigned long timeout = millis() + duration;
while(millis() < timeout) while(millis() < timeout)
{ {
_server->handleClient(); _server.handleClient();
if(blocking) if(blocking)
{ {
delay(10); delay(10);

View File

@@ -1,10 +1,9 @@
#pragma once #pragma once
#include <Preferences.h> #include <Preferences.h>
#include <EthernetWebServer.h> #include <WebServer.h>
#include "NukiWrapper.h" #include "NukiWrapper.h"
#include "Network.h" #include "Network.h"
#include "webserver/AbstractWebServer.h"
enum class TokenType enum class TokenType
{ {
@@ -43,7 +42,7 @@ private:
void waitAndProcess(const bool blocking, const uint32_t duration); void waitAndProcess(const bool blocking, const uint32_t duration);
AbstractWebServer* _server; WebServer _server;
NukiWrapper* _nuki; NukiWrapper* _nuki;
Network* _network; Network* _network;
Preferences* _preferences; Preferences* _preferences;

View File

@@ -1,29 +0,0 @@
#include "EthernetServerImpl.h"
EthernetServerImpl::EthernetServerImpl(IPAddress addr, int port)
: EthernetServer(port)
{}
EthernetServerImpl::EthernetServerImpl(int port)
: EthernetServer(port)
{}
void EthernetServerImpl::begin(uint16_t port)
{
EthernetServer::begin();
}
void EthernetServerImpl::begin()
{
EthernetServer::begin();
}
void EthernetServerImpl::close()
{
}
int EthernetServerImpl::setNoDelay(bool nodelay)
{
return 0;
}

View File

@@ -1,15 +0,0 @@
#pragma once
#include <EthernetServer.h>
class EthernetServerImpl : public EthernetServer
{
public:
EthernetServerImpl(IPAddress addr, int port);
EthernetServerImpl(int port);
void begin();
void begin(uint16_t port);
void close();
int setNoDelay(bool nodelay);
};

View File

@@ -30,7 +30,7 @@
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <EthernetWebServer.h> #include <WebServer.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
const char *ssid = "YourSSIDHere"; const char *ssid = "YourSSIDHere";

View File

@@ -1,7 +1,7 @@
/* /*
FSWebServer - Example EthernetWebServer with FS backend for esp8266/esp32 FSWebServer - Example WebServer with FS backend for esp8266/esp32
Copyright (c) 2015 Hristo Gochkov. All rights reserved. Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the EthernetWebServer library for Arduino environment. This file is part of the WebServer library for Arduino environment.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@@ -24,7 +24,7 @@
*/ */
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <EthernetWebServer.h> #include <WebServer.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#define FILESYSTEM SPIFFS #define FILESYSTEM SPIFFS

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,7 +1,7 @@
<!-- <!--
FSWebServer - Example Index Page FSWebServer - Example Index Page
Copyright (c) 2015 Hristo Gochkov. All rights reserved. Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the EthernetWebServer library for Arduino environment. This file is part of the WebServer library for Arduino environment.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public

View File

@@ -1,6 +1,6 @@
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <EthernetWebServer.h> #include <WebServer.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
const char* ssid = "........"; const char* ssid = "........";

View File

@@ -7,7 +7,7 @@
#include <WiFi.h> #include <WiFi.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#include <EthernetWebServer.h> #include <WebServer.h>
const char* ssid = "........"; const char* ssid = "........";
const char* password = "........"; const char* password = "........";

View File

@@ -1,7 +1,7 @@
#include <WiFi.h> #include <WiFi.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <ArduinoOTA.h> #include <ArduinoOTA.h>
#include <EthernetWebServer.h> #include <WebServer.h>
const char* ssid = "........"; const char* ssid = "........";
const char* password = "........"; const char* password = "........";

View File

@@ -1,6 +1,6 @@
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <EthernetWebServer.h> #include <WebServer.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <uri/UriBraces.h> #include <uri/UriBraces.h>

View File

@@ -1,8 +1,8 @@
/* /*
SDWebServer - Example EthernetWebServer with SD Card backend for esp8266 SDWebServer - Example WebServer with SD Card backend for esp8266
Copyright (c) 2015 Hristo Gochkov. All rights reserved. Copyright (c) 2015 Hristo Gochkov. All rights reserved.
This file is part of the EthernetWebServer library for Arduino environment. This file is part of the WebServer library for Arduino environment.
This library is free software; you can redistribute it and/or This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public modify it under the terms of the GNU Lesser General Public
@@ -29,7 +29,7 @@
*/ */
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <EthernetWebServer.h> #include <WebServer.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <SPI.h> #include <SPI.h>
#include <SD.h> #include <SD.h>

View File

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 174 KiB

View File

@@ -1,6 +1,6 @@
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <EthernetWebServer.h> #include <WebServer.h>
const char* ssid = "........"; const char* ssid = "........";
const char* password = "........"; const char* password = "........";

View File

@@ -4,7 +4,7 @@
#include <WiFi.h> #include <WiFi.h>
#include <WiFiClient.h> #include <WiFiClient.h>
#include <EthernetWebServer.h> #include <WebServer.h>
#include <ESPmDNS.h> #include <ESPmDNS.h>
#include <Update.h> #include <Update.h>

View File

@@ -0,0 +1,22 @@
#pragma once
#include <stdint.h>
#include <cstddef>
class EthClient
{
public:
virtual uint8_t connected() = 0;
virtual int available() = 0;
virtual unsigned long getTimeout(void) = 0;
virtual int setTimeout(uint32_t seconds) = 0;
virtual int read() = 0;
virtual size_t write(const char *buffer, size_t size) = 0;
virtual size_t write_P(PGM_P buf, size_t size) = 0;
virtual size_t write(Stream &stream) = 0;
virtual String readStringUntil(char terminator) = 0;
virtual size_t readBytes(char *buffer, size_t length) = 0;
virtual IPAddress localIP() = 0;
virtual void stop() = 0;
virtual void flush() = 0;
};

View File

@@ -0,0 +1,20 @@
#pragma once
#include <IPAddress.h>
#include <WiFiClient.h>
#include "EthClient.h"
class EthServer
{
public:
EthServer(IPAddress address, int port) { }
EthServer(int port) { }
virtual EthClient* available() = 0;
virtual void discardClient() = 0;
virtual void close() = 0;
virtual void begin(const int port = 80) = 0;
virtual void setNoDelay(const bool value) = 0;
};

View File

@@ -22,8 +22,8 @@
#include <Arduino.h> #include <Arduino.h>
#include <esp32-hal-log.h> #include <esp32-hal-log.h>
#include "WiFiServer.h" #include "WiFiServer.h"
#include "EthernetClient.h" #include "WiFiClient.h"
#include "EthernetWebServer.h" #include "WebServer.h"
#include "detail/mimetable.h" #include "detail/mimetable.h"
#ifndef WEBSERVER_MAX_POST_ARGS #ifndef WEBSERVER_MAX_POST_ARGS
@@ -32,7 +32,7 @@
#define __STR(a) #a #define __STR(a) #a
#define _STR(a) __STR(a) #define _STR(a) __STR(a)
const char * _eth_http_method_str[] = { const char * _http_method_str[] = {
#define XX(num, name, string) _STR(name), #define XX(num, name, string) _STR(name),
HTTP_METHOD_MAP(XX) HTTP_METHOD_MAP(XX)
#undef XX #undef XX
@@ -41,14 +41,14 @@ const char * _eth_http_method_str[] = {
static const char Content_Type[] PROGMEM = "Content-Type"; static const char Content_Type[] PROGMEM = "Content-Type";
static const char filename[] PROGMEM = "filename"; static const char filename[] PROGMEM = "filename";
static char* readBytesWithTimeout(EthernetClient& client, size_t maxLength, size_t& dataLength, int timeout_ms) static char* readBytesWithTimeout(EthClient* client, size_t maxLength, size_t& dataLength, int timeout_ms)
{ {
char *buf = nullptr; char *buf = nullptr;
dataLength = 0; dataLength = 0;
while (dataLength < maxLength) { while (dataLength < maxLength) {
int tries = timeout_ms; int tries = timeout_ms;
size_t newLength; size_t newLength;
while (!(newLength = client.available()) && tries--) delay(1); while (!(newLength = client->available()) && tries--) delay(1);
if (!newLength) { if (!newLength) {
break; break;
} }
@@ -66,17 +66,17 @@ static char* readBytesWithTimeout(EthernetClient& client, size_t maxLength, size
} }
buf = newBuf; buf = newBuf;
} }
client.readBytes(buf + dataLength, newLength); client->readBytes(buf + dataLength, newLength);
dataLength += newLength; dataLength += newLength;
buf[dataLength] = '\0'; buf[dataLength] = '\0';
} }
return buf; return buf;
} }
bool EthernetWebServer::_parseRequest(EthernetClient& client) { bool WebServer::_parseRequest(EthClient* client) {
// Read the first line of HTTP request // Read the first line of HTTP request
String req = client.readStringUntil('\r'); String req = client->readStringUntil('\r');
client.readStringUntil('\n'); client->readStringUntil('\n');
//reset header value //reset header value
for (int i = 0; i < _headerKeysCount; ++i) { for (int i = 0; i < _headerKeysCount; ++i) {
_currentHeaders[i].value =String(); _currentHeaders[i].value =String();
@@ -105,9 +105,9 @@ bool EthernetWebServer::_parseRequest(EthernetClient& client) {
_chunked = false; _chunked = false;
HTTPMethod method = HTTP_ANY; HTTPMethod method = HTTP_ANY;
size_t num_methods = sizeof(_eth_http_method_str) / sizeof(const char *); size_t num_methods = sizeof(_http_method_str) / sizeof(const char *);
for (size_t i=0; i<num_methods; i++) { for (size_t i=0; i<num_methods; i++) {
if (methodStr == _eth_http_method_str[i]) { if (methodStr == _http_method_str[i]) {
method = (HTTPMethod)i; method = (HTTPMethod)i;
break; break;
} }
@@ -139,8 +139,8 @@ bool EthernetWebServer::_parseRequest(EthernetClient& client) {
uint32_t contentLength = 0; uint32_t contentLength = 0;
//parse headers //parse headers
while(1){ while(1){
req = client.readStringUntil('\r'); req = client->readStringUntil('\r');
client.readStringUntil('\n'); client->readStringUntil('\n');
if (req == "") break;//no moar headers if (req == "") break;//no moar headers
int headerDiv = req.indexOf(':'); int headerDiv = req.indexOf(':');
if (headerDiv == -1){ if (headerDiv == -1){
@@ -213,8 +213,8 @@ bool EthernetWebServer::_parseRequest(EthernetClient& client) {
String headerValue; String headerValue;
//parse headers //parse headers
while(1){ while(1){
req = client.readStringUntil('\r'); req = client->readStringUntil('\r');
client.readStringUntil('\n'); client->readStringUntil('\n');
if (req == "") break;//no moar headers if (req == "") break;//no moar headers
int headerDiv = req.indexOf(':'); int headerDiv = req.indexOf(':');
if (headerDiv == -1){ if (headerDiv == -1){
@@ -233,7 +233,7 @@ bool EthernetWebServer::_parseRequest(EthernetClient& client) {
} }
_parseArguments(searchStr); _parseArguments(searchStr);
} }
client.flush(); client->flush();
log_v("Request: %s", url.c_str()); log_v("Request: %s", url.c_str());
log_v(" Arguments: %s", searchStr.c_str()); log_v(" Arguments: %s", searchStr.c_str());
@@ -241,7 +241,7 @@ bool EthernetWebServer::_parseRequest(EthernetClient& client) {
return true; return true;
} }
bool EthernetWebServer::_collectHeader(const char* headerName, const char* headerValue) { bool WebServer::_collectHeader(const char* headerName, const char* headerValue) {
for (int i = 0; i < _headerKeysCount; i++) { for (int i = 0; i < _headerKeysCount; i++) {
if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) { if (_currentHeaders[i].key.equalsIgnoreCase(headerName)) {
_currentHeaders[i].value=headerValue; _currentHeaders[i].value=headerValue;
@@ -251,7 +251,7 @@ bool EthernetWebServer::_collectHeader(const char* headerName, const char* heade
return false; return false;
} }
void EthernetWebServer::_parseArguments(String data) { void WebServer::_parseArguments(String data) {
log_v("args: %s", data.c_str()); log_v("args: %s", data.c_str());
if (_currentArgs) if (_currentArgs)
delete[] _currentArgs; delete[] _currentArgs;
@@ -300,7 +300,7 @@ void EthernetWebServer::_parseArguments(String data) {
} }
void EthernetWebServer::_uploadWriteByte(uint8_t b){ void WebServer::_uploadWriteByte(uint8_t b){
if (_currentUpload->currentSize == HTTP_UPLOAD_BUFLEN){ if (_currentUpload->currentSize == HTTP_UPLOAD_BUFLEN){
if(_currentHandler && _currentHandler->canUpload(_currentUri)) if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload); _currentHandler->upload(*this, _currentUri, *_currentUpload);
@@ -310,30 +310,30 @@ void EthernetWebServer::_uploadWriteByte(uint8_t b){
_currentUpload->buf[_currentUpload->currentSize++] = b; _currentUpload->buf[_currentUpload->currentSize++] = b;
} }
int EthernetWebServer::_uploadReadByte(EthernetClient& client){ int WebServer::_uploadReadByte(EthClient* client){
int res = client.read(); int res = client->read();
if(res < 0) { if(res < 0) {
// keep trying until you either read a valid byte or timeout // keep trying until you either read a valid byte or timeout
unsigned long startMillis = millis(); unsigned long startMillis = millis();
long timeoutIntervalMillis = client.getTimeout(); long timeoutIntervalMillis = client->getTimeout();
boolean timedOut = false; boolean timedOut = false;
for(;;) { for(;;) {
if (!client.connected()) return -1; if (!client->connected()) return -1;
// loosely modeled after blinkWithoutDelay pattern // loosely modeled after blinkWithoutDelay pattern
while(!timedOut && !client.available() && client.connected()){ while(!timedOut && !client->available() && client->connected()){
delay(2); delay(2);
timedOut = millis() - startMillis >= timeoutIntervalMillis; timedOut = millis() - startMillis >= timeoutIntervalMillis;
} }
res = client.read(); res = client->read();
if(res >= 0) { if(res >= 0) {
return res; // exit on a valid read return res; // exit on a valid read
} }
// NOTE: it is possible to get here and have all of the following // NOTE: it is possible to get here and have all of the following
// assertions hold true // assertions hold true
// //
// -- client.available() > 0 // -- client->available() > 0
// -- client.connected == true // -- client->connected == true
// -- res == -1 // -- res == -1
// //
// a simple retry strategy overcomes this which is to say the // a simple retry strategy overcomes this which is to say the
@@ -351,17 +351,17 @@ int EthernetWebServer::_uploadReadByte(EthernetClient& client){
return res; return res;
} }
bool EthernetWebServer::_parseForm(EthernetClient& client, String boundary, uint32_t len){ bool WebServer::_parseForm(EthClient* client, String boundary, uint32_t len){
(void) len; (void) len;
log_v("Parse Form: Boundary: %s Length: %d", boundary.c_str(), len); log_v("Parse Form: Boundary: %s Length: %d", boundary.c_str(), len);
String line; String line;
int retry = 0; int retry = 0;
do { do {
line = client.readStringUntil('\r'); line = client->readStringUntil('\r');
++retry; ++retry;
} while (line.length() == 0 && retry < 3); } while (line.length() == 0 && retry < 3);
client.readStringUntil('\n'); client->readStringUntil('\n');
//start reading the form //start reading the form
if (line == ("--"+boundary)){ if (line == ("--"+boundary)){
if(_postArgs) delete[] _postArgs; if(_postArgs) delete[] _postArgs;
@@ -374,8 +374,8 @@ bool EthernetWebServer::_parseForm(EthernetClient& client, String boundary, uint
String argFilename; String argFilename;
bool argIsFile = false; bool argIsFile = false;
line = client.readStringUntil('\r'); line = client->readStringUntil('\r');
client.readStringUntil('\n'); client->readStringUntil('\n');
if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){ if (line.length() > 19 && line.substring(0, 19).equalsIgnoreCase(F("Content-Disposition"))){
int nameStart = line.indexOf('='); int nameStart = line.indexOf('=');
if (nameStart != -1){ if (nameStart != -1){
@@ -395,19 +395,19 @@ bool EthernetWebServer::_parseForm(EthernetClient& client, String boundary, uint
log_v("PostArg Name: %s", argName.c_str()); log_v("PostArg Name: %s", argName.c_str());
using namespace mime; using namespace mime;
argType = FPSTR(mimeTable[txt].mimeType); argType = FPSTR(mimeTable[txt].mimeType);
line = client.readStringUntil('\r'); line = client->readStringUntil('\r');
client.readStringUntil('\n'); client->readStringUntil('\n');
if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){ if (line.length() > 12 && line.substring(0, 12).equalsIgnoreCase(FPSTR(Content_Type))){
argType = line.substring(line.indexOf(':')+2); argType = line.substring(line.indexOf(':')+2);
//skip next line //skip next line
client.readStringUntil('\r'); client->readStringUntil('\r');
client.readStringUntil('\n'); client->readStringUntil('\n');
} }
log_v("PostArg Type: %s", argType.c_str()); log_v("PostArg Type: %s", argType.c_str());
if (!argIsFile){ if (!argIsFile){
while(1){ while(1){
line = client.readStringUntil('\r'); line = client->readStringUntil('\r');
client.readStringUntil('\n'); client->readStringUntil('\n');
if (line.startsWith("--"+boundary)) break; if (line.startsWith("--"+boundary)) break;
if (argValue.length() > 0) argValue += "\n"; if (argValue.length() > 0) argValue += "\n";
argValue += line; argValue += line;
@@ -495,8 +495,8 @@ readfile:
if(_currentHandler && _currentHandler->canUpload(_currentUri)) if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload); _currentHandler->upload(*this, _currentUri, *_currentUpload);
log_v("End File: %s Type: %s Size: %d", _currentUpload->filename.c_str(), _currentUpload->type.c_str(), _currentUpload->totalSize); log_v("End File: %s Type: %s Size: %d", _currentUpload->filename.c_str(), _currentUpload->type.c_str(), _currentUpload->totalSize);
line = client.readStringUntil(0x0D); line = client->readStringUntil(0x0D);
client.readStringUntil(0x0A); client->readStringUntil(0x0A);
if (line == "--"){ if (line == "--"){
log_v("Done Parsing POST"); log_v("Done Parsing POST");
break; break;
@@ -550,7 +550,7 @@ readfile:
return false; return false;
} }
String EthernetWebServer::urlDecode(const String& text) String WebServer::urlDecode(const String& text)
{ {
String decoded = ""; String decoded = "";
char temp[] = "0x00"; char temp[] = "0x00";
@@ -581,7 +581,7 @@ String EthernetWebServer::urlDecode(const String& text)
return decoded; return decoded;
} }
bool EthernetWebServer::_parseFormUploadAborted(){ bool WebServer::_parseFormUploadAborted(){
_currentUpload->status = UPLOAD_FILE_ABORTED; _currentUpload->status = UPLOAD_FILE_ABORTED;
if(_currentHandler && _currentHandler->canUpload(_currentUri)) if(_currentHandler && _currentHandler->canUpload(_currentUri))
_currentHandler->upload(*this, _currentUri, *_currentUpload); _currentHandler->upload(*this, _currentUri, *_currentUpload);

View File

@@ -1,5 +1,5 @@
/* /*
EthernetWebServer.cpp - Dead simple web-server. Webserver->cpp - Dead simple web-server->
Supports only one simultaneous client, knows how to handle GET and POST. Supports only one simultaneous client, knows how to handle GET and POST.
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
@@ -24,9 +24,8 @@
#include <Arduino.h> #include <Arduino.h>
#include <esp32-hal-log.h> #include <esp32-hal-log.h>
#include <libb64/cencode.h> #include <libb64/cencode.h>
#include "WiFiServer.h" #include "WiFiClient.h"
#include "EthernetClient.h" #include "WebServer.h"
#include "EthernetWebServer.h"
#include "FS.h" #include "FS.h"
#include "detail/RequestHandlersImpl.h" #include "detail/RequestHandlersImpl.h"
#include "mbedtls/md5.h" #include "mbedtls/md5.h"
@@ -39,9 +38,10 @@ static const char WWW_Authenticate[] = "WWW-Authenticate";
static const char Content_Length[] = "Content-Length"; static const char Content_Length[] = "Content-Length";
EthernetWebServer::EthernetWebServer(IPAddress addr, int port) //WebServer::WebServer(IPAddress addr, int port)
WebServer::WebServer(EthServer* server)
: _corsEnabled(false) : _corsEnabled(false)
, _server(addr, port) , _server(server)
, _currentMethod(HTTP_ANY) , _currentMethod(HTTP_ANY)
, _currentVersion(0) , _currentVersion(0)
, _currentStatus(HC_NONE) , _currentStatus(HC_NONE)
@@ -61,30 +61,8 @@ EthernetWebServer::EthernetWebServer(IPAddress addr, int port)
{ {
} }
EthernetWebServer::EthernetWebServer(int port) WebServer::~WebServer() {
: _corsEnabled(false) _server->close();
, _server(port)
, _currentMethod(HTTP_ANY)
, _currentVersion(0)
, _currentStatus(HC_NONE)
, _statusChange(0)
, _nullDelay(true)
, _currentHandler(nullptr)
, _firstHandler(nullptr)
, _lastHandler(nullptr)
, _currentArgCount(0)
, _currentArgs(nullptr)
, _postArgsLen(0)
, _postArgs(nullptr)
, _headerKeysCount(0)
, _currentHeaders(nullptr)
, _contentLength(0)
, _chunked(false)
{
}
EthernetWebServer::~EthernetWebServer() {
_server.close();
if (_currentHeaders) if (_currentHeaders)
delete[]_currentHeaders; delete[]_currentHeaders;
RequestHandler* handler = _firstHandler; RequestHandler* handler = _firstHandler;
@@ -95,19 +73,19 @@ EthernetWebServer::~EthernetWebServer() {
} }
} }
void EthernetWebServer::begin() { void WebServer::begin() {
close(); close();
_server.begin(); _server->begin();
_server.setNoDelay(true); _server->setNoDelay(true);
} }
void EthernetWebServer::begin(uint16_t port) { void WebServer::begin(uint16_t port) {
close(); close();
_server.begin(port); _server->begin(port);
_server.setNoDelay(true); _server->setNoDelay(true);
} }
String EthernetWebServer::_extractParam(String& authReq, const String& param, const char delimit){ String WebServer::_extractParam(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 "";
@@ -134,7 +112,7 @@ static String md5str(String &in){
return String(out); return String(out);
} }
bool EthernetWebServer::authenticate(const char * username, const char * password){ bool WebServer::authenticate(const char * username, const char * password){
if(hasHeader(FPSTR(AUTHORIZATION_HEADER))) { if(hasHeader(FPSTR(AUTHORIZATION_HEADER))) {
String authReq = header(FPSTR(AUTHORIZATION_HEADER)); String authReq = header(FPSTR(AUTHORIZATION_HEADER));
if(authReq.startsWith(F("Basic"))){ if(authReq.startsWith(F("Basic"))){
@@ -222,7 +200,7 @@ bool EthernetWebServer::authenticate(const char * username, const char * passwor
return false; return false;
} }
String EthernetWebServer::_getRandomHexString() { String WebServer::_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++) {
@@ -231,7 +209,7 @@ String EthernetWebServer::_getRandomHexString() {
return String(buffer); return String(buffer);
} }
void EthernetWebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) { void WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) {
if(realm == NULL) { if(realm == NULL) {
_srealm = String(F("Login Required")); _srealm = String(F("Login Required"));
} else { } else {
@@ -248,23 +226,23 @@ void EthernetWebServer::requestAuthentication(HTTPAuthMethod mode, const char* r
send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg); send(401, String(FPSTR(mimeTable[html].mimeType)), authFailMsg);
} }
void EthernetWebServer::on(const Uri &uri, EthernetWebServer::THandlerFunction handler) { void WebServer::on(const Uri &uri, WebServer::THandlerFunction handler) {
on(uri, HTTP_ANY, handler); on(uri, HTTP_ANY, handler);
} }
void EthernetWebServer::on(const Uri &uri, HTTPMethod method, EthernetWebServer::THandlerFunction fn) { void WebServer::on(const Uri &uri, HTTPMethod method, WebServer::THandlerFunction fn) {
on(uri, method, fn, _fileUploadHandler); on(uri, method, fn, _fileUploadHandler);
} }
void EthernetWebServer::on(const Uri &uri, HTTPMethod method, EthernetWebServer::THandlerFunction fn, EthernetWebServer::THandlerFunction ufn) { void WebServer::on(const Uri &uri, HTTPMethod method, WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn) {
_addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method)); _addRequestHandler(new FunctionRequestHandler(fn, ufn, uri, method));
} }
void EthernetWebServer::addHandler(RequestHandler* handler) { void WebServer::addHandler(RequestHandler* handler) {
_addRequestHandler(handler); _addRequestHandler(handler);
} }
void EthernetWebServer::_addRequestHandler(RequestHandler* handler) { void WebServer::_addRequestHandler(RequestHandler* handler) {
if (!_lastHandler) { if (!_lastHandler) {
_firstHandler = handler; _firstHandler = handler;
_lastHandler = handler; _lastHandler = handler;
@@ -275,20 +253,19 @@ void EthernetWebServer::_addRequestHandler(RequestHandler* handler) {
} }
} }
void EthernetWebServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) { void WebServer::serveStatic(const char* uri, FS& fs, const char* path, const char* cache_header) {
_addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header)); _addRequestHandler(new StaticRequestHandler(fs, path, uri, cache_header));
} }
void EthernetWebServer::handleClient() { void WebServer::handleClient() {
if (_currentStatus == HC_NONE) { if (_currentStatus == HC_NONE) {
EthernetClient client = _server.available(); EthClient* client = _server->available();
if (!client) { if (!client->connected()) {
if (_nullDelay) { if (_nullDelay) {
delay(1); delay(1);
} }
return; return;
} }
log_v("New client"); log_v("New client");
_currentClient = client; _currentClient = client;
@@ -299,29 +276,23 @@ void EthernetWebServer::handleClient() {
bool keepCurrentClient = false; bool keepCurrentClient = false;
bool callYield = false; bool callYield = false;
if (_currentClient.connected()) { if (_currentClient->connected()) {
switch (_currentStatus) { switch (_currentStatus) {
case HC_NONE: case HC_NONE:
// No-op to avoid C++ compiler warning // No-op to avoid C++ compiler warning
break; break;
case HC_WAIT_READ: case HC_WAIT_READ:
// Wait for data from client to become available // Wait for data from client to become available
if (_currentClient.available()) { if (_currentClient->available()) {
if (_parseRequest(_currentClient)) { if (_parseRequest(_currentClient)) {
// because HTTP_MAX_SEND_WAIT is expressed in milliseconds, // because HTTP_MAX_SEND_WAIT is expressed in milliseconds,
// it must be divided by 1000 // it must be divided by 1000
_currentClient.setTimeout(HTTP_MAX_SEND_WAIT / 1000); _currentClient->setTimeout(HTTP_MAX_SEND_WAIT / 1000);
_contentLength = CONTENT_LENGTH_NOT_SET; _contentLength = CONTENT_LENGTH_NOT_SET;
_handleRequest(); _handleRequest();
// Fix for issue with Chrome based browsers: https://github.com/espressif/arduino-esp32/issues/3652
// if (_currentClient.connected()) {
// _currentStatus = HC_WAIT_CLOSE;
// _statusChange = millis();
// keepCurrentClient = true;
// }
} }
} else { // !_currentClient.available() } else { // !_currentClient->available()
if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) { if (millis() - _statusChange <= HTTP_MAX_DATA_WAIT) {
keepCurrentClient = true; keepCurrentClient = true;
} }
@@ -337,8 +308,10 @@ void EthernetWebServer::handleClient() {
} }
} }
// TODO
if (!keepCurrentClient) { if (!keepCurrentClient) {
_currentClient = EthernetClient(); _server->discardClient();
_currentClient = _server->available();
_currentStatus = HC_NONE; _currentStatus = HC_NONE;
_currentUpload.reset(); _currentUpload.reset();
} }
@@ -348,18 +321,18 @@ void EthernetWebServer::handleClient() {
} }
} }
void EthernetWebServer::close() { void WebServer::close() {
_server.close(); _server->close();
_currentStatus = HC_NONE; _currentStatus = HC_NONE;
if(!_headerKeysCount) if(!_headerKeysCount)
collectHeaders(0, 0); collectHeaders(0, 0);
} }
void EthernetWebServer::stop() { void WebServer::stop() {
close(); close();
} }
void EthernetWebServer::sendHeader(const String& name, const String& value, bool first) { void WebServer::sendHeader(const String& name, const String& value, bool first) {
String headerLine = name; String headerLine = name;
headerLine += F(": "); headerLine += F(": ");
headerLine += value; headerLine += value;
@@ -373,23 +346,23 @@ void EthernetWebServer::sendHeader(const String& name, const String& value, bool
} }
} }
void EthernetWebServer::setContentLength(const size_t contentLength) { void WebServer::setContentLength(const size_t contentLength) {
_contentLength = contentLength; _contentLength = contentLength;
} }
void EthernetWebServer::enableDelay(boolean value) { void WebServer::enableDelay(boolean value) {
_nullDelay = value; _nullDelay = value;
} }
void EthernetWebServer::enableCORS(boolean value) { void WebServer::enableCORS(boolean value) {
_corsEnabled = value; _corsEnabled = value;
} }
void EthernetWebServer::enableCrossOrigin(boolean value) { void WebServer::enableCrossOrigin(boolean value) {
enableCORS(value); enableCORS(value);
} }
void EthernetWebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) { void WebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) {
response = String(F("HTTP/1.")) + String(_currentVersion) + ' '; response = String(F("HTTP/1.")) + String(_currentVersion) + ' ';
response += String(code); response += String(code);
response += ' '; response += ' ';
@@ -423,7 +396,7 @@ void EthernetWebServer::_prepareHeader(String& response, int code, const char* c
_responseHeaders = ""; _responseHeaders = "";
} }
void EthernetWebServer::send(int code, const char* content_type, const String& content) { void WebServer::send(int code, const char* content_type, const String& content) {
String header; String header;
// Can we asume the following? // Can we asume the following?
//if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET) //if(code == 200 && content.length() == 0 && _contentLength == CONTENT_LENGTH_NOT_SET)
@@ -434,7 +407,7 @@ void EthernetWebServer::send(int code, const char* content_type, const String& c
sendContent(content); sendContent(content);
} }
void EthernetWebServer::send_P(int code, PGM_P content_type, PGM_P content) { void WebServer::send_P(int code, PGM_P content_type, PGM_P content) {
size_t contentLength = 0; size_t contentLength = 0;
if (content != NULL) { if (content != NULL) {
@@ -449,7 +422,7 @@ void EthernetWebServer::send_P(int code, PGM_P content_type, PGM_P content) {
sendContent_P(content); sendContent_P(content);
} }
void EthernetWebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) { void WebServer::send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength) {
String header; String header;
char type[64]; char type[64];
memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type)); memccpy_P((void*)type, (PGM_VOID_P)content_type, 0, sizeof(type));
@@ -458,19 +431,19 @@ void EthernetWebServer::send_P(int code, PGM_P content_type, PGM_P content, size
sendContent_P(content, contentLength); sendContent_P(content, contentLength);
} }
void EthernetWebServer::send(int code, char* content_type, const String& content) { void WebServer::send(int code, char* content_type, const String& content) {
send(code, (const char*)content_type, content); send(code, (const char*)content_type, content);
} }
void EthernetWebServer::send(int code, const String& content_type, const String& content) { void WebServer::send(int code, const String& content_type, const String& content) {
send(code, (const char*)content_type.c_str(), content); send(code, (const char*)content_type.c_str(), content);
} }
void EthernetWebServer::sendContent(const String& content) { void WebServer::sendContent(const String& content) {
sendContent(content.c_str(), content.length()); sendContent(content.c_str(), content.length());
} }
void EthernetWebServer::sendContent(const char* content, size_t contentLength) { void WebServer::sendContent(const char* content, size_t contentLength) {
const char * footer = "\r\n"; const char * footer = "\r\n";
if(_chunked) { if(_chunked) {
char * chunkSize = (char *)malloc(11); char * chunkSize = (char *)malloc(11);
@@ -482,18 +455,18 @@ void EthernetWebServer::sendContent(const char* content, size_t contentLength) {
} }
_currentClientWrite(content, contentLength); _currentClientWrite(content, contentLength);
if(_chunked){ if(_chunked){
_currentClient.write(footer, 2); _currentClient->write(footer, 2);
if (contentLength == 0) { if (contentLength == 0) {
_chunked = false; _chunked = false;
} }
} }
} }
void EthernetWebServer::sendContent_P(PGM_P content) { void WebServer::sendContent_P(PGM_P content) {
sendContent_P(content, strlen_P(content)); sendContent_P(content, strlen_P(content));
} }
void EthernetWebServer::sendContent_P(PGM_P content, size_t size) { void WebServer::sendContent_P(PGM_P content, size_t size) {
const char * footer = "\r\n"; const char * footer = "\r\n";
if(_chunked) { if(_chunked) {
char * chunkSize = (char *)malloc(11); char * chunkSize = (char *)malloc(11);
@@ -505,7 +478,7 @@ void EthernetWebServer::sendContent_P(PGM_P content, size_t size) {
} }
_currentClientWrite_P(content, size); _currentClientWrite_P(content, size);
if(_chunked){ if(_chunked){
_currentClient.write(footer, 2); _currentClient->write(footer, 2);
if (size == 0) { if (size == 0) {
_chunked = false; _chunked = false;
} }
@@ -513,7 +486,7 @@ void EthernetWebServer::sendContent_P(PGM_P content, size_t size) {
} }
void EthernetWebServer::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType) void WebServer::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType)
{ {
using namespace mime; using namespace mime;
setContentLength(fileSize); setContentLength(fileSize);
@@ -525,13 +498,13 @@ void EthernetWebServer::_streamFileCore(const size_t fileSize, const String & fi
send(200, contentType, ""); send(200, contentType, "");
} }
String EthernetWebServer::pathArg(unsigned int i) { String WebServer::pathArg(unsigned int i) {
if (_currentHandler != nullptr) if (_currentHandler != nullptr)
return _currentHandler->pathArg(i); return _currentHandler->pathArg(i);
return ""; return "";
} }
String EthernetWebServer::arg(String name) { String WebServer::arg(String name) {
for (int j = 0; j < _postArgsLen; ++j) { for (int j = 0; j < _postArgsLen; ++j) {
if ( _postArgs[j].key == name ) if ( _postArgs[j].key == name )
return _postArgs[j].value; return _postArgs[j].value;
@@ -543,23 +516,23 @@ String EthernetWebServer::arg(String name) {
return ""; return "";
} }
String EthernetWebServer::arg(int i) { String WebServer::arg(int i) {
if (i < _currentArgCount) if (i < _currentArgCount)
return _currentArgs[i].value; return _currentArgs[i].value;
return ""; return "";
} }
String EthernetWebServer::argName(int i) { String WebServer::argName(int i) {
if (i < _currentArgCount) if (i < _currentArgCount)
return _currentArgs[i].key; return _currentArgs[i].key;
return ""; return "";
} }
int EthernetWebServer::args() { int WebServer::args() {
return _currentArgCount; return _currentArgCount;
} }
bool EthernetWebServer::hasArg(String name) { bool WebServer::hasArg(String name) {
for (int j = 0; j < _postArgsLen; ++j) { for (int j = 0; j < _postArgsLen; ++j) {
if (_postArgs[j].key == name) if (_postArgs[j].key == name)
return true; return true;
@@ -572,7 +545,7 @@ bool EthernetWebServer::hasArg(String name) {
} }
String EthernetWebServer::header(String name) { String WebServer::header(String name) {
for (int i = 0; i < _headerKeysCount; ++i) { for (int i = 0; i < _headerKeysCount; ++i) {
if (_currentHeaders[i].key.equalsIgnoreCase(name)) if (_currentHeaders[i].key.equalsIgnoreCase(name))
return _currentHeaders[i].value; return _currentHeaders[i].value;
@@ -580,7 +553,7 @@ String EthernetWebServer::header(String name) {
return ""; return "";
} }
void EthernetWebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) { void WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
_headerKeysCount = headerKeysCount + 1; _headerKeysCount = headerKeysCount + 1;
if (_currentHeaders) if (_currentHeaders)
delete[]_currentHeaders; delete[]_currentHeaders;
@@ -591,23 +564,23 @@ void EthernetWebServer::collectHeaders(const char* headerKeys[], const size_t he
} }
} }
String EthernetWebServer::header(int i) { String WebServer::header(int i) {
if (i < _headerKeysCount) if (i < _headerKeysCount)
return _currentHeaders[i].value; return _currentHeaders[i].value;
return ""; return "";
} }
String EthernetWebServer::headerName(int i) { String WebServer::headerName(int i) {
if (i < _headerKeysCount) if (i < _headerKeysCount)
return _currentHeaders[i].key; return _currentHeaders[i].key;
return ""; return "";
} }
int EthernetWebServer::headers() { int WebServer::headers() {
return _headerKeysCount; return _headerKeysCount;
} }
bool EthernetWebServer::hasHeader(String name) { bool WebServer::hasHeader(String name) {
for (int i = 0; i < _headerKeysCount; ++i) { for (int i = 0; i < _headerKeysCount; ++i) {
if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0)) if ((_currentHeaders[i].key.equalsIgnoreCase(name)) && (_currentHeaders[i].value.length() > 0))
return true; return true;
@@ -615,19 +588,19 @@ bool EthernetWebServer::hasHeader(String name) {
return false; return false;
} }
String EthernetWebServer::hostHeader() { String WebServer::hostHeader() {
return _hostHeader; return _hostHeader;
} }
void EthernetWebServer::onFileUpload(THandlerFunction fn) { void WebServer::onFileUpload(THandlerFunction fn) {
_fileUploadHandler = fn; _fileUploadHandler = fn;
} }
void EthernetWebServer::onNotFound(THandlerFunction fn) { void WebServer::onNotFound(THandlerFunction fn) {
_notFoundHandler = fn; _notFoundHandler = fn;
} }
void EthernetWebServer::_handleRequest() { void WebServer::_handleRequest() {
bool handled = false; bool handled = false;
if (!_currentHandler){ if (!_currentHandler){
log_e("request handler not found"); log_e("request handler not found");
@@ -654,13 +627,13 @@ void EthernetWebServer::_handleRequest() {
} }
void EthernetWebServer::_finalizeResponse() { void WebServer::_finalizeResponse() {
if (_chunked) { if (_chunked) {
sendContent(""); sendContent("");
} }
} }
String EthernetWebServer::_responseCodeToString(int code) { String WebServer::_responseCodeToString(int code) {
switch (code) { switch (code) {
case 100: return F("Continue"); case 100: return F("Continue");
case 101: return F("Switching Protocols"); case 101: return F("Switching Protocols");
@@ -705,8 +678,3 @@ String EthernetWebServer::_responseCodeToString(int code) {
default: return F(""); default: return F("");
} }
} }
size_t EthernetWebServer::write_P(const char *buf, size_t size)
{
return _currentClient.write(buf, size);
}

View File

@@ -1,5 +1,5 @@
/* /*
EthernetWebServer.h - Dead simple web-server. WebServer.h - Dead simple web-server.
Supports only one simultaneous client, knows how to handle GET and POST. Supports only one simultaneous client, knows how to handle GET and POST.
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved. Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
@@ -27,7 +27,6 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include <WiFi.h> #include <WiFi.h>
#include <EthernetServer.h>
#include "HTTP_Method.h" #include "HTTP_Method.h"
#include "Uri.h" #include "Uri.h"
@@ -50,7 +49,7 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH };
#define CONTENT_LENGTH_UNKNOWN ((size_t) -1) #define CONTENT_LENGTH_UNKNOWN ((size_t) -1)
#define CONTENT_LENGTH_NOT_SET ((size_t) -2) #define CONTENT_LENGTH_NOT_SET ((size_t) -2)
class EthernetWebServer; class WebServer;
typedef struct { typedef struct {
HTTPUploadStatus status; HTTPUploadStatus status;
@@ -63,18 +62,18 @@ typedef struct {
} HTTPUpload; } HTTPUpload;
#include "detail/RequestHandler.h" #include "detail/RequestHandler.h"
#include "EthernetServerImpl.h" #include "EthServer.h"
#include "EthClient.h"
namespace fs { namespace fs {
class FS; class FS;
} }
class EthernetWebServer class WebServer
{ {
public: public:
EthernetWebServer(IPAddress addr, int port = 80); WebServer(EthServer* server);
EthernetWebServer(int port = 80); virtual ~WebServer();
virtual ~EthernetWebServer();
virtual void begin(); virtual void begin();
virtual void begin(uint16_t port); virtual void begin(uint16_t port);
@@ -97,7 +96,7 @@ public:
String uri() { return _currentUri; } String uri() { return _currentUri; }
HTTPMethod method() { return _currentMethod; } HTTPMethod method() { return _currentMethod; }
virtual EthernetClient client() { return _currentClient; } virtual EthClient* client() { return _currentClient; }
HTTPUpload& upload() { return *_currentUpload; } HTTPUpload& upload() { return *_currentUpload; }
String pathArg(unsigned int i); // get request path argument by number String pathArg(unsigned int i); // get request path argument by number
@@ -141,23 +140,22 @@ public:
template<typename T> template<typename T>
size_t streamFile(T &file, const String& contentType) { size_t streamFile(T &file, const String& contentType) {
_streamFileCore(file.size(), file.name(), contentType); _streamFileCore(file.size(), file.name(), contentType);
return _currentClient.write(file); return _currentClient->write(file);
} }
protected: protected:
size_t write_P(PGM_P buf, size_t size); virtual size_t _currentClientWrite(const char* b, size_t l) { return _currentClient->write( b, l ); }
virtual size_t _currentClientWrite(const char* b, size_t l) { return _currentClient.write( b, l ); } virtual size_t _currentClientWrite_P(PGM_P b, size_t l) { return _currentClient->write_P( b, l ); }
virtual size_t _currentClientWrite_P(PGM_P b, size_t l) { return write_P( b, l ); }
void _addRequestHandler(RequestHandler* handler); void _addRequestHandler(RequestHandler* handler);
void _handleRequest(); void _handleRequest();
void _finalizeResponse(); void _finalizeResponse();
bool _parseRequest(EthernetClient& client); bool _parseRequest(EthClient* client);
void _parseArguments(String data); void _parseArguments(String data);
static String _responseCodeToString(int code); static String _responseCodeToString(int code);
bool _parseForm(EthernetClient& client, String boundary, uint32_t len); bool _parseForm(EthClient* client, String boundary, uint32_t len);
bool _parseFormUploadAborted(); bool _parseFormUploadAborted();
void _uploadWriteByte(uint8_t b); void _uploadWriteByte(uint8_t b);
int _uploadReadByte(EthernetClient& client); int _uploadReadByte(EthClient* client);
void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength); void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength);
bool _collectHeader(const char* headerName, const char* headerValue); bool _collectHeader(const char* headerName, const char* headerValue);
@@ -173,9 +171,9 @@ protected:
}; };
boolean _corsEnabled; boolean _corsEnabled;
EthernetServerImpl _server; EthServer* _server;
EthernetClient _currentClient; EthClient* _currentClient = nullptr;
HTTPMethod _currentMethod; HTTPMethod _currentMethod;
String _currentUri; String _currentUri;
uint8_t _currentVersion; uint8_t _currentVersion;

View File

@@ -0,0 +1,77 @@
#include "WifiEthClient.h"
WifiEthClient::WifiEthClient(WiFiClient *wifiClient)
: _wifiClient(wifiClient)
{
}
WifiEthClient::~WifiEthClient()
{
_wifiClient = nullptr;
}
uint8_t WifiEthClient::connected()
{
return _wifiClient->connected();
}
int WifiEthClient::setTimeout(uint32_t seconds)
{
return _wifiClient->setTimeout(seconds);
}
size_t WifiEthClient::write(const char *buffer, size_t size)
{
return _wifiClient->write(buffer, size);
}
IPAddress WifiEthClient::localIP()
{
return _wifiClient->localIP();
}
void WifiEthClient::stop()
{
_wifiClient->stop();
}
size_t WifiEthClient::write_P(const char *buf, size_t size)
{
return _wifiClient->write_P(buf, size);
}
int WifiEthClient::available()
{
return _wifiClient->available();
}
String WifiEthClient::readStringUntil(char terminator)
{
return _wifiClient->readStringUntil(terminator);
}
size_t WifiEthClient::readBytes(char *buffer, size_t length)
{
return _wifiClient->readBytes(buffer, length);
}
void WifiEthClient::flush()
{
_wifiClient->flush();
}
int WifiEthClient::read()
{
return _wifiClient->read();
}
unsigned long WifiEthClient::getTimeout(void)
{
return _wifiClient->getTimeout();
}
size_t WifiEthClient::write(Stream &stream)
{
return _wifiClient->write(stream);
}

View File

@@ -0,0 +1,28 @@
#pragma once
#include <WiFiClient.h>
#include "EthClient.h"
class WifiEthClient : public EthClient
{
public:
explicit WifiEthClient(WiFiClient* wifiClient);
virtual ~WifiEthClient();
uint8_t connected() override;
int available() override;
unsigned long getTimeout(void) override;
int setTimeout(uint32_t seconds) override;
int read() override;
size_t write(const char *buffer, size_t size) override;
size_t write(Stream &stream) override;
size_t write_P(const char *buf, size_t size) override;
String readStringUntil(char terminator) override;
size_t readBytes(char *buffer, size_t length) override;
IPAddress localIP() override;
void stop() override;
void flush() override;
private:
WiFiClient* _wifiClient;
};

View File

@@ -0,0 +1,56 @@
#include "WifiEthServer.h"
WifiEthServer::WifiEthServer(IPAddress address, int port)
: EthServer(address, port),
_wifiServer(address, port)
{
}
WifiEthServer::WifiEthServer(int port)
: EthServer(port),
_wifiServer(port)
{
}
void WifiEthServer::close()
{
_wifiServer.close();
}
void WifiEthServer::begin(const int port)
{
_wifiServer.begin(port);
}
void WifiEthServer::setNoDelay(const bool value)
{
_wifiServer.setNoDelay(value);
}
EthClient* WifiEthServer::available()
{
if(_wifiEthClient != nullptr)
{
delete _wifiEthClient;
_wifiEthClient = nullptr;
}
_wifiClient = _wifiServer.available();
_wifiEthClient = new WifiEthClient(&_wifiClient);
return _wifiEthClient;
}
void WifiEthServer::discardClient()
{
if(_wifiEthClient != nullptr)
{
delete _wifiEthClient;
_wifiEthClient = nullptr;
}
_wifiClient = WiFiClient();
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include "EthServer.h"
#include "WifiEthClient.h"
#include <WiFiServer.h>
class WifiEthServer : public EthServer
{
public:
WifiEthServer(IPAddress address, int port);
explicit WifiEthServer(int port);
virtual EthClient* available();
virtual void discardClient();
virtual void begin(const int port = 80);
virtual void close();
virtual void setNoDelay(const bool value);
private:
WiFiServer _wifiServer;
WiFiClient _wifiClient;
WifiEthClient* _wifiEthClient = nullptr;
};

View File

@@ -9,8 +9,8 @@ public:
virtual ~RequestHandler() { } virtual ~RequestHandler() { }
virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; } virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; }
virtual bool canUpload(String uri) { (void) uri; return false; } virtual bool canUpload(String uri) { (void) uri; return false; }
virtual bool handle(EthernetWebServer& server, HTTPMethod requestMethod, String requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; } virtual bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; }
virtual void upload(EthernetWebServer& server, String requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; } virtual void upload(WebServer& server, String requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; }
RequestHandler* next() { return _next; } RequestHandler* next() { return _next; }
void next(RequestHandler* r) { _next = r; } void next(RequestHandler* r) { _next = r; }

View File

@@ -10,7 +10,7 @@ using namespace mime;
class FunctionRequestHandler : public RequestHandler { class FunctionRequestHandler : public RequestHandler {
public: public:
FunctionRequestHandler(EthernetWebServer::THandlerFunction fn, EthernetWebServer::THandlerFunction ufn, const Uri &uri, HTTPMethod method) FunctionRequestHandler(WebServer::THandlerFunction fn, WebServer::THandlerFunction ufn, const Uri &uri, HTTPMethod method)
: _fn(fn) : _fn(fn)
, _ufn(ufn) , _ufn(ufn)
, _uri(uri.clone()) , _uri(uri.clone())
@@ -37,7 +37,7 @@ public:
return true; return true;
} }
bool handle(EthernetWebServer& server, HTTPMethod requestMethod, String requestUri) override { bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) override {
(void) server; (void) server;
if (!canHandle(requestMethod, requestUri)) if (!canHandle(requestMethod, requestUri))
return false; return false;
@@ -46,7 +46,7 @@ public:
return true; return true;
} }
void upload(EthernetWebServer& server, String requestUri, HTTPUpload& upload) override { void upload(WebServer& server, String requestUri, HTTPUpload& upload) override {
(void) server; (void) server;
(void) upload; (void) upload;
if (canUpload(requestUri)) if (canUpload(requestUri))
@@ -54,8 +54,8 @@ public:
} }
protected: protected:
EthernetWebServer::THandlerFunction _fn; WebServer::THandlerFunction _fn;
EthernetWebServer::THandlerFunction _ufn; WebServer::THandlerFunction _ufn;
Uri *_uri; Uri *_uri;
HTTPMethod _method; HTTPMethod _method;
}; };
@@ -83,7 +83,7 @@ public:
return true; return true;
} }
bool handle(EthernetWebServer& server, HTTPMethod requestMethod, String requestUri) override { bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) override {
if (!canHandle(requestMethod, requestUri)) if (!canHandle(requestMethod, requestUri))
return false; return false;

View File

@@ -11,6 +11,7 @@
*/ */
#include "WiFiManager.h" #include "WiFiManager.h"
#include "WifiEthServer.h"
#if defined(ESP8266) || defined(ESP32) #if defined(ESP8266) || defined(ESP32)
@@ -586,7 +587,7 @@ void WiFiManager::setupHTTPServer(){
#endif #endif
} }
server.reset(new WM_WebServer(_httpPort)); server.reset(new WM_WebServer(new WifiEthServer(80)));
// This is not the safest way to reset the webserver, it can cause crashes on callbacks initilized before this and since its a shared pointer... // This is not the safest way to reset the webserver, it can cause crashes on callbacks initilized before this and since its a shared pointer...
if ( _webservercallback != NULL) { if ( _webservercallback != NULL) {
@@ -2290,7 +2291,7 @@ boolean WiFiManager::captivePortal() {
if(!_enableCaptivePortal) return false; // skip redirections, @todo maybe allow redirection even when no cp ? might be useful if(!_enableCaptivePortal) return false; // skip redirections, @todo maybe allow redirection even when no cp ? might be useful
String serverLoc = toStringIp(server->client().localIP()); String serverLoc = toStringIp(server->client()->localIP());
if(_httpPort != 80) serverLoc += ":" + (String)_httpPort; // add port if not default if(_httpPort != 80) serverLoc += ":" + (String)_httpPort; // add port if not default
bool doredirect = serverLoc != server->hostHeader(); // redirect if hostheader not server ip, prevent redirect loops bool doredirect = serverLoc != server->hostHeader(); // redirect if hostheader not server ip, prevent redirect loops
// doredirect = !isIp(server->hostHeader()) // old check // doredirect = !isIp(server->hostHeader()) // old check
@@ -2301,7 +2302,7 @@ boolean WiFiManager::captivePortal() {
#endif #endif
server->sendHeader(F("Location"), (String)F("http://") + serverLoc, true); // @HTTPHEAD send redirect server->sendHeader(F("Location"), (String)F("http://") + serverLoc, true); // @HTTPHEAD send redirect
server->send ( 302, FPSTR(HTTP_HEAD_CT2), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves. server->send ( 302, FPSTR(HTTP_HEAD_CT2), ""); // Empty content inhibits Content-length header so we have to close the socket ourselves.
server->client().stop(); // Stop is needed because we sent no content length server->client()->stop(); // Stop is needed because we sent no content length
return true; return true;
} }
return false; return false;

View File

@@ -20,7 +20,7 @@ void callback(char* topic, byte* payload, unsigned int length) {
// handle message arrived // handle message arrived
} }
EthernetClient ethClient; server-> ethClient;
PubSubClient client(server, 1883, callback, ethClient); PubSubClient client(server, 1883, callback, ethClient);
void setup() void setup()

View File

@@ -85,8 +85,8 @@ void setup()
Serial.begin(115200); Serial.begin(115200);
// const NetworkDeviceType networkDevice = NetworkDeviceType::WiFi; const NetworkDeviceType networkDevice = NetworkDeviceType::WiFi;
const NetworkDeviceType networkDevice = digitalRead(NETWORK_SELECT) == HIGH ? NetworkDeviceType::WiFi : NetworkDeviceType::W5500; // const NetworkDeviceType networkDevice = digitalRead(NETWORK_SELECT) == HIGH ? NetworkDeviceType::WiFi : NetworkDeviceType::W5500;
preferences = new Preferences(); preferences = new Preferences();
preferences->begin("nukihub", false); preferences->begin("nukihub", false);

View File

@@ -1,24 +0,0 @@
#pragma once
#include <functional>
#include <WString.h>
typedef std::function<void(void)> THandlerFunction;
class Uri;
class AbstractWebServer
{
public:
explicit AbstractWebServer(int port) {};
virtual void begin() = 0;
virtual bool authenticate(const char * username, const char * password) = 0;
virtual void requestAuthentication(int mode, const char* realm, const String& authFailMsg) = 0;
virtual void requestAuthentication() = 0;
virtual void send(int code, const char* content_type, const String& content) = 0;
virtual void on(const Uri &uri, THandlerFunction handler) = 0;
virtual int args() = 0;
virtual String arg(int i) = 0;
virtual String argName(int i) = 0;
virtual void handleClient() = 0;
};

View File

@@ -1,58 +0,0 @@
#include "EthWebServer.h"
EthWebServer::EthWebServer(int port)
: AbstractWebServer(port),
_server(port)
{}
void EthWebServer::begin()
{
_server.begin();
}
bool EthWebServer::authenticate(const char *username, const char *password)
{
return _server.authenticate(username, password);
}
void EthWebServer::requestAuthentication(int mode, const char *realm, const String &authFailMsg)
{
return _server.requestAuthentication((HTTPAuthMethod)mode, realm, authFailMsg);
}
void EthWebServer::requestAuthentication()
{
return requestAuthentication(HTTPAuthMethod::BASIC_AUTH, "*", "Authentication failed");
}
void EthWebServer::send(int code, const char *content_type, const String &content)
{
_server.send(code, content_type, content);
}
void EthWebServer::on(const Uri &uri, EthernetWebServer::THandlerFunction handler)
{
_server.on(uri, handler);
}
int EthWebServer::args()
{
return _server.args();
}
String EthWebServer::arg(int i)
{
return _server.arg(i);
}
String EthWebServer::argName(int i)
{
return _server.argName(i);
}
void EthWebServer::handleClient()
{
_server.handleClient();
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include "AbstractWebServer.h"
#include "EthernetWebServer.h"
class EthWebServer : public AbstractWebServer
{
public:
explicit EthWebServer(int port);
virtual void begin();
virtual bool authenticate(const char *username, const char *password);
virtual void requestAuthentication(int mode, const char *realm, const String &authFailMsg);
virtual void requestAuthentication();
virtual void send(int code, const char *content_type, const String &content);
virtual void on(const Uri &uri, THandlerFunction handler);
virtual int args();
virtual String arg(int i);
virtual String argName(int i);
virtual void handleClient();
private:
EthernetWebServer _server;
};

View File

@@ -1,57 +0,0 @@
#include "WifiWebServer.h"
WifiWebServer::WifiWebServer(int port)
: AbstractWebServer(port),
_server(port)
{}
void WifiWebServer::begin()
{
_server.begin();
}
bool WifiWebServer::authenticate(const char *username, const char *password)
{
return _server.authenticate(username, password);
}
void WifiWebServer::requestAuthentication(int mode, const char *realm, const String &authFailMsg)
{
return _server.requestAuthentication((HTTPAuthMethod)mode, realm, authFailMsg);
}
void WifiWebServer::send(int code, const char *content_type, const String &content)
{
_server.send(code, content_type, content);
}
void WifiWebServer::on(const Uri &uri, WebServer::THandlerFunction handler)
{
_server.on(uri, handler);
}
void WifiWebServer::requestAuthentication()
{
}
int WifiWebServer::args()
{
return _server.args();
}
String WifiWebServer::arg(int i)
{
return _server.arg(i);
}
String WifiWebServer::argName(int i)
{
return _server.argName(i);
}
void WifiWebServer::handleClient()
{
_server.handleClient();
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include <WebServer.h>
#include "AbstractWebServer.h"
class WifiWebServer : public AbstractWebServer
{
public:
explicit WifiWebServer(int port);
virtual void begin();
virtual bool authenticate(const char *username, const char *password);
virtual void requestAuthentication(int mode, const char *realm, const String &authFailMsg);
virtual void requestAuthentication();
virtual void send(int code, const char *content_type, const String &content);
virtual void on(const Uri &uri, WebServer::THandlerFunction handler);
virtual int args();
virtual String arg(int i);
virtual String argName(int i);
virtual void handleClient();
private:
WebServer _server;
};