mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-25 20:02:37 +03:00
add begin(port) to esp8266webserver, move some strings to flash, some refactoring (#4148)
* add begin(port) to esp8266webserver, move some strings to flash, some refactoring * Moved more strings to flash, unified some strings * move mimetable strings into a standalone file * more string moves to flash, remove duplicates, refactor of template method, minor styling * Reverted moving small string to flash (no heap advantage, reduces bin size)
This commit is contained in:
parent
0339bbb11c
commit
bcbd5961c0
@ -36,7 +36,13 @@
|
|||||||
#define DEBUG_OUTPUT Serial
|
#define DEBUG_OUTPUT Serial
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
const char * AUTHORIZATION_HEADER = "Authorization";
|
//const char * AUTHORIZATION_HEADER = "Authorization";
|
||||||
|
static const char AUTHORIZATION_HEADER[] PROGMEM = "Authorization";
|
||||||
|
static const char qop_auth[] PROGMEM = "qop=auth";
|
||||||
|
static const char WWW_Authenticate[] PROGMEM = "WWW-Authenticate";
|
||||||
|
static const char colon[] PROGMEM = ":";
|
||||||
|
static const char Content_Length[] PROGMEM = "Content-Length";
|
||||||
|
|
||||||
|
|
||||||
ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port)
|
ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port)
|
||||||
: _server(addr, port)
|
: _server(addr, port)
|
||||||
@ -44,13 +50,13 @@ ESP8266WebServer::ESP8266WebServer(IPAddress addr, int port)
|
|||||||
, _currentVersion(0)
|
, _currentVersion(0)
|
||||||
, _currentStatus(HC_NONE)
|
, _currentStatus(HC_NONE)
|
||||||
, _statusChange(0)
|
, _statusChange(0)
|
||||||
, _currentHandler(0)
|
, _currentHandler(nullptr)
|
||||||
, _firstHandler(0)
|
, _firstHandler(nullptr)
|
||||||
, _lastHandler(0)
|
, _lastHandler(nullptr)
|
||||||
, _currentArgCount(0)
|
, _currentArgCount(0)
|
||||||
, _currentArgs(0)
|
, _currentArgs(nullptr)
|
||||||
, _headerKeysCount(0)
|
, _headerKeysCount(0)
|
||||||
, _currentHeaders(0)
|
, _currentHeaders(nullptr)
|
||||||
, _contentLength(0)
|
, _contentLength(0)
|
||||||
, _chunked(false)
|
, _chunked(false)
|
||||||
{
|
{
|
||||||
@ -62,13 +68,13 @@ ESP8266WebServer::ESP8266WebServer(int port)
|
|||||||
, _currentVersion(0)
|
, _currentVersion(0)
|
||||||
, _currentStatus(HC_NONE)
|
, _currentStatus(HC_NONE)
|
||||||
, _statusChange(0)
|
, _statusChange(0)
|
||||||
, _currentHandler(0)
|
, _currentHandler(nullptr)
|
||||||
, _firstHandler(0)
|
, _firstHandler(nullptr)
|
||||||
, _lastHandler(0)
|
, _lastHandler(nullptr)
|
||||||
, _currentArgCount(0)
|
, _currentArgCount(0)
|
||||||
, _currentArgs(0)
|
, _currentArgs(nullptr)
|
||||||
, _headerKeysCount(0)
|
, _headerKeysCount(0)
|
||||||
, _currentHeaders(0)
|
, _currentHeaders(nullptr)
|
||||||
, _contentLength(0)
|
, _contentLength(0)
|
||||||
, _chunked(false)
|
, _chunked(false)
|
||||||
{
|
{
|
||||||
@ -88,79 +94,83 @@ ESP8266WebServer::~ESP8266WebServer() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::begin() {
|
void ESP8266WebServer::begin() {
|
||||||
_currentStatus = HC_NONE;
|
close();
|
||||||
_server.begin();
|
_server.begin();
|
||||||
if(!_headerKeysCount)
|
|
||||||
collectHeaders(0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
String ESP8266WebServer::_exractParam(String& authReq,const String& param,const char delimit){
|
void ESP8266WebServer::begin(uint16_t port) {
|
||||||
|
close();
|
||||||
|
_server.begin(port);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ESP8266WebServer::_extractParam(String& authReq,const String& param,const char delimit){
|
||||||
int _begin = authReq.indexOf(param);
|
int _begin = authReq.indexOf(param);
|
||||||
if (_begin==-1) return "";
|
if (_begin==-1)
|
||||||
|
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()));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ESP8266WebServer::authenticate(const char * username, const char * password){
|
bool ESP8266WebServer::authenticate(const char * username, const char * password){
|
||||||
if(hasHeader(AUTHORIZATION_HEADER)){
|
if(hasHeader(FPSTR(AUTHORIZATION_HEADER))) {
|
||||||
String authReq = header(AUTHORIZATION_HEADER);
|
String authReq = header(FPSTR(AUTHORIZATION_HEADER));
|
||||||
if(authReq.startsWith("Basic")){
|
if(authReq.startsWith(F("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 = String();
|
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 = String();
|
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 = String();
|
authReq = "";
|
||||||
delete[] toencode;
|
delete[] toencode;
|
||||||
delete[] encoded;
|
delete[] encoded;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
delete[] toencode;
|
delete[] toencode;
|
||||||
delete[] encoded;
|
delete[] encoded;
|
||||||
}else if(authReq.startsWith("Digest")){
|
} else if(authReq.startsWith(F("Digest"))) {
|
||||||
authReq = authReq.substring(7);
|
authReq = authReq.substring(7);
|
||||||
#ifdef DEBUG_ESP_HTTP_SERVER
|
#ifdef DEBUG_ESP_HTTP_SERVER
|
||||||
DEBUG_OUTPUT.println(authReq);
|
DEBUG_OUTPUT.println(authReq);
|
||||||
#endif
|
#endif
|
||||||
String _username = _exractParam(authReq,"username=\"");
|
String _username = _extractParam(authReq,F("username=\""));
|
||||||
if((!_username.length())||_username!=String(username)){
|
if(!_username.length() || _username != String(username)) {
|
||||||
authReq = String();
|
authReq = "";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// extracting required parameters for RFC 2069 simpler Digest
|
// extracting required parameters for RFC 2069 simpler Digest
|
||||||
String _realm = _exractParam(authReq,"realm=\"");
|
String _realm = _extractParam(authReq, F("realm=\""));
|
||||||
String _nonce = _exractParam(authReq,"nonce=\"");
|
String _nonce = _extractParam(authReq, F("nonce=\""));
|
||||||
String _uri = _exractParam(authReq,"uri=\"");
|
String _uri = _extractParam(authReq, F("uri=\""));
|
||||||
String _response = _exractParam(authReq,"response=\"");
|
String _response = _extractParam(authReq, F("response=\""));
|
||||||
String _opaque = _exractParam(authReq,"opaque=\"");
|
String _opaque = _extractParam(authReq, F("opaque=\""));
|
||||||
|
|
||||||
if((!_realm.length())||(!_nonce.length())||(!_uri.length())||(!_response.length())||(!_opaque.length())){
|
if((!_realm.length()) || (!_nonce.length()) || (!_uri.length()) || (!_response.length()) || (!_opaque.length())) {
|
||||||
authReq = String();
|
authReq = "";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if((_opaque!=_sopaque)||(_nonce!=_snonce)||(_realm!=_srealm)){
|
if((_opaque != _sopaque) || (_nonce != _snonce) || (_realm != _srealm)) {
|
||||||
authReq = String();
|
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){
|
if(authReq.indexOf(FPSTR(qop_auth)) != -1) {
|
||||||
_nc = _exractParam(authReq,"nc=",',');
|
_nc = _extractParam(authReq, F("nc="), ',');
|
||||||
_cnonce = _exractParam(authReq,"cnonce=\"");
|
_cnonce = _extractParam(authReq, F("cnonce=\""));
|
||||||
}
|
}
|
||||||
MD5Builder md5;
|
MD5Builder md5;
|
||||||
md5.begin();
|
md5.begin();
|
||||||
md5.add(String(username)+":"+_realm+":"+String(password)); // md5 of the user:realm:user
|
md5.add(String(username) + ':' + _realm + ':' + String(password)); // md5 of the user:realm:user
|
||||||
md5.calculate();
|
md5.calculate();
|
||||||
String _H1 = md5.toString();
|
String _H1 = md5.toString();
|
||||||
#ifdef DEBUG_ESP_HTTP_SERVER
|
#ifdef DEBUG_ESP_HTTP_SERVER
|
||||||
@ -168,15 +178,15 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password
|
|||||||
#endif
|
#endif
|
||||||
md5.begin();
|
md5.begin();
|
||||||
if(_currentMethod == HTTP_GET){
|
if(_currentMethod == HTTP_GET){
|
||||||
md5.add("GET:"+_uri);
|
md5.add(String(F("GET:")) + _uri);
|
||||||
}else if(_currentMethod == HTTP_POST){
|
}else if(_currentMethod == HTTP_POST){
|
||||||
md5.add("POST:"+_uri);
|
md5.add(String(F("POST:")) + _uri);
|
||||||
}else if(_currentMethod == HTTP_PUT){
|
}else if(_currentMethod == HTTP_PUT){
|
||||||
md5.add("PUT:"+_uri);
|
md5.add(String(F("PUT:")) + _uri);
|
||||||
}else if(_currentMethod == HTTP_DELETE){
|
}else if(_currentMethod == HTTP_DELETE){
|
||||||
md5.add("DELETE:"+_uri);
|
md5.add(String(F("DELETE:")) + _uri);
|
||||||
}else{
|
}else{
|
||||||
md5.add("GET:"+_uri);
|
md5.add(String(F("GET:")) + _uri);
|
||||||
}
|
}
|
||||||
md5.calculate();
|
md5.calculate();
|
||||||
String _H2 = md5.toString();
|
String _H2 = md5.toString();
|
||||||
@ -184,49 +194,50 @@ bool ESP8266WebServer::authenticate(const char * username, const char * password
|
|||||||
DEBUG_OUTPUT.println("Hash of GET:uri=" + _H2);
|
DEBUG_OUTPUT.println("Hash of GET:uri=" + _H2);
|
||||||
#endif
|
#endif
|
||||||
md5.begin();
|
md5.begin();
|
||||||
if(authReq.indexOf("qop=auth") != -1){
|
if(authReq.indexOf(FPSTR(qop_auth)) != -1) {
|
||||||
md5.add(_H1+":"+_nonce+":"+_nc+":"+_cnonce+":auth:"+_H2);
|
md5.add(_H1 + FPSTR(colon) + _nonce + FPSTR(colon) + _nc + FPSTR(colon) + _cnonce + ':auth:' + _H2);
|
||||||
}else{
|
}else{
|
||||||
md5.add(_H1+":"+_nonce+":"+_H2);
|
md5.add(_H1 + FPSTR(colon) + _nonce + FPSTR(colon) + _H2);
|
||||||
}
|
}
|
||||||
md5.calculate();
|
md5.calculate();
|
||||||
String _responsecheck = md5.toString();
|
String _responsecheck = md5.toString();
|
||||||
#ifdef DEBUG_ESP_HTTP_SERVER
|
#ifdef DEBUG_ESP_HTTP_SERVER
|
||||||
DEBUG_OUTPUT.println("The Proper response=" +_responsecheck);
|
DEBUG_OUTPUT.println("The Proper response=" +_responsecheck);
|
||||||
#endif
|
#endif
|
||||||
if(_response==_responsecheck){
|
if(_response == _responsecheck){
|
||||||
authReq = String();
|
authReq = "";
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
authReq = String();
|
authReq = "";
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
String ESP8266WebServer::_getRandomHexString(){
|
String ESP8266WebServer::_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), "%08x", RANDOM_REG32);
|
sprintf (buffer + (i*8), "%08x", RANDOM_REG32);
|
||||||
}
|
}
|
||||||
return String(buffer);
|
return String(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg){
|
void ESP8266WebServer::requestAuthentication(HTTPAuthMethod mode, const char* realm, const String& authFailMsg) {
|
||||||
if(realm==NULL){
|
if(realm == NULL) {
|
||||||
_srealm = "Login Required";
|
_srealm = String(F("Login Required"));
|
||||||
}else{
|
} else {
|
||||||
_srealm = String(realm);
|
_srealm = String(realm);
|
||||||
}
|
}
|
||||||
if(mode==BASIC_AUTH){
|
if(mode == BASIC_AUTH) {
|
||||||
sendHeader("WWW-Authenticate", "Basic realm=\"" + _srealm + "\"");
|
sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Basic realm=\"")) + _srealm + String(F("\"")));
|
||||||
}else{
|
} else {
|
||||||
_snonce=_getRandomHexString();
|
_snonce=_getRandomHexString();
|
||||||
_sopaque=_getRandomHexString();
|
_sopaque=_getRandomHexString();
|
||||||
sendHeader("WWW-Authenticate", "Digest realm=\"" +_srealm + "\", qop=\"auth\", nonce=\""+_snonce+"\", opaque=\""+_sopaque+"\"");
|
sendHeader(String(FPSTR(WWW_Authenticate)), String(F("Digest realm=\"")) +_srealm + String(F("\", qop=\"auth\", nonce=\"")) + _snonce + String(F("\", opaque=\"")) + _sopaque + String(F("\"")));
|
||||||
}
|
}
|
||||||
send(401,"text/html",authFailMsg);
|
using namespace mime;
|
||||||
|
send(401, mimeTable[html].mimeType, authFailMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::on(const String &uri, ESP8266WebServer::THandlerFunction handler) {
|
void ESP8266WebServer::on(const String &uri, ESP8266WebServer::THandlerFunction handler) {
|
||||||
@ -327,6 +338,9 @@ void ESP8266WebServer::handleClient() {
|
|||||||
|
|
||||||
void ESP8266WebServer::close() {
|
void ESP8266WebServer::close() {
|
||||||
_server.close();
|
_server.close();
|
||||||
|
_currentStatus = HC_NONE;
|
||||||
|
if(!_headerKeysCount)
|
||||||
|
collectHeaders(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::stop() {
|
void ESP8266WebServer::stop() {
|
||||||
@ -335,7 +349,7 @@ void ESP8266WebServer::stop() {
|
|||||||
|
|
||||||
void ESP8266WebServer::sendHeader(const String& name, const String& value, bool first) {
|
void ESP8266WebServer::sendHeader(const String& name, const String& value, bool first) {
|
||||||
String headerLine = name;
|
String headerLine = name;
|
||||||
headerLine += ": ";
|
headerLine += F(": ");
|
||||||
headerLine += value;
|
headerLine += value;
|
||||||
headerLine += "\r\n";
|
headerLine += "\r\n";
|
||||||
|
|
||||||
@ -347,36 +361,37 @@ void ESP8266WebServer::sendHeader(const String& name, const String& value, bool
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::setContentLength(size_t contentLength) {
|
void ESP8266WebServer::setContentLength(const size_t contentLength) {
|
||||||
_contentLength = contentLength;
|
_contentLength = contentLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) {
|
void ESP8266WebServer::_prepareHeader(String& response, int code, const char* content_type, size_t contentLength) {
|
||||||
response = "HTTP/1."+String(_currentVersion)+" ";
|
response = String(F("HTTP/1.")) + String(_currentVersion) + ' ';
|
||||||
response += String(code);
|
response += String(code);
|
||||||
response += " ";
|
response += ' ';
|
||||||
response += _responseCodeToString(code);
|
response += _responseCodeToString(code);
|
||||||
response += "\r\n";
|
response += "\r\n";
|
||||||
|
|
||||||
|
using namespace mime;
|
||||||
if (!content_type)
|
if (!content_type)
|
||||||
content_type = "text/html";
|
content_type = mimeTable[html].mimeType;
|
||||||
|
|
||||||
sendHeader("Content-Type", content_type, true);
|
sendHeader(String(F("Content-Type")), content_type, true);
|
||||||
if (_contentLength == CONTENT_LENGTH_NOT_SET) {
|
if (_contentLength == CONTENT_LENGTH_NOT_SET) {
|
||||||
sendHeader("Content-Length", String(contentLength));
|
sendHeader(String(FPSTR(Content_Length)), String(contentLength));
|
||||||
} else if (_contentLength != CONTENT_LENGTH_UNKNOWN) {
|
} else if (_contentLength != CONTENT_LENGTH_UNKNOWN) {
|
||||||
sendHeader("Content-Length", String(_contentLength));
|
sendHeader(String(FPSTR(Content_Length)), String(_contentLength));
|
||||||
} else if(_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion){ //HTTP/1.1 or above client
|
} else if(_contentLength == CONTENT_LENGTH_UNKNOWN && _currentVersion){ //HTTP/1.1 or above client
|
||||||
//let's do chunked
|
//let's do chunked
|
||||||
_chunked = true;
|
_chunked = true;
|
||||||
sendHeader("Accept-Ranges","none");
|
sendHeader(String(F("Accept-Ranges")),String(F("none")));
|
||||||
sendHeader("Transfer-Encoding","chunked");
|
sendHeader(String(F("Transfer-Encoding")),String(F("chunked")));
|
||||||
}
|
}
|
||||||
sendHeader("Connection", "close");
|
sendHeader(String(F("Connection")), String(F("close")));
|
||||||
|
|
||||||
response += _responseHeaders;
|
response += _responseHeaders;
|
||||||
response += "\r\n";
|
response += "\r\n";
|
||||||
_responseHeaders = String();
|
_responseHeaders = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::send(int code, const char* content_type, const String& content) {
|
void ESP8266WebServer::send(int code, const char* content_type, const String& content) {
|
||||||
@ -466,24 +481,37 @@ void ESP8266WebServer::sendContent_P(PGM_P content, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void ESP8266WebServer::_streamFileCore(const size_t fileSize, const String & fileName, const String & contentType)
|
||||||
|
{
|
||||||
|
using namespace mime;
|
||||||
|
setContentLength(fileSize);
|
||||||
|
if (fileName.endsWith(mimeTable[gz].endsWith) &&
|
||||||
|
contentType != mimeTable[gz].mimeType &&
|
||||||
|
contentType != mimeTable[none].mimeType) {
|
||||||
|
sendHeader(F("Content-Encoding"), F("gzip"));
|
||||||
|
}
|
||||||
|
send(200, contentType, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
String ESP8266WebServer::arg(String name) {
|
String ESP8266WebServer::arg(String name) {
|
||||||
for (int i = 0; i < _currentArgCount; ++i) {
|
for (int i = 0; i < _currentArgCount; ++i) {
|
||||||
if ( _currentArgs[i].key == name )
|
if ( _currentArgs[i].key == name )
|
||||||
return _currentArgs[i].value;
|
return _currentArgs[i].value;
|
||||||
}
|
}
|
||||||
return String();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String ESP8266WebServer::arg(int i) {
|
String ESP8266WebServer::arg(int i) {
|
||||||
if (i < _currentArgCount)
|
if (i < _currentArgCount)
|
||||||
return _currentArgs[i].value;
|
return _currentArgs[i].value;
|
||||||
return String();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String ESP8266WebServer::argName(int i) {
|
String ESP8266WebServer::argName(int i) {
|
||||||
if (i < _currentArgCount)
|
if (i < _currentArgCount)
|
||||||
return _currentArgs[i].key;
|
return _currentArgs[i].key;
|
||||||
return String();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int ESP8266WebServer::args() {
|
int ESP8266WebServer::args() {
|
||||||
@ -504,7 +532,7 @@ String ESP8266WebServer::header(String name) {
|
|||||||
if (_currentHeaders[i].key.equalsIgnoreCase(name))
|
if (_currentHeaders[i].key.equalsIgnoreCase(name))
|
||||||
return _currentHeaders[i].value;
|
return _currentHeaders[i].value;
|
||||||
}
|
}
|
||||||
return String();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
|
void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t headerKeysCount) {
|
||||||
@ -512,7 +540,7 @@ void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t hea
|
|||||||
if (_currentHeaders)
|
if (_currentHeaders)
|
||||||
delete[]_currentHeaders;
|
delete[]_currentHeaders;
|
||||||
_currentHeaders = new RequestArgument[_headerKeysCount];
|
_currentHeaders = new RequestArgument[_headerKeysCount];
|
||||||
_currentHeaders[0].key = AUTHORIZATION_HEADER;
|
_currentHeaders[0].key = FPSTR(AUTHORIZATION_HEADER);
|
||||||
for (int i = 1; i < _headerKeysCount; i++){
|
for (int i = 1; i < _headerKeysCount; i++){
|
||||||
_currentHeaders[i].key = headerKeys[i-1];
|
_currentHeaders[i].key = headerKeys[i-1];
|
||||||
}
|
}
|
||||||
@ -521,13 +549,13 @@ void ESP8266WebServer::collectHeaders(const char* headerKeys[], const size_t hea
|
|||||||
String ESP8266WebServer::header(int i) {
|
String ESP8266WebServer::header(int i) {
|
||||||
if (i < _headerKeysCount)
|
if (i < _headerKeysCount)
|
||||||
return _currentHeaders[i].value;
|
return _currentHeaders[i].value;
|
||||||
return String();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
String ESP8266WebServer::headerName(int i) {
|
String ESP8266WebServer::headerName(int i) {
|
||||||
if (i < _headerKeysCount)
|
if (i < _headerKeysCount)
|
||||||
return _currentHeaders[i].key;
|
return _currentHeaders[i].key;
|
||||||
return String();
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
int ESP8266WebServer::headers() {
|
int ESP8266WebServer::headers() {
|
||||||
@ -574,13 +602,14 @@ void ESP8266WebServer::_handleRequest() {
|
|||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
send(404, "text/plain", String("Not found: ") + _currentUri);
|
using namespace mime;
|
||||||
|
send(404, mimeTable[html].mimeType, String(F("Not found: ")) + _currentUri);
|
||||||
handled = true;
|
handled = true;
|
||||||
}
|
}
|
||||||
if (handled) {
|
if (handled) {
|
||||||
_finalizeResponse();
|
_finalizeResponse();
|
||||||
}
|
}
|
||||||
_currentUri = String();
|
_currentUri = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -632,6 +661,6 @@ String ESP8266WebServer::_responseCodeToString(int code) {
|
|||||||
case 503: return F("Service Unavailable");
|
case 503: return F("Service Unavailable");
|
||||||
case 504: return F("Gateway Time-out");
|
case 504: return F("Gateway Time-out");
|
||||||
case 505: return F("HTTP Version not supported");
|
case 505: return F("HTTP Version not supported");
|
||||||
default: return "";
|
default: return F("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,7 @@ public:
|
|||||||
virtual ~ESP8266WebServer();
|
virtual ~ESP8266WebServer();
|
||||||
|
|
||||||
virtual void begin();
|
virtual void begin();
|
||||||
|
virtual void begin(uint16_t port);
|
||||||
virtual void handleClient();
|
virtual void handleClient();
|
||||||
|
|
||||||
virtual void close();
|
virtual void close();
|
||||||
@ -120,7 +121,7 @@ public:
|
|||||||
void send_P(int code, PGM_P content_type, PGM_P content);
|
void send_P(int code, PGM_P content_type, PGM_P content);
|
||||||
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
|
void send_P(int code, PGM_P content_type, PGM_P content, size_t contentLength);
|
||||||
|
|
||||||
void setContentLength(size_t contentLength);
|
void setContentLength(const size_t contentLength);
|
||||||
void sendHeader(const String& name, const String& value, bool first = false);
|
void sendHeader(const String& name, const String& value, bool first = false);
|
||||||
void sendContent(const String& content);
|
void sendContent(const String& content);
|
||||||
void sendContent_P(PGM_P content);
|
void sendContent_P(PGM_P content);
|
||||||
@ -128,17 +129,12 @@ public:
|
|||||||
|
|
||||||
static String urlDecode(const String& text);
|
static String urlDecode(const String& text);
|
||||||
|
|
||||||
template<typename T> size_t streamFile(T &file, const String& contentType){
|
template<typename T>
|
||||||
setContentLength(file.size());
|
size_t streamFile(T &file, const String& contentType) {
|
||||||
if (String(file.name()).endsWith(".gz") &&
|
_streamFileCore(file.size(), file.name(), contentType);
|
||||||
contentType != "application/x-gzip" &&
|
return _currentClient.write(file);
|
||||||
contentType != "application/octet-stream"){
|
|
||||||
sendHeader("Content-Encoding", "gzip");
|
|
||||||
}
|
}
|
||||||
send(200, contentType, "");
|
|
||||||
return _currentClient.write(file);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
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 _currentClient.write_P( b, l ); }
|
||||||
@ -154,10 +150,12 @@ protected:
|
|||||||
uint8_t _uploadReadByte(WiFiClient& client);
|
uint8_t _uploadReadByte(WiFiClient& 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);
|
||||||
|
|
||||||
|
void _streamFileCore(const size_t fileSize, const String & fileName, const String & contentType);
|
||||||
|
|
||||||
String _getRandomHexString();
|
String _getRandomHexString();
|
||||||
// for extracting Auth parameters
|
// for extracting Auth parameters
|
||||||
String _exractParam(String& authReq,const String& param,const char delimit = '"');
|
String _extractParam(String& authReq,const String& param,const char delimit = '"');
|
||||||
|
|
||||||
struct RequestArgument {
|
struct RequestArgument {
|
||||||
String key;
|
String key;
|
||||||
|
@ -2,32 +2,9 @@
|
|||||||
#define REQUESTHANDLERSIMPL_H
|
#define REQUESTHANDLERSIMPL_H
|
||||||
|
|
||||||
#include "RequestHandler.h"
|
#include "RequestHandler.h"
|
||||||
|
#include "mimetable.h"
|
||||||
|
|
||||||
// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules
|
using namespace mime;
|
||||||
static const struct {const char endsWith[16]; const char mimeType[32];} mimeTable[] ICACHE_RODATA_ATTR = {
|
|
||||||
{ ".html", "text/html" },
|
|
||||||
{ ".htm", "text/html" },
|
|
||||||
{ ".css", "text/css" },
|
|
||||||
{ ".txt", "text/plain" },
|
|
||||||
{ ".js", "application/javascript" },
|
|
||||||
{ ".json", "application/json" },
|
|
||||||
{ ".png", "image/png" },
|
|
||||||
{ ".gif", "image/gif" },
|
|
||||||
{ ".jpg", "image/jpeg" },
|
|
||||||
{ ".ico", "image/x-icon" },
|
|
||||||
{ ".svg", "image/svg+xml" },
|
|
||||||
{ ".ttf", "application/x-font-ttf" },
|
|
||||||
{ ".otf", "application/x-font-opentype" },
|
|
||||||
{ ".woff", "application/font-woff" },
|
|
||||||
{ ".woff2", "application/font-woff2" },
|
|
||||||
{ ".eot", "application/vnd.ms-fontobject" },
|
|
||||||
{ ".sfnt", "application/font-sfnt" },
|
|
||||||
{ ".xml", "text/xml" },
|
|
||||||
{ ".pdf", "application/pdf" },
|
|
||||||
{ ".zip", "application/zip" },
|
|
||||||
{ ".gz", "application/x-gzip" },
|
|
||||||
{ ".appcache", "text/cache-manifest" },
|
|
||||||
{ "", "application/octet-stream" } };
|
|
||||||
|
|
||||||
class FunctionRequestHandler : public RequestHandler {
|
class FunctionRequestHandler : public RequestHandler {
|
||||||
public:
|
public:
|
||||||
@ -124,10 +101,10 @@ public:
|
|||||||
|
|
||||||
// look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for
|
// look for gz file, only if the original specified path is not a gz. So part only works to send gzip via content encoding when a non compressed is asked for
|
||||||
// if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc...
|
// if you point the the path to gzip you will serve the gzip as content type "application/x-gzip", not text or javascript etc...
|
||||||
if (!path.endsWith(".gz") && !_fs.exists(path)) {
|
if (!path.endsWith(mimeTable[gz].endsWith) && !_fs.exists(path)) {
|
||||||
String pathWithGz = path + ".gz";
|
String pathWithGz = path + mimeTable[gz].endsWith;
|
||||||
if(_fs.exists(pathWithGz))
|
if(_fs.exists(pathWithGz))
|
||||||
path += ".gz";
|
path += mimeTable[gz].endsWith;
|
||||||
}
|
}
|
||||||
|
|
||||||
File f = _fs.open(path, "r");
|
File f = _fs.open(path, "r");
|
||||||
|
35
libraries/ESP8266WebServer/src/detail/mimetable.cpp
Normal file
35
libraries/ESP8266WebServer/src/detail/mimetable.cpp
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
#include "mimetable.h"
|
||||||
|
#include "pgmspace.h"
|
||||||
|
|
||||||
|
namespace mime
|
||||||
|
{
|
||||||
|
|
||||||
|
// Table of extension->MIME strings stored in PROGMEM, needs to be global due to GCC section typing rules
|
||||||
|
const Entry mimeTable[maxType] ICACHE_RODATA_ATTR =
|
||||||
|
{
|
||||||
|
{ ".html", "text/html" },
|
||||||
|
{ ".htm", "text/html" },
|
||||||
|
{ ".css", "text/css" },
|
||||||
|
{ ".txt", "text/plain" },
|
||||||
|
{ ".js", "application/javascript" },
|
||||||
|
{ ".json", "application/json" },
|
||||||
|
{ ".png", "image/png" },
|
||||||
|
{ ".gif", "image/gif" },
|
||||||
|
{ ".jpg", "image/jpeg" },
|
||||||
|
{ ".ico", "image/x-icon" },
|
||||||
|
{ ".svg", "image/svg+xml" },
|
||||||
|
{ ".ttf", "application/x-font-ttf" },
|
||||||
|
{ ".otf", "application/x-font-opentype" },
|
||||||
|
{ ".woff", "application/font-woff" },
|
||||||
|
{ ".woff2", "application/font-woff2" },
|
||||||
|
{ ".eot", "application/vnd.ms-fontobject" },
|
||||||
|
{ ".sfnt", "application/font-sfnt" },
|
||||||
|
{ ".xml", "text/xml" },
|
||||||
|
{ ".pdf", "application/pdf" },
|
||||||
|
{ ".zip", "application/zip" },
|
||||||
|
{ ".gz", "application/x-gzip" },
|
||||||
|
{ ".appcache", "text/cache-manifest" },
|
||||||
|
{ "", "application/octet-stream" }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
47
libraries/ESP8266WebServer/src/detail/mimetable.h
Normal file
47
libraries/ESP8266WebServer/src/detail/mimetable.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef __MIMETABLE_H__
|
||||||
|
#define __MIMETABLE_H__
|
||||||
|
|
||||||
|
|
||||||
|
namespace mime
|
||||||
|
{
|
||||||
|
|
||||||
|
enum type
|
||||||
|
{
|
||||||
|
html,
|
||||||
|
htm,
|
||||||
|
css,
|
||||||
|
txt,
|
||||||
|
js,
|
||||||
|
json,
|
||||||
|
png,
|
||||||
|
gif,
|
||||||
|
jpg,
|
||||||
|
ico,
|
||||||
|
svg,
|
||||||
|
ttf,
|
||||||
|
otf,
|
||||||
|
woff,
|
||||||
|
woff2,
|
||||||
|
eot,
|
||||||
|
sfnt,
|
||||||
|
xml,
|
||||||
|
pdf,
|
||||||
|
zip,
|
||||||
|
gz,
|
||||||
|
appcache,
|
||||||
|
none,
|
||||||
|
maxType
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Entry
|
||||||
|
{
|
||||||
|
const char endsWith[16];
|
||||||
|
const char mimeType[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
extern const Entry mimeTable[maxType];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user