forked from me-no-dev/ESPAsyncWebServer
Merge branch 'master' into fix-serveStatic
Conflicts: src/AsyncWebServerHandlerImpl.h
This commit is contained in:
@@ -1,2 +1,10 @@
|
|||||||
# ESPAsyncWebServer
|
# ESPAsyncWebServer
|
||||||
|
|
||||||
|
[](https://gitter.im/me-no-dev/ESPAsyncWebServer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||||
Async Web Server for ESP8266 Arduino
|
Async Web Server for ESP8266 Arduino
|
||||||
|
Requires [ESPAsyncTCP](https://github.com/me-no-dev/ESPAsyncTCP) to work
|
||||||
|
|
||||||
|
This library should be considered experimental
|
||||||
|
Examples, description and all will be provided really soon :)
|
||||||
|
|
||||||
|
To use this library you need to have the git versions of either ESP8266 or ESP31B Arduino Core
|
||||||
|
199
examples/ESP32_AsyncFSBrowser/ESP32_AsyncFSBrowser.ino
Normal file
199
examples/ESP32_AsyncFSBrowser/ESP32_AsyncFSBrowser.ino
Normal file
@@ -0,0 +1,199 @@
|
|||||||
|
#include <ESP31BWiFi.h>
|
||||||
|
#include <ESPAsyncTCP.h>
|
||||||
|
#include <ESPAsyncWebServer.h>
|
||||||
|
#include <FS.h>
|
||||||
|
|
||||||
|
// WEB HANDLER IMPLEMENTATION
|
||||||
|
class SPIFFSEditor: public AsyncWebHandler {
|
||||||
|
private:
|
||||||
|
String _username;
|
||||||
|
String _password;
|
||||||
|
bool _uploadAuthenticated;
|
||||||
|
public:
|
||||||
|
SPIFFSEditor(String username=String(), String password=String()):_username(username),_password(password),_uploadAuthenticated(false){}
|
||||||
|
bool canHandle(AsyncWebServerRequest *request){
|
||||||
|
if(request->method() == HTTP_GET && request->url() == "/edit" && (SPIFFS.exists("/edit.htm") || SPIFFS.exists("/edit.htm.gz")))
|
||||||
|
return true;
|
||||||
|
else if(request->method() == HTTP_GET && request->url() == "/list")
|
||||||
|
return true;
|
||||||
|
else if(request->method() == HTTP_GET && (request->url().endsWith("/") || SPIFFS.exists(request->url()) || (!request->hasParam("download") && SPIFFS.exists(request->url()+".gz"))))
|
||||||
|
return true;
|
||||||
|
else if(request->method() == HTTP_POST && request->url() == "/edit")
|
||||||
|
return true;
|
||||||
|
else if(request->method() == HTTP_DELETE && request->url() == "/edit")
|
||||||
|
return true;
|
||||||
|
else if(request->method() == HTTP_PUT && request->url() == "/edit")
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleRequest(AsyncWebServerRequest *request){
|
||||||
|
if(_username.length() && (request->method() != HTTP_GET || request->url() == "/edit" || request->url() == "/list") && !request->authenticate(_username.c_str(),_password.c_str()))
|
||||||
|
return request->requestAuthentication();
|
||||||
|
|
||||||
|
if(request->method() == HTTP_GET && request->url() == "/edit"){
|
||||||
|
request->send(SPIFFS, "/edit.htm");
|
||||||
|
} else if(request->method() == HTTP_GET && request->url() == "/list"){
|
||||||
|
if(request->hasParam("dir")){
|
||||||
|
String path = request->getParam("dir")->value();
|
||||||
|
Dir dir = SPIFFS.openDir(path);
|
||||||
|
path = String();
|
||||||
|
String output = "[";
|
||||||
|
while(dir.next()){
|
||||||
|
File entry = dir.openFile("r");
|
||||||
|
if (output != "[") output += ',';
|
||||||
|
bool isDir = false;
|
||||||
|
output += "{\"type\":\"";
|
||||||
|
output += (isDir)?"dir":"file";
|
||||||
|
output += "\",\"name\":\"";
|
||||||
|
output += String(entry.name()).substring(1);
|
||||||
|
output += "\"}";
|
||||||
|
entry.close();
|
||||||
|
}
|
||||||
|
output += "]";
|
||||||
|
request->send(200, "text/json", output);
|
||||||
|
output = String();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
request->send(400);
|
||||||
|
} else if(request->method() == HTTP_GET){
|
||||||
|
String path = request->url();
|
||||||
|
if(path.endsWith("/"))
|
||||||
|
path += "index.htm";
|
||||||
|
request->send(SPIFFS, path, String(), request->hasParam("download"));
|
||||||
|
} else if(request->method() == HTTP_DELETE){
|
||||||
|
if(request->hasParam("path", true)){
|
||||||
|
SPIFFS.remove(request->getParam("path", true)->value());
|
||||||
|
request->send(200, "", "DELETE: "+request->getParam("path", true)->value());
|
||||||
|
} else
|
||||||
|
request->send(404);
|
||||||
|
} else if(request->method() == HTTP_POST){
|
||||||
|
if(request->hasParam("data", true, true) && SPIFFS.exists(request->getParam("data", true, true)->value()))
|
||||||
|
request->send(200, "", "UPLOADED: "+request->getParam("data", true, true)->value());
|
||||||
|
else
|
||||||
|
request->send(500);
|
||||||
|
} else if(request->method() == HTTP_PUT){
|
||||||
|
if(request->hasParam("path", true)){
|
||||||
|
String filename = request->getParam("path", true)->value();
|
||||||
|
if(SPIFFS.exists(filename)){
|
||||||
|
request->send(200);
|
||||||
|
} else {
|
||||||
|
File f = SPIFFS.open(filename, "w");
|
||||||
|
if(f){
|
||||||
|
f.write(0x00);
|
||||||
|
f.close();
|
||||||
|
request->send(200, "", "CREATE: "+filename);
|
||||||
|
} else {
|
||||||
|
request->send(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
request->send(400);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleUpload(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||||
|
if(!index){
|
||||||
|
if(!_username.length() || request->authenticate(_username.c_str(),_password.c_str()))
|
||||||
|
_uploadAuthenticated = true;
|
||||||
|
request->_tempFile = SPIFFS.open(filename, "w");
|
||||||
|
}
|
||||||
|
if(_uploadAuthenticated && request->_tempFile && len){
|
||||||
|
request->_tempFile.write(data,len);
|
||||||
|
}
|
||||||
|
if(_uploadAuthenticated && final)
|
||||||
|
if(request->_tempFile) request->_tempFile.close();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// SKETCH BEGIN
|
||||||
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
const char* ssid = "**********";
|
||||||
|
const char* password = "************";
|
||||||
|
const char* http_username = "admin";
|
||||||
|
const char* http_password = "admin";
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.setDebugOutput(true);
|
||||||
|
SPIFFS.begin();
|
||||||
|
WiFi.mode(WIFI_STA);
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
if(WiFi.waitForConnectResult() != WL_CONNECTED){
|
||||||
|
Serial.printf("WiFi Failed!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
server.serveStatic("/fs", SPIFFS, "/");
|
||||||
|
|
||||||
|
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
request->send(200, "text/plain", String(ESP.getFreeHeap()));
|
||||||
|
});
|
||||||
|
server.addHandler(new SPIFFSEditor(http_username,http_password));
|
||||||
|
|
||||||
|
server.onNotFound([](AsyncWebServerRequest *request){
|
||||||
|
os_printf("NOT_FOUND: ");
|
||||||
|
if(request->method() == HTTP_GET)
|
||||||
|
os_printf("GET");
|
||||||
|
else if(request->method() == HTTP_POST)
|
||||||
|
os_printf("POST");
|
||||||
|
else if(request->method() == HTTP_DELETE)
|
||||||
|
os_printf("DELETE");
|
||||||
|
else if(request->method() == HTTP_PUT)
|
||||||
|
os_printf("PUT");
|
||||||
|
else if(request->method() == HTTP_PATCH)
|
||||||
|
os_printf("PATCH");
|
||||||
|
else if(request->method() == HTTP_HEAD)
|
||||||
|
os_printf("HEAD");
|
||||||
|
else if(request->method() == HTTP_OPTIONS)
|
||||||
|
os_printf("OPTIONS");
|
||||||
|
else
|
||||||
|
os_printf("UNKNOWN");
|
||||||
|
os_printf(" http://%s%s\n", request->host().c_str(), request->url().c_str());
|
||||||
|
|
||||||
|
if(request->contentLength()){
|
||||||
|
os_printf("_CONTENT_TYPE: %s\n", request->contentType().c_str());
|
||||||
|
os_printf("_CONTENT_LENGTH: %u\n", request->contentLength());
|
||||||
|
}
|
||||||
|
|
||||||
|
int headers = request->headers();
|
||||||
|
int i;
|
||||||
|
for(i=0;i<headers;i++){
|
||||||
|
AsyncWebHeader* h = request->getHeader(i);
|
||||||
|
os_printf("_HEADER[%s]: %s\n", h->name().c_str(), h->value().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
int params = request->params();
|
||||||
|
for(i=0;i<params;i++){
|
||||||
|
AsyncWebParameter* p = request->getParam(i);
|
||||||
|
if(p->isFile()){
|
||||||
|
os_printf("_FILE[%s]: %s, size: %u\n", p->name().c_str(), p->value().c_str(), p->size());
|
||||||
|
} else if(p->isPost()){
|
||||||
|
os_printf("_POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||||
|
} else {
|
||||||
|
os_printf("_GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
request->send(404);
|
||||||
|
});
|
||||||
|
server.onFileUpload([](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final){
|
||||||
|
if(!index)
|
||||||
|
os_printf("UploadStart: %s\n", filename.c_str());
|
||||||
|
os_printf("%s", (const char*)data);
|
||||||
|
if(final)
|
||||||
|
os_printf("UploadEnd: %s (%u)\n", filename.c_str(), index+len);
|
||||||
|
});
|
||||||
|
server.onRequestBody([](AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total){
|
||||||
|
if(!index)
|
||||||
|
os_printf("BodyStart: %u\n", total);
|
||||||
|
os_printf("%s", (const char*)data);
|
||||||
|
if(index + len == total)
|
||||||
|
os_printf("BodyEnd: %u\n", total);
|
||||||
|
});
|
||||||
|
server.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){}
|
||||||
|
|
BIN
examples/ESP32_AsyncFSBrowser/data/edit.htm.gz
Normal file
BIN
examples/ESP32_AsyncFSBrowser/data/edit.htm.gz
Normal file
Binary file not shown.
BIN
examples/ESP32_AsyncFSBrowser/data/favicon.ico
Normal file
BIN
examples/ESP32_AsyncFSBrowser/data/favicon.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
BIN
examples/ESP32_AsyncFSBrowser/data/graphs.js.gz
Normal file
BIN
examples/ESP32_AsyncFSBrowser/data/graphs.js.gz
Normal file
Binary file not shown.
366
examples/ESP32_AsyncFSBrowser/data/index.htm
Normal file
366
examples/ESP32_AsyncFSBrowser/data/index.htm
Normal file
@@ -0,0 +1,366 @@
|
|||||||
|
<!--
|
||||||
|
FSWebServer - Example Index Page
|
||||||
|
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||||
|
This file is part of the ESP8266WebServer library for Arduino environment.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
-->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||||
|
<title>ESP Monitor</title>
|
||||||
|
<script type="text/javascript" src="graphs.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
if (typeof XMLHttpRequest === "undefined") {
|
||||||
|
XMLHttpRequest = function () {
|
||||||
|
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e) {}
|
||||||
|
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e) {}
|
||||||
|
try { return new ActiveXObject("Microsoft.XMLHTTP"); } catch (e) {}
|
||||||
|
throw new Error("This browser does not support XMLHttpRequest.");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var QueuedRequester = function () {
|
||||||
|
this.queue = [];
|
||||||
|
this.running = false;
|
||||||
|
this.xmlhttp = null;
|
||||||
|
}
|
||||||
|
QueuedRequester.prototype = {
|
||||||
|
_request: function(req){
|
||||||
|
this.running = true;
|
||||||
|
if(!req instanceof Object) return;
|
||||||
|
var that = this;
|
||||||
|
|
||||||
|
function scriptCb(d){ return function(e){
|
||||||
|
d.callback(e);
|
||||||
|
if(that.queue.length === 0) that.running = false;
|
||||||
|
if(that.running) that._request(that.queue.shift());
|
||||||
|
}}
|
||||||
|
|
||||||
|
function ajaxCb(x,d){ return function(){
|
||||||
|
if (x.readyState == 4){
|
||||||
|
if(x.status == 200){
|
||||||
|
if(d.type === "json") d.callback(JSON.parse(x.responseText));
|
||||||
|
else if(d.type === "xml") d.callback(x.responseXML);
|
||||||
|
else d.callback(x.responseText);
|
||||||
|
}
|
||||||
|
if(that.queue.length === 0) that.running = false;
|
||||||
|
if(that.running) that._request(that.queue.shift());
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
|
||||||
|
var p = "";
|
||||||
|
if(req.params instanceof Object){
|
||||||
|
for (var key in req.params) {
|
||||||
|
if(p === "")
|
||||||
|
p += (req.method === "GET" || req.method === "SCRIPT")?"?":"";
|
||||||
|
else
|
||||||
|
p += "&";
|
||||||
|
p += key+"="+req.params[key];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if(req.method === "SCRIPT"){
|
||||||
|
var head = document.getElementsByTagName('head')[0];
|
||||||
|
if(req.type === "css"){
|
||||||
|
var c = document.createElement('link');
|
||||||
|
c.setAttribute('href', req.url+p);
|
||||||
|
c.setAttribute('rel', 'stylesheet');
|
||||||
|
c.setAttribute('type', 'text/css');
|
||||||
|
c.setAttribute('async', 'true');
|
||||||
|
c.addEventListener('load', scriptCb(req), false);
|
||||||
|
head.appendChild(c);
|
||||||
|
} else if(req.type === "javascript"){
|
||||||
|
var s = document.createElement('script');
|
||||||
|
s.setAttribute('src', req.url+p);
|
||||||
|
s.setAttribute('type', 'text/javascript');
|
||||||
|
s.setAttribute('async', 'true');
|
||||||
|
s.addEventListener('load', scriptCb(req), false);
|
||||||
|
head.appendChild(s);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.xmlhttp = new XMLHttpRequest();
|
||||||
|
this.xmlhttp.onreadystatechange = ajaxCb(this.xmlhttp, req);
|
||||||
|
if(req.method === "GET"){
|
||||||
|
this.xmlhttp.open(req.method, req.url+p, true);
|
||||||
|
this.xmlhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
|
||||||
|
this.xmlhttp.send();
|
||||||
|
} else {
|
||||||
|
this.xmlhttp.open(req.method, req.url, true);
|
||||||
|
this.xmlhttp.send(p);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stop: function(){
|
||||||
|
if(this.running) this.running = false;
|
||||||
|
if(this.xmlhttp && this.xmlhttp.readyState < 4){
|
||||||
|
this.xmlhttp.abort();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
add: function(url, method, params, type, callback){
|
||||||
|
this.queue.push({url:url,method:method,params:params,type:type,callback:callback});
|
||||||
|
if(!this.running){
|
||||||
|
this._request(this.queue.shift());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var requests = new QueuedRequester();
|
||||||
|
var heap,temp,digi,rssi;
|
||||||
|
var reloadPeriod = 1000;
|
||||||
|
var running = false;
|
||||||
|
|
||||||
|
function ipStr(ip){
|
||||||
|
return (ip & 0xFF) + "." + ((ip >> 8) & 0xFF) + "." + ((ip >> 16) & 0xFF) + "." + ((ip >> 24) & 0xFF);
|
||||||
|
}
|
||||||
|
function statusStr(status){
|
||||||
|
if(status === 0) return "IDLE";
|
||||||
|
else if(status === 1) return "CONNECTING";
|
||||||
|
else if(status === 2) return "WRONG_PASSWORD";
|
||||||
|
else if(status === 3) return "NO_AP_FOUND";
|
||||||
|
else if(status === 4) return "CONNECT_FAILED";
|
||||||
|
else if(status === 5) return "CONNECTED";
|
||||||
|
else return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
function securityStr(status){
|
||||||
|
if(status === 7) return "";
|
||||||
|
else if(status === 8) return "WPA/WPA2";
|
||||||
|
else if(status === 2) return "WPA";
|
||||||
|
else if(status === 4) return "WPA2";
|
||||||
|
else if(status === 5) return "WEP";
|
||||||
|
else return "UNKNOWN";
|
||||||
|
}
|
||||||
|
|
||||||
|
function loadValues(){
|
||||||
|
if(!running) return;
|
||||||
|
requests.add("/wificonf", "GET", null, "json", function(res){
|
||||||
|
if(res){
|
||||||
|
wifiState(res);
|
||||||
|
//rssi.add(res.rssi);
|
||||||
|
//heap.add(res.heap);
|
||||||
|
//temp.add(res.analog);
|
||||||
|
//digi.add(res.gpio);
|
||||||
|
if(running) setTimeout(loadValues, reloadPeriod);
|
||||||
|
} else running = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
function loadAvailables(){
|
||||||
|
if(!running) return;
|
||||||
|
requests.add("/scan", "GET", null, "json", function(res){
|
||||||
|
if(res){
|
||||||
|
wifiScan(res);
|
||||||
|
if(running) setTimeout(loadAvailables, 10*1000);
|
||||||
|
} else running = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
var avrParts = null;
|
||||||
|
var signature = null;
|
||||||
|
var lfuse = null;
|
||||||
|
var hfuse = null;
|
||||||
|
var efuse = null;
|
||||||
|
var lock = null;
|
||||||
|
var part = null;
|
||||||
|
|
||||||
|
function onNoPart(){
|
||||||
|
document.getElementById("avr-info").innerText = "AVR Part not found";
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPart(){
|
||||||
|
document.getElementById("avr-info").innerText = ("Part: id:"+part.id+" name:"+part.name+", signature:"+part.signature+", flash:"+part.flash+"B, eeprom:"+part.eeprom+"B, low:"+((part.fuses.low)?lfuse:"")+", high:"+((part.fuses.high)?hfuse:"")+", ext:"+((part.fuses.ext)?efuse:"")+", lock:"+((part.fuses.lock)?lock:"")+"");
|
||||||
|
}
|
||||||
|
|
||||||
|
function avrInfo(){
|
||||||
|
requests.add("/avr/info", "GET", null, "json", function(res){
|
||||||
|
var sig = (res.sig0 << 16) + (res.sig1 << 8) + res.sig2;
|
||||||
|
if(sig == 0){
|
||||||
|
onNoPart();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
signature = "0x"+sig.toString(16);
|
||||||
|
lfuse = res.low.toString(16);
|
||||||
|
hfuse = res.high.toString(16);
|
||||||
|
efuse = res.ext.toString(16);
|
||||||
|
lock = res.lock.toString(16);
|
||||||
|
if(avrParts == null){
|
||||||
|
requests.add("/avrs.json", "GET", null, "json", function(res){
|
||||||
|
if(!res) return;
|
||||||
|
avrParts = res;
|
||||||
|
for(p in avrParts){
|
||||||
|
if(avrParts[p].signature === signature){
|
||||||
|
part = avrParts[p];
|
||||||
|
onPart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
for(p in avrParts){
|
||||||
|
if(avrParts[p].signature === signature){
|
||||||
|
part = avrParts[p];
|
||||||
|
onPart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
function run(){
|
||||||
|
if(!running){
|
||||||
|
running = true;
|
||||||
|
loadValues();
|
||||||
|
loadAvailables();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onBodyLoad(){
|
||||||
|
var refreshInput = document.getElementById("refresh-rate");
|
||||||
|
refreshInput.value = reloadPeriod;
|
||||||
|
refreshInput.onchange = function(e){
|
||||||
|
var value = parseInt(e.target.value);
|
||||||
|
reloadPeriod = (value > 0)?value:0;
|
||||||
|
e.target.value = reloadPeriod;
|
||||||
|
}
|
||||||
|
var stopButton = document.getElementById("stop-button");
|
||||||
|
stopButton.onclick = function(e){
|
||||||
|
running = false;
|
||||||
|
requests.stop();
|
||||||
|
}
|
||||||
|
var startButton = document.getElementById("start-button");
|
||||||
|
startButton.onclick = function(e){
|
||||||
|
run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Example with 10K thermistor
|
||||||
|
//function calcThermistor(v) {
|
||||||
|
// var t = Math.log(((10230000 / v) - 10000));
|
||||||
|
// t = (1/(0.001129148+(0.000234125*t)+(0.0000000876741*t*t*t)))-273.15;
|
||||||
|
// return (t>120)?0:Math.round(t*10)/10;
|
||||||
|
//}
|
||||||
|
//temp = createGraph(document.getElementById("analog"), "Temperature", 100, 128, 10, 40, false, "cyan", calcThermistor);
|
||||||
|
|
||||||
|
//temp = createGraph(document.getElementById("analog"), "Analog Input", 100, 128, 0, 1023, false, "cyan");
|
||||||
|
rssi = createGraph(document.getElementById("rssi"), "WiFi RSSI", 100, 116, -100, -10, false, "green");
|
||||||
|
//heap = createGraph(document.getElementById("heap"), "Current Heap", 100, 125, 0, 40000, true, "orange");
|
||||||
|
//digi = createDigiGraph(document.getElementById("digital"), "GPIO", 100, 146, [0, 4, 5, 16], "gold");
|
||||||
|
//run();
|
||||||
|
//avrInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function wifiState(res){
|
||||||
|
if(!res) return;
|
||||||
|
document.getElementsByName("ssid")[0].value = res.sta.ssid;
|
||||||
|
document.getElementsByName("bssid")[0].value = res.sta.bssid;
|
||||||
|
document.getElementsByName("channel")[0].value = res.sta.channel;
|
||||||
|
|
||||||
|
rssi.add(res.sta.rssi);
|
||||||
|
document.getElementsByName("status")[0].value = statusStr(res.sta.status);
|
||||||
|
document.getElementsByName("rssi")[0].value = res.sta.rssi;
|
||||||
|
document.getElementsByName("mac")[0].value = res.sta.mac;
|
||||||
|
|
||||||
|
document.getElementsByName("ip")[0].value = ipStr(res.sta.ip);
|
||||||
|
document.getElementsByName("mask")[0].value = ipStr(res.sta.netmask);
|
||||||
|
document.getElementsByName("gateway")[0].value = ipStr(res.sta.gateway);
|
||||||
|
document.getElementsByName("dns")[0].value = ipStr(res.sta.dns);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wifiScan(res){
|
||||||
|
if(!res || !res.length) return;
|
||||||
|
var table = document.getElementById("available");
|
||||||
|
table.innerHTML = "";
|
||||||
|
for (var i=0; i<res.length; i++){
|
||||||
|
var row = document.createElement("tr");
|
||||||
|
row.innerHTML = "<td>"+(i+1)+"</td><td>"+res[i].ssid+"</td><td>"+res[i].bssid+"</td><td>"+res[i].channel+"</td><td>"+securityStr(res[i].secure)+"</td><td>"+res[i].hidden+"</td><td>"+res[i].rssi+"</td>";
|
||||||
|
table.appendChild(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
#wifi-state {
|
||||||
|
display: block;
|
||||||
|
border: 1px solid rgb(68, 68, 68);
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
width: 500px;
|
||||||
|
background-color: rgb(238, 238, 238);
|
||||||
|
}
|
||||||
|
|
||||||
|
#wifi-state label {
|
||||||
|
width:100px;
|
||||||
|
display:inline-block;
|
||||||
|
font:14px Verdana;
|
||||||
|
}
|
||||||
|
#wifi-state input {
|
||||||
|
margin:1px;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border: 1px solid rgb(68, 68, 68);
|
||||||
|
padding: 5px;
|
||||||
|
margin: 5px;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color:#CCCCCC;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body id="index" style="margin:0; padding:0;" onload="onBodyLoad()">
|
||||||
|
<!--div id="avr-info"></div-->
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div id="controls" style="display: block; border: 1px solid rgb(68, 68, 68); padding: 5px; margin: 5px; width: 362px; background-color: rgb(238, 238, 238);">
|
||||||
|
<label>Period (ms):</label>
|
||||||
|
<input type="number" id="refresh-rate"/>
|
||||||
|
<input type="button" id="start-button" value="Start"/>
|
||||||
|
<input type="button" id="stop-button" value="Stop"/>
|
||||||
|
</div>
|
||||||
|
<div id="rssi"></div>
|
||||||
|
</div>
|
||||||
|
<div style="display:inline-block">
|
||||||
|
<div id="wifi-form">
|
||||||
|
<form id="wifi-state">
|
||||||
|
<label>SSID:</label><input type="text" name="ssid" disabled="true"/><label>MAC:</label><input type="text" name="mac" disabled="true"/><br />
|
||||||
|
<label>BSSID:</label><input type="text" name="bssid" disabled="true"/><label>IP:</label><input type="text" name="ip" disabled="true"/><br />
|
||||||
|
<label>Channel:</label><input type="text" name="channel" disabled="true"/><label>Netmask:</label><input type="text" name="mask" disabled="true"/><br />
|
||||||
|
<label>Status:</label><input type="text" name="status" disabled="true"/><label>Gateway:</label><input type="text" name="gateway" disabled="true"/><br />
|
||||||
|
<label>RSSI:</label><input type="text" name="rssi" disabled="true"/><label>DNS:</label><input type="text" name="dns" disabled="true"/>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th> </th>
|
||||||
|
<th style="width:200px">SSID</th>
|
||||||
|
<th style="width:150px">BSSID</th>
|
||||||
|
<th>Channel</th>
|
||||||
|
<th style="width:80px">Secure</th>
|
||||||
|
<th>Hidden</th>
|
||||||
|
<th>RSSI</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="available"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--div id="heap"></div>
|
||||||
|
<div id="analog"></div>
|
||||||
|
<div id="digital"></div-->
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@@ -1,9 +1,9 @@
|
|||||||
name=ESP8266 Async Web Server
|
name=ESP Async WebServer
|
||||||
version=1.0.0
|
version=1.0.0
|
||||||
author=ESP8266
|
author=Me-No-Dev
|
||||||
maintainer=Me-No-Dev
|
maintainer=Me-No-Dev
|
||||||
sentence=Async Web Server for ESP8266
|
sentence=Async Web Server for ESP8266 and ESP31B
|
||||||
paragraph=Async Web Server for ESP8266
|
paragraph=Async Web Server for ESP8266 and ESP31B
|
||||||
category=Other
|
category=Other
|
||||||
url=https://github.com/me-no-dev/ESPAsyncWebServer
|
url=https://github.com/me-no-dev/ESPAsyncWebServer
|
||||||
architectures=*
|
architectures=*
|
||||||
|
@@ -21,7 +21,8 @@ class AsyncStaticWebHandler: public AsyncWebHandler {
|
|||||||
public:
|
public:
|
||||||
AsyncStaticWebHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
|
AsyncStaticWebHandler(FS& fs, const char* path, const char* uri, const char* cache_header)
|
||||||
: _fs(fs), _uri(uri), _path(path), _cache_header(cache_header){
|
: _fs(fs), _uri(uri), _path(path), _cache_header(cache_header){
|
||||||
_isFile = _fs.exists(path);
|
|
||||||
|
_isFile = _fs.exists(path) || _fs.exists((String(path)+".gz").c_str());
|
||||||
if (_uri != "/" && _uri.endsWith("/")) {
|
if (_uri != "/" && _uri.endsWith("/")) {
|
||||||
_uri = _uri.substring(0, _uri.length() - 1);
|
_uri = _uri.substring(0, _uri.length() - 1);
|
||||||
//os_printf("[AsyncStaticWebHandler] _uri / removed");
|
//os_printf("[AsyncStaticWebHandler] _uri / removed");
|
||||||
|
@@ -57,6 +57,17 @@ class AsyncCallbackResponse: public AsyncAbstractResponse {
|
|||||||
size_t _fillBuffer(uint8_t *buf, size_t maxLen);
|
size_t _fillBuffer(uint8_t *buf, size_t maxLen);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class AsyncChunkedResponse: public AsyncAbstractResponse {
|
||||||
|
private:
|
||||||
|
AwsResponseFiller _content;
|
||||||
|
public:
|
||||||
|
AsyncChunkedResponse(String contentType, AwsResponseFiller callback);
|
||||||
|
bool _sourceValid(){ return !!(_content); }
|
||||||
|
size_t _fillBuffer(uint8_t *buf, size_t maxLen);
|
||||||
|
};
|
||||||
|
|
||||||
|
class cbuf;
|
||||||
|
|
||||||
class AsyncResponseStream: public AsyncAbstractResponse, public Print {
|
class AsyncResponseStream: public AsyncAbstractResponse, public Print {
|
||||||
private:
|
private:
|
||||||
cbuf *_content;
|
cbuf *_content;
|
||||||
|
@@ -86,6 +86,7 @@ class AsyncWebServerRequest {
|
|||||||
String _temp;
|
String _temp;
|
||||||
uint8_t _parseState;
|
uint8_t _parseState;
|
||||||
|
|
||||||
|
uint8_t _version;
|
||||||
WebRequestMethod _method;
|
WebRequestMethod _method;
|
||||||
String _url;
|
String _url;
|
||||||
String _host;
|
String _host;
|
||||||
@@ -142,6 +143,7 @@ class AsyncWebServerRequest {
|
|||||||
~AsyncWebServerRequest();
|
~AsyncWebServerRequest();
|
||||||
|
|
||||||
AsyncClient* client(){ return _client; }
|
AsyncClient* client(){ return _client; }
|
||||||
|
uint8_t version(){ return _version; }
|
||||||
WebRequestMethod method(){ return _method; }
|
WebRequestMethod method(){ return _method; }
|
||||||
String url(){ return _url; }
|
String url(){ return _url; }
|
||||||
String host(){ return _host; }
|
String host(){ return _host; }
|
||||||
@@ -161,11 +163,13 @@ class AsyncWebServerRequest {
|
|||||||
void send(FS &fs, String path, String contentType=String(), bool download=false);
|
void send(FS &fs, String path, String contentType=String(), bool download=false);
|
||||||
void send(Stream &stream, String contentType, size_t len);
|
void send(Stream &stream, String contentType, size_t len);
|
||||||
void send(String contentType, size_t len, AwsResponseFiller callback);
|
void send(String contentType, size_t len, AwsResponseFiller callback);
|
||||||
|
void sendChunked(String contentType, AwsResponseFiller callback);
|
||||||
|
|
||||||
AsyncWebServerResponse *beginResponse(int code, String contentType=String(), String content=String());
|
AsyncWebServerResponse *beginResponse(int code, String contentType=String(), String content=String());
|
||||||
AsyncWebServerResponse *beginResponse(FS &fs, String path, String contentType=String(), bool download=false);
|
AsyncWebServerResponse *beginResponse(FS &fs, String path, String contentType=String(), bool download=false);
|
||||||
AsyncWebServerResponse *beginResponse(Stream &stream, String contentType, size_t len);
|
AsyncWebServerResponse *beginResponse(Stream &stream, String contentType, size_t len);
|
||||||
AsyncWebServerResponse *beginResponse(String contentType, size_t len, AwsResponseFiller callback);
|
AsyncWebServerResponse *beginResponse(String contentType, size_t len, AwsResponseFiller callback);
|
||||||
|
AsyncWebServerResponse *beginChunkedResponse(String contentType, AwsResponseFiller callback);
|
||||||
AsyncResponseStream *beginResponseStream(String contentType, size_t len, size_t bufferSize=1460);
|
AsyncResponseStream *beginResponseStream(String contentType, size_t len, size_t bufferSize=1460);
|
||||||
|
|
||||||
int headers(); // get header count
|
int headers(); // get header count
|
||||||
@@ -221,6 +225,8 @@ class AsyncWebServerResponse {
|
|||||||
AsyncWebHeader *_headers;
|
AsyncWebHeader *_headers;
|
||||||
String _contentType;
|
String _contentType;
|
||||||
size_t _contentLength;
|
size_t _contentLength;
|
||||||
|
bool _sendContentLength;
|
||||||
|
bool _chunked;
|
||||||
size_t _headLength;
|
size_t _headLength;
|
||||||
size_t _sentLength;
|
size_t _sentLength;
|
||||||
size_t _ackedLength;
|
size_t _ackedLength;
|
||||||
@@ -230,8 +236,10 @@ class AsyncWebServerResponse {
|
|||||||
public:
|
public:
|
||||||
AsyncWebServerResponse();
|
AsyncWebServerResponse();
|
||||||
virtual ~AsyncWebServerResponse();
|
virtual ~AsyncWebServerResponse();
|
||||||
|
virtual void setContentLength(size_t len);
|
||||||
|
virtual void setContentType(String type);
|
||||||
virtual void addHeader(String name, String value);
|
virtual void addHeader(String name, String value);
|
||||||
virtual String _assembleHead();
|
virtual String _assembleHead(uint8_t version);
|
||||||
virtual bool _finished();
|
virtual bool _finished();
|
||||||
virtual bool _failed();
|
virtual bool _failed();
|
||||||
virtual void _respond(AsyncWebServerRequest *request);
|
virtual void _respond(AsyncWebServerRequest *request);
|
||||||
|
@@ -9,7 +9,7 @@
|
|||||||
#define STRINGARRAY_H_
|
#define STRINGARRAY_H_
|
||||||
|
|
||||||
#include "stddef.h"
|
#include "stddef.h"
|
||||||
#include "String.h"
|
#include "WString.h"
|
||||||
|
|
||||||
class StringArrayItem;
|
class StringArrayItem;
|
||||||
class StringArrayItem {
|
class StringArrayItem {
|
||||||
|
@@ -2,7 +2,6 @@
|
|||||||
#include "AsyncWebServerResponseImpl.h"
|
#include "AsyncWebServerResponseImpl.h"
|
||||||
#include "cbuf.h"
|
#include "cbuf.h"
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Abstract Response
|
* Abstract Response
|
||||||
* */
|
* */
|
||||||
@@ -53,14 +52,16 @@ const char* AsyncWebServerResponse::_responseCodeToString(int code) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
AsyncWebServerResponse::AsyncWebServerResponse()
|
AsyncWebServerResponse::AsyncWebServerResponse()
|
||||||
:_code(0)
|
: _code(0)
|
||||||
,_headers(NULL)
|
, _headers(NULL)
|
||||||
,_contentType()
|
, _contentType()
|
||||||
,_contentLength(0)
|
, _contentLength(0)
|
||||||
,_headLength(0)
|
, _sendContentLength(true)
|
||||||
,_sentLength(0)
|
, _chunked(false)
|
||||||
,_ackedLength(0)
|
, _headLength(0)
|
||||||
,_state(RESPONSE_SETUP)
|
, _sentLength(0)
|
||||||
|
, _ackedLength(0)
|
||||||
|
, _state(RESPONSE_SETUP)
|
||||||
{
|
{
|
||||||
addHeader("Connection","close");
|
addHeader("Connection","close");
|
||||||
addHeader("Access-Control-Allow-Origin","*");
|
addHeader("Access-Control-Allow-Origin","*");
|
||||||
@@ -74,6 +75,16 @@ AsyncWebServerResponse::~AsyncWebServerResponse(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AsyncWebServerResponse::setContentLength(size_t len){
|
||||||
|
if(_state == RESPONSE_SETUP)
|
||||||
|
_contentLength = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServerResponse::setContentType(String type){
|
||||||
|
if(_state == RESPONSE_SETUP)
|
||||||
|
_contentType = type;
|
||||||
|
}
|
||||||
|
|
||||||
void AsyncWebServerResponse::addHeader(String name, String value){
|
void AsyncWebServerResponse::addHeader(String name, String value){
|
||||||
AsyncWebHeader *header = new AsyncWebHeader(name, value);
|
AsyncWebHeader *header = new AsyncWebHeader(name, value);
|
||||||
if(_headers == NULL){
|
if(_headers == NULL){
|
||||||
@@ -85,12 +96,19 @@ void AsyncWebServerResponse::addHeader(String name, String value){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String AsyncWebServerResponse::_assembleHead(){
|
String AsyncWebServerResponse::_assembleHead(uint8_t version){
|
||||||
String out = "HTTP/1.1 " + String(_code) + " " + _responseCodeToString(_code) + "\r\n";
|
if(version){
|
||||||
out += "Content-Length: " + String(_contentLength) + "\r\n";
|
addHeader("Accept-Ranges","none");
|
||||||
if(_contentType.length()){
|
if(_chunked)
|
||||||
out += "Content-Type: " + _contentType + "\r\n";
|
addHeader("Transfer-Encoding","chunked");
|
||||||
}
|
}
|
||||||
|
String out = "HTTP/1." + String(version) + " " + String(_code) + " " + _responseCodeToString(_code) + "\r\n";
|
||||||
|
if(_sendContentLength)
|
||||||
|
out += "Content-Length: " + String(_contentLength) + "\r\n";
|
||||||
|
|
||||||
|
if(_contentType.length())
|
||||||
|
out += "Content-Type: " + _contentType + "\r\n";
|
||||||
|
|
||||||
AsyncWebHeader *h;
|
AsyncWebHeader *h;
|
||||||
while(_headers != NULL){
|
while(_headers != NULL){
|
||||||
h = _headers;
|
h = _headers;
|
||||||
@@ -124,7 +142,7 @@ AsyncBasicResponse::AsyncBasicResponse(int code, String contentType, String cont
|
|||||||
|
|
||||||
void AsyncBasicResponse::_respond(AsyncWebServerRequest *request){
|
void AsyncBasicResponse::_respond(AsyncWebServerRequest *request){
|
||||||
_state = RESPONSE_HEADERS;
|
_state = RESPONSE_HEADERS;
|
||||||
String out = _assembleHead();
|
String out = _assembleHead(request->version());
|
||||||
size_t outLen = out.length();
|
size_t outLen = out.length();
|
||||||
size_t space = request->client()->space();
|
size_t space = request->client()->space();
|
||||||
if(!_contentLength && space >= outLen){
|
if(!_contentLength && space >= outLen){
|
||||||
@@ -193,7 +211,7 @@ void AsyncAbstractResponse::_respond(AsyncWebServerRequest *request){
|
|||||||
request->send(500);
|
request->send(500);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_head = _assembleHead();
|
_head = _assembleHead(request->version());
|
||||||
_state = RESPONSE_HEADERS;
|
_state = RESPONSE_HEADERS;
|
||||||
size_t outLen = _head.length();
|
size_t outLen = _head.length();
|
||||||
size_t space = request->client()->space();
|
size_t space = request->client()->space();
|
||||||
@@ -218,18 +236,42 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
|
|||||||
_ackedLength += len;
|
_ackedLength += len;
|
||||||
size_t space = request->client()->space();
|
size_t space = request->client()->space();
|
||||||
if(_state == RESPONSE_CONTENT){
|
if(_state == RESPONSE_CONTENT){
|
||||||
size_t remaining = _contentLength - _sentLength;
|
size_t outLen;
|
||||||
size_t outLen = (remaining > space)?space:remaining;
|
size_t readLen = 0;
|
||||||
|
|
||||||
|
if(_chunked || !_sendContentLength){
|
||||||
|
outLen = space;
|
||||||
|
} else {
|
||||||
|
size_t remaining = _contentLength - _sentLength;
|
||||||
|
outLen = (remaining > space)?space:remaining;
|
||||||
|
}
|
||||||
uint8_t *buf = (uint8_t *)malloc(outLen);
|
uint8_t *buf = (uint8_t *)malloc(outLen);
|
||||||
outLen = _fillBuffer(buf, outLen);
|
|
||||||
|
if(_chunked){
|
||||||
|
readLen = _fillBuffer(buf, outLen - 8);
|
||||||
|
char pre[6];
|
||||||
|
sprintf(pre, "%x\r\n", readLen);
|
||||||
|
size_t preLen = strlen(pre);
|
||||||
|
memmove(buf+preLen, buf, preLen);
|
||||||
|
for(size_t i=0; i<preLen; i++)
|
||||||
|
buf[i] = pre[i];
|
||||||
|
outLen = preLen + readLen;
|
||||||
|
buf[outLen++] = '\r';
|
||||||
|
buf[outLen++] = '\n';
|
||||||
|
} else {
|
||||||
|
outLen = _fillBuffer(buf, outLen);
|
||||||
|
}
|
||||||
|
|
||||||
if(outLen)
|
if(outLen)
|
||||||
request->client()->write((const char*)buf, outLen);
|
outLen = request->client()->write((const char*)buf, outLen);
|
||||||
_sentLength += outLen;
|
_sentLength += outLen;
|
||||||
free(buf);
|
free(buf);
|
||||||
if(_sentLength == _contentLength){
|
|
||||||
|
if((_chunked && readLen == 0) || (!_sendContentLength && outLen == 0) || _sentLength == _contentLength){
|
||||||
_state = RESPONSE_WAIT_ACK;
|
_state = RESPONSE_WAIT_ACK;
|
||||||
}
|
}
|
||||||
return outLen;
|
return outLen;
|
||||||
|
|
||||||
} else if(_state == RESPONSE_HEADERS){
|
} else if(_state == RESPONSE_HEADERS){
|
||||||
size_t outLen = _head.length();
|
size_t outLen = _head.length();
|
||||||
if(space >= outLen){
|
if(space >= outLen){
|
||||||
@@ -244,8 +286,10 @@ size_t AsyncAbstractResponse::_ack(AsyncWebServerRequest *request, size_t len, u
|
|||||||
return out.length();
|
return out.length();
|
||||||
}
|
}
|
||||||
} else if(_state == RESPONSE_WAIT_ACK){
|
} else if(_state == RESPONSE_WAIT_ACK){
|
||||||
if(_ackedLength >= (_headLength+_contentLength)){
|
if(!_sendContentLength || _ackedLength >= (_headLength+_contentLength)){
|
||||||
_state = RESPONSE_END;
|
_state = RESPONSE_END;
|
||||||
|
if(!_chunked && !_sendContentLength)
|
||||||
|
request->client()->close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -330,6 +374,8 @@ AsyncCallbackResponse::AsyncCallbackResponse(String contentType, size_t len, Aws
|
|||||||
_code = 200;
|
_code = 200;
|
||||||
_content = callback;
|
_content = callback;
|
||||||
_contentLength = len;
|
_contentLength = len;
|
||||||
|
if(!len)
|
||||||
|
_sendContentLength = false;
|
||||||
_contentType = contentType;
|
_contentType = contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,6 +383,23 @@ size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
|
|||||||
return _content(data, len);
|
return _content(data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Chunked Response
|
||||||
|
* */
|
||||||
|
|
||||||
|
AsyncChunkedResponse::AsyncChunkedResponse(String contentType, AwsResponseFiller callback){
|
||||||
|
_code = 200;
|
||||||
|
_content = callback;
|
||||||
|
_contentLength = 0;
|
||||||
|
_contentType = contentType;
|
||||||
|
_sendContentLength = false;
|
||||||
|
_chunked = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t AsyncChunkedResponse::_fillBuffer(uint8_t *data, size_t len){
|
||||||
|
return _content(data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Response Stream (You can print/write/printf to it, up to the contentLen bytes)
|
* Response Stream (You can print/write/printf to it, up to the contentLen bytes)
|
||||||
@@ -345,6 +408,8 @@ size_t AsyncCallbackResponse::_fillBuffer(uint8_t *data, size_t len){
|
|||||||
AsyncResponseStream::AsyncResponseStream(String contentType, size_t len, size_t bufferSize){
|
AsyncResponseStream::AsyncResponseStream(String contentType, size_t len, size_t bufferSize){
|
||||||
_code = 200;
|
_code = 200;
|
||||||
_contentLength = len;
|
_contentLength = len;
|
||||||
|
if(!len)
|
||||||
|
_sendContentLength = false;
|
||||||
_contentType = contentType;
|
_contentType = contentType;
|
||||||
_content = new cbuf(bufferSize);
|
_content = new cbuf(bufferSize);
|
||||||
}
|
}
|
||||||
@@ -358,16 +423,15 @@ size_t AsyncResponseStream::_fillBuffer(uint8_t *buf, size_t maxLen){
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncResponseStream::write(const uint8_t *data, size_t len){
|
size_t AsyncResponseStream::write(const uint8_t *data, size_t len){
|
||||||
if(_finished())
|
if(_finished() || (_content->room() == 0 && ETS_INTR_WITHINISR()))
|
||||||
return 0;
|
return 0;
|
||||||
//while(_content->room() < len) delay(1);
|
if(len > _content->available())
|
||||||
|
len = _content->available();
|
||||||
|
while(_content->room() < len) delay(0);
|
||||||
return _content->write((const char*)data, len);
|
return _content->write((const char*)data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AsyncResponseStream::write(uint8_t data){
|
size_t AsyncResponseStream::write(uint8_t data){
|
||||||
if(_finished())
|
|
||||||
return 0;
|
|
||||||
//while(_content->room() == 0) delay(1);
|
|
||||||
return write(&data, 1);
|
return write(&data, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -9,6 +9,10 @@
|
|||||||
#include "AsyncWebServerResponseImpl.h"
|
#include "AsyncWebServerResponseImpl.h"
|
||||||
#include <libb64/cencode.h>
|
#include <libb64/cencode.h>
|
||||||
|
|
||||||
|
#ifndef ESP8266
|
||||||
|
#define os_strlen strlen
|
||||||
|
#endif
|
||||||
|
|
||||||
#define __is_param_char(c) ((c) && ((c) != '{') && ((c) != '[') && ((c) != '&') && ((c) != '='))
|
#define __is_param_char(c) ((c) && ((c) != '{') && ((c) != '[') && ((c) != '&') && ((c) != '='))
|
||||||
|
|
||||||
enum { PARSE_REQ_START, PARSE_REQ_HEADERS, PARSE_REQ_BODY, PARSE_REQ_END, PARSE_REQ_FAIL };
|
enum { PARSE_REQ_START, PARSE_REQ_HEADERS, PARSE_REQ_BODY, PARSE_REQ_END, PARSE_REQ_FAIL };
|
||||||
@@ -21,6 +25,7 @@ AsyncWebServerRequest::AsyncWebServerRequest(AsyncWebServer* s, AsyncClient* c)
|
|||||||
, _interestingHeaders(new StringArray())
|
, _interestingHeaders(new StringArray())
|
||||||
, _temp()
|
, _temp()
|
||||||
, _parseState(0)
|
, _parseState(0)
|
||||||
|
, _version(0)
|
||||||
, _method(HTTP_ANY)
|
, _method(HTTP_ANY)
|
||||||
, _url()
|
, _url()
|
||||||
, _host()
|
, _host()
|
||||||
@@ -147,11 +152,12 @@ void AsyncWebServerRequest::_onAck(size_t len, uint32_t time){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebServerRequest::_onError(int8_t error){
|
void AsyncWebServerRequest::_onError(int8_t error){
|
||||||
//os_printf("e:%d:%u\n", error, _client->state());
|
if(error != -11)
|
||||||
|
os_printf("ERROR[%d] %s, state: %s\n", error, _client->errorToString(error), _client->stateToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebServerRequest::_onTimeout(uint32_t time){
|
void AsyncWebServerRequest::_onTimeout(uint32_t time){
|
||||||
//os_printf("t:%u\n", time);
|
os_printf("TIMEOUT: %u, state: %s\n", time, _client->stateToString());
|
||||||
_client->close();
|
_client->close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +230,9 @@ bool AsyncWebServerRequest::_parseReqHead(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_temp = _temp.substring(_temp.indexOf(' ')+1);
|
||||||
|
if(_temp.startsWith("HTTP/1.1"))
|
||||||
|
_version = 1;
|
||||||
_temp = String();
|
_temp = String();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -615,32 +624,42 @@ AsyncWebServerResponse * AsyncWebServerRequest::beginResponse(String contentType
|
|||||||
return new AsyncCallbackResponse(contentType, len, callback);
|
return new AsyncCallbackResponse(contentType, len, callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AsyncWebServerResponse * AsyncWebServerRequest::beginChunkedResponse(String contentType, AwsResponseFiller callback){
|
||||||
|
if(_version)
|
||||||
|
return new AsyncChunkedResponse(contentType, callback);
|
||||||
|
return new AsyncCallbackResponse(contentType, 0, callback);
|
||||||
|
}
|
||||||
|
|
||||||
AsyncResponseStream * AsyncWebServerRequest::beginResponseStream(String contentType, size_t len, size_t bufferSize){
|
AsyncResponseStream * AsyncWebServerRequest::beginResponseStream(String contentType, size_t len, size_t bufferSize){
|
||||||
return new AsyncResponseStream(contentType, len, bufferSize);
|
return new AsyncResponseStream(contentType, len, bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebServerRequest::send(int code, String contentType, String content){
|
void AsyncWebServerRequest::send(int code, String contentType, String content){
|
||||||
send(new AsyncBasicResponse(code, contentType, content));
|
send(beginResponse(code, contentType, content));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebServerRequest::send(FS &fs, String path, String contentType, bool download){
|
void AsyncWebServerRequest::send(FS &fs, String path, String contentType, bool download){
|
||||||
if(fs.exists(path) || (!download && fs.exists(path+".gz"))){
|
if(fs.exists(path) || (!download && fs.exists(path+".gz"))){
|
||||||
send(new AsyncFileResponse(fs, path, contentType, download));
|
send(beginResponse(fs, path, contentType, download));
|
||||||
} else send(404);
|
} else send(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebServerRequest::send(Stream &stream, String contentType, size_t len){
|
void AsyncWebServerRequest::send(Stream &stream, String contentType, size_t len){
|
||||||
send(new AsyncStreamResponse(stream, contentType, len));
|
send(beginResponse(stream, contentType, len));
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncWebServerRequest::send(String contentType, size_t len, AwsResponseFiller callback){
|
void AsyncWebServerRequest::send(String contentType, size_t len, AwsResponseFiller callback){
|
||||||
send(new AsyncCallbackResponse(contentType, len, callback));
|
send(beginResponse(contentType, len, callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AsyncWebServerRequest::sendChunked(String contentType, AwsResponseFiller callback){
|
||||||
|
send(beginChunkedResponse(contentType, callback));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool AsyncWebServerRequest::authenticate(const char * username, const char * password){
|
bool AsyncWebServerRequest::authenticate(const char * username, const char * password){
|
||||||
if(_authorization.length()){
|
if(_authorization.length()){
|
||||||
char toencodeLen = strlen(username)+strlen(password)+1;
|
char toencodeLen = os_strlen(username)+os_strlen(password)+1;
|
||||||
char *toencode = new char[toencodeLen];
|
char *toencode = new char[toencodeLen];
|
||||||
if(toencode == NULL){
|
if(toencode == NULL){
|
||||||
return false;
|
return false;
|
||||||
|
Reference in New Issue
Block a user