1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-07-27 18:02:17 +03:00

Merge branch 'esp8266' of https://github.com/ficeto/Arduino into esp8266

Conflicts:
	hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino
This commit is contained in:
Ivan Grokhotkov
2015-05-12 18:58:10 +03:00
43 changed files with 1529 additions and 3864 deletions

View File

@ -23,8 +23,10 @@
File extensions with more than 3 charecters are not supported by the SD Library
File Names longer than 8 charecters will be truncated by the SD library, so keep filenames shorter
index.htm is the default index (works on subfolders as well)
*/
upload the contents of SdRoot to the root of the SDcard and access the editor by going to http://esp8266sd.local/edit
*/
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
@ -32,8 +34,8 @@
#include <SPI.h>
#include <SD.h>
//do not go larger than 1460 bytes as that is the maximum that could fit in a packet
#define WWW_BUF_SIZE 1460
#define DBG_OUTPUT_PORT Serial
const char* ssid = "**********";
const char* password = "**********";
@ -43,13 +45,38 @@ MDNSResponder mdns;
ESP8266WebServer server(80);
static bool hasSD = false;
File uploadFile;
void returnOK(){
WiFiClient client = server.client();
String message = "HTTP/1.1 200 OK\r\n";
message += "Content-Type: text/plain\r\n";
message += "Connection: close\r\n";
message += "Access-Control-Allow-Origin: *\r\n";
message += "\r\n";
client.print(message);
message = 0;
client.stop();
}
void returnFail(String msg){
WiFiClient client = server.client();
String message = "HTTP/1.1 500 Fail\r\n";
message += "Content-Type: text/plain\r\n";
message += "Connection: close\r\n";
message += "Access-Control-Allow-Origin: *\r\n";
message += "\r\n";
message += msg;
message += "\r\n";
client.print(message);
message = 0;
client.stop();
}
bool loadFromSdCard(String path){
String dataType = "text/plain";
//handle default index
if(path.endsWith("/")) path += "index.htm";
//set proper Content-Type for the most common extensions
if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
else if(path.endsWith(".htm")) dataType = "text/html";
else if(path.endsWith(".css")) dataType = "text/css";
@ -62,99 +89,224 @@ bool loadFromSdCard(String path){
else if(path.endsWith(".pdf")) dataType = "application/pdf";
else if(path.endsWith(".zip")) dataType = "application/zip";
//Try to open the file
File dataFile = SD.open(path.c_str());
//if it's a folder, try to open the default index
if(dataFile && dataFile.isDirectory()){
if(dataFile.isDirectory()){
path += "/index.htm";
dataType = "text/html";
dataFile = SD.open(path.c_str());
}
//and finally if the file exists, stream the content to the client
if(server.hasArg("download")) dataType = "application/octet-stream";
if (dataFile) {
WiFiClient client = server.client();
//send the file headers
String head = "HTTP/1.1 200 OK\r\nContent-Type: ";
head += dataType;
head += "\r\nContent-Length: ";
head += dataFile.size();
head += "\r\nConnection: close";
head += "\r\nAccess-Control-Allow-Origin: *";
head += "\r\n\r\n";
client.print(head);
dataType = 0;
path = 0;
//partition the data packets to fit in a TCP packet (1460 bytes MAX)
uint8_t obuf[WWW_BUF_SIZE];
while (dataFile.available() > WWW_BUF_SIZE){
dataFile.read(obuf, WWW_BUF_SIZE);
client.write(obuf, WWW_BUF_SIZE);
if(client.write(obuf, WWW_BUF_SIZE) != WWW_BUF_SIZE){
DBG_OUTPUT_PORT.println("Sent less data than expected!");
dataFile.close();
return true;
}
}
//stream the last data left (size is at most WWW_BUF_SIZE bytes)
uint16_t leftLen = dataFile.available();
dataFile.read(obuf, leftLen);
client.write(obuf, leftLen);
if(client.write(obuf, leftLen) != leftLen){
DBG_OUTPUT_PORT.println("Sent less data than expected!");
dataFile.close();
return true;
}
dataFile.close();
client.stop();
return true;
}
return false;
}
void tryLoadFromSdCard(){
String message = "FileNotFound\n\n";
if(hasSD){
//try to load the URL from SD Card
if(loadFromSdCard(server.uri())) return;
void handleFileUpload(){
if(server.uri() != "/edit") return;
HTTPUpload upload = server.upload();
if(upload.status == UPLOAD_FILE_START){
if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str());
uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename);
} else if(upload.status == UPLOAD_FILE_WRITE){
if(uploadFile) uploadFile.write(upload.buf, upload.buflen);
DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.buflen);
} else if(upload.status == UPLOAD_FILE_END){
if(uploadFile) uploadFile.close();
DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.size);
}
}
void deleteRecursive(String path){
File file = SD.open((char *)path.c_str());
if(!file.isDirectory()){
file.close();
SD.remove((char *)path.c_str());
return;
}
file.rewindDirectory();
File entry;
String entryPath;
while(true) {
entry = file.openNextFile();
if (!entry) break;
entryPath = path + "/" +entry.name();
if(entry.isDirectory()){
entry.close();
deleteRecursive(entryPath);
} else {
entry.close();
SD.remove((char *)entryPath.c_str());
}
entryPath = 0;
yield();
}
SD.rmdir((char *)path.c_str());
path = 0;
file.close();
}
void handleDelete(){
if(server.args() == 0) return returnFail("BAD ARGS");
String path = server.arg(0);
if(path == "/" || !SD.exists((char *)path.c_str())) return returnFail("BAD PATH");
deleteRecursive(path);
returnOK();
path = 0;
}
void handleCreate(){
if(server.args() == 0) return returnFail("BAD ARGS");
String path = server.arg(0);
if(path == "/" || SD.exists((char *)path.c_str())) return returnFail("BAD PATH");
if(path.indexOf('.') > 0){
File file = SD.open((char *)path.c_str(), FILE_WRITE);
if(file){
file.write((const char *)0);
file.close();
}
} else {
message = "SDCARD Not Detected\n\n";
SD.mkdir((char *)path.c_str());
}
returnOK();
path = 0;
}
void printDirectory() {
if(!server.hasArg("dir")) return returnFail("BAD ARGS");
String path = server.arg("dir");
if(path != "/" && !SD.exists((char *)path.c_str())) return returnFail("BAD PATH");
File dir = SD.open((char *)path.c_str());
path = 0;
if(!dir.isDirectory()){
dir.close();
return returnFail("NOT DIR");
}
dir.rewindDirectory();
File entry;
WiFiClient client = server.client();
client.print("HTTP/1.1 200 OK\r\nContent-Type: text/json\r\n\r\n");
String output = "[";
while(true) {
entry = dir.openNextFile();
if (!entry) break;
if(output != "[") output += ',';
output += "{\"type\":\"";
output += (entry.isDirectory())?"dir":"file";
output += "\",\"name\":\"";
output += entry.name();
output += "\"";
output += "}";
entry.close();
if(output.length() > 1460){
client.write(output.substring(0, 1460).c_str(), 1460);
output = output.substring(1460);
}
}
dir.close();
output += "]";
client.write(output.c_str(), output.length());
client.stop();
output = 0;
}
void handleNotFound(){
if(hasSD && loadFromSdCard(server.uri())) return;
String message = "SDCARD Not Detected\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET)?"GET":"POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i=0; i<server.args(); i++){
message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
DBG_OUTPUT_PORT.print(message);
}
void setup(void){
uint8_t i = 0;
Serial.begin(115200);
//setup WiFi
WiFi.begin(ssid, password);
Serial.print("\nConnecting to ");
Serial.println(ssid);
//wait for WiFi to connect
while (WiFi.status() != WL_CONNECTED && i++ < 20) delay(500);
//check if we have connected?
if(i == 20){
Serial.print("Could not connect to");
Serial.println(ssid);
//stop execution and wait forever
void setup(void){
DBG_OUTPUT_PORT.begin(115200);
DBG_OUTPUT_PORT.setDebugOutput(true);
DBG_OUTPUT_PORT.print("\n");
WiFi.begin(ssid, password);
DBG_OUTPUT_PORT.print("Connecting to ");
DBG_OUTPUT_PORT.println(ssid);
// Wait for connection
uint8_t i = 0;
while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
delay(500);
}
if(i == 21){
DBG_OUTPUT_PORT.print("Could not connect to");
DBG_OUTPUT_PORT.println(ssid);
while(1) delay(500);
}
Serial.print("Connected! IP address: ");
Serial.println(WiFi.localIP());
//start mDNS Server
DBG_OUTPUT_PORT.print("Connected! IP address: ");
DBG_OUTPUT_PORT.println(WiFi.localIP());
/*
if (mdns.begin(hostname, WiFi.localIP())) {
Serial.println("MDNS responder started");
Serial.print("You can now connect to http://");
Serial.print(hostname);
Serial.println(".local");
DBG_OUTPUT_PORT.println("MDNS responder started");
DBG_OUTPUT_PORT.print("You can now connect to http://");
DBG_OUTPUT_PORT.print(hostname);
DBG_OUTPUT_PORT.println(".local");
}
*/
//Attach handler
server.onNotFound(tryLoadFromSdCard);
server.on("/list", HTTP_GET, printDirectory);
server.on("/edit", HTTP_DELETE, handleDelete);
server.on("/edit", HTTP_PUT, handleCreate);
server.on("/edit", HTTP_POST, [](){ returnOK(); });
server.onNotFound(handleNotFound);
server.onFileUpload(handleFileUpload);
//start server
server.begin();
Serial.println("HTTP server started");
DBG_OUTPUT_PORT.println("HTTP server started");
//init SD Card
if (SD.begin(SS)){
Serial.println("SD Card initialized.");
DBG_OUTPUT_PORT.println("SD Card initialized.");
hasSD = true;
}
}
void loop(void){
server.handleClient();
}
}

View File

@ -0,0 +1,670 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SD Editor</title>
<style type="text/css" media="screen">
.contextMenu {
z-index: 300;
position: absolute;
left: 5px;
border: 1px solid #444;
background-color: #F5F5F5;
display: none;
box-shadow: 0 0 10px rgba( 0, 0, 0, .4 );
font-size: 12px;
font-family: sans-serif;
font-weight:bold;
}
.contextMenu ul {
list-style: none;
top: 0;
left: 0;
margin: 0;
padding: 0;
}
.contextMenu li {
position: relative;
min-width: 60px;
cursor: pointer;
}
.contextMenu span {
color: #444;
display: inline-block;
padding: 6px;
}
.contextMenu li:hover { background: #444; }
.contextMenu li:hover span { color: #EEE; }
.css-treeview ul, .css-treeview li {
padding: 0;
margin: 0;
list-style: none;
}
.css-treeview input {
position: absolute;
opacity: 0;
}
.css-treeview {
font: normal 11px Verdana, Arial, Sans-serif;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
}
.css-treeview span {
color: #00f;
cursor: pointer;
}
.css-treeview span:hover {
text-decoration: underline;
}
.css-treeview input + label + ul {
margin: 0 0 0 22px;
}
.css-treeview input ~ ul {
display: none;
}
.css-treeview label, .css-treeview label::before {
cursor: pointer;
}
.css-treeview input:disabled + label {
cursor: default;
opacity: .6;
}
.css-treeview input:checked:not(:disabled) ~ ul {
display: block;
}
.css-treeview label, .css-treeview label::before {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACgCAYAAAAFOewUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApxJREFUeNrslM1u00AQgGdthyalFFOK+ClIIKQKyqUVQvTEE3DmAhLwAhU8QZoH4A2Q2gMSFace4MCtJ8SPBFwAkRuiHKpA6sRN/Lu7zG5i14kctaUqRGhGXnu9O/Pt7MzsMiklvF+9t2kWTDvyIrAsA0aKRRi1T0C/hJ4LUbt5/8rNpWVlp8RSr9J40b48fxFaTQ9+ft8EZ6MJYb0Ok+dnYGpmPgXwKIAvLx8vYXc5GdMAQJgQEkpjRTh36TS2U+DWW/D17WuYgm8pwJyY1npZsZKOxImOV1I/h4+O6vEg5GCZBpgmA6hX8wHKUHDRBXQYicQ4rlc3Tf0VMs8DHBS864F2YFspjgUYjKX/Az3gsdQd2eeBHwmdGWXHcgBGSkZXOXohcEXebRoQcAgjqediNY+AVyu3Z3sAKqfKoGMsewBeEIOPgQxxPJIjcGH6qtL/0AdADzKGnuuD+2tLK7Q8DhHHbOBW+KEzcHLuYc82MkEUekLiwuvVH+guQBQzOG4XdAb8EOcRcqQvDkY2iCLuxECJ43JobMXoutqGgDa2T7UqLKwt9KRyuxKVByqVXXqIoCCUCAqhUOioTWC7G4TQEOD0APy2/7G2Xpu1J4+lxeQ4TXBbITDpoVelRN/BVFbwu5oMMJUBhoXy5tmdRcMwymP2OLQaLjx9/vnBo6V3K6izATmSnMa0Dq7ferIohJhr1p01zrlz49rZF4OMs8JkX23vVQzYp+wbYGV/KpXKjvspl8tsIKCrMNAYFxj2GKS5ZWxg4ewKsJfaGMIY5KXqPz8LBBj6+yDvVP79+yDp/9F9oIx3OisHWwe7Oal0HxCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwD8E/BZgAP0qhKj3rXO7AAAAAElFTkSuQmCC") no-repeat;
}
.css-treeview label, .css-treeview span, .css-treeview label::before {
display: inline-block;
height: 16px;
line-height: 16px;
vertical-align: middle;
}
.css-treeview label {
background-position: 18px 0;
}
.css-treeview label::before {
content: "";
width: 16px;
margin: 0 22px 0 0;
vertical-align: middle;
background-position: 0 -32px;
}
.css-treeview input:checked + label::before {
background-position: 0 -16px;
}
/* webkit adjacent element selector bugfix */
@media screen and (-webkit-min-device-pixel-ratio:0)
{
.css-treeview{
-webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
}
@-webkit-keyframes webkit-adjacent-element-selector-bugfix
{
from {
padding: 0;
}
to {
padding: 0;
}
}
}
#uploader {
position: absolute;
top: 0;
right: 0;
left: 0;
height:28px;
line-height: 24px;
padding-left: 10px;
background-color: #444;
color:#EEE;
}
#tree {
position: absolute;
top: 28px;
bottom: 0;
left: 0;
width:200px;
padding: 8px;
}
#editor, #preview {
position: absolute;
top: 28px;
right: 0;
bottom: 0;
left: 200px;
}
#preview {
background-color: #EEE;
padding:5px;
}
</style>
<script>
function createFileUploader(element, tree, editor){
var xmlHttp;
var input = document.createElement("input");
input.type = "file";
input.multiple = false;
input.name = "data";
document.getElementById(element).appendChild(input);
var path = document.createElement("input");
path.id = "upload-path";
path.type = "text";
path.name = "path";
path.defaultValue = "/";
document.getElementById(element).appendChild(path);
var button = document.createElement("button");
button.innerHTML = 'Upload';
document.getElementById(element).appendChild(button);
var mkdir = document.createElement("button");
mkdir.innerHTML = 'MkDir';
document.getElementById(element).appendChild(mkdir);
var mkfile = document.createElement("button");
mkfile.innerHTML = 'MkFile';
document.getElementById(element).appendChild(mkfile);
function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
else {
tree.refreshPath(path.value);
}
}
}
function createPath(p){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("path", p);
xmlHttp.open("PUT", "/edit");
xmlHttp.send(formData);
}
mkfile.onclick = function(e){
if(path.value.indexOf(".") === -1) return;
createPath(path.value);
editor.loadUrl(path.value);
};
mkdir.onclick = function(e){
if(path.value.length < 2) return;
var dir = path.value
if(dir.indexOf(".") !== -1){
if(dir.lastIndexOf("/") === 0) return;
dir = dir.substring(0, dir.lastIndexOf("/"));
}
createPath(dir);
};
button.onclick = function(e){
if(input.files.length === 0){
return;
}
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("data", input.files[0], path.value);
xmlHttp.open("POST", "/edit");
xmlHttp.send(formData);
}
input.onchange = function(e){
if(input.files.length === 0) return;
var filename = input.files[0].name;
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
var name = /(.*)\.[^.]+$/.exec(filename)[1];
if(typeof name !== undefined){
if(name.length > 8) name = name.substring(0, 8);
filename = name;
}
if(typeof ext !== undefined){
if(ext === "html") ext = "htm";
else if(ext === "jpeg") ext = "jpg";
filename = filename + "." + ext;
}
if(path.value === "/" || path.value.lastIndexOf("/") === 0){
path.value = "/"+filename;
} else {
path.value = path.value.substring(0, path.value.lastIndexOf("/")+1)+filename;
}
}
}
function createTree(element, editor){
var preview = document.getElementById("preview");
var treeRoot = document.createElement("div");
treeRoot.className = "css-treeview";
document.getElementById(element).appendChild(treeRoot);
function loadDownload(path){
document.getElementById('download-frame').src = path+"?download=true";
}
function loadPreview(path){
document.getElementById("editor").style.display = "none";
preview.style.display = "block";
preview.innerHTML = '<img src="'+path+'" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
}
function fillFolderMenu(el, path){
var list = document.createElement("ul");
el.appendChild(list);
var action = document.createElement("li");
list.appendChild(action);
var isChecked = document.getElementById(path).checked;
var expnd = document.createElement("li");
list.appendChild(expnd);
if(isChecked){
expnd.innerHTML = "<span>Collapse</span>";
expnd.onclick = function(e){
document.getElementById(path).checked = false;
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var refrsh = document.createElement("li");
list.appendChild(refrsh);
refrsh.innerHTML = "<span>Refresh</span>";
refrsh.onclick = function(e){
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
} else {
expnd.innerHTML = "<span>Expand</span>";
expnd.onclick = function(e){
document.getElementById(path).checked = true;
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
var upload = document.createElement("li");
list.appendChild(upload);
upload.innerHTML = "<span>Upload</span>";
upload.onclick = function(e){
var pathEl = document.getElementById("upload-path");
if(pathEl){
var subPath = pathEl.value;
if(subPath.lastIndexOf("/") < 1) pathEl.value = path+subPath;
else pathEl.value = path.substring(subPath.lastIndexOf("/"))+subPath;
}
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var delFile = document.createElement("li");
list.appendChild(delFile);
delFile.innerHTML = "<span>Delete</span>";
delFile.onclick = function(e){
httpDelete(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
function fillFileMenu(el, path){
var list = document.createElement("ul");
el.appendChild(list);
var action = document.createElement("li");
list.appendChild(action);
if(isTextFile(path)){
action.innerHTML = "<span>Edit</span>";
action.onclick = function(e){
editor.loadUrl(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
} else if(isImageFile(path)){
action.innerHTML = "<span>Preview</span>";
action.onclick = function(e){
loadPreview(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
var download = document.createElement("li");
list.appendChild(download);
download.innerHTML = "<span>Download</span>";
download.onclick = function(e){
loadDownload(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var delFile = document.createElement("li");
list.appendChild(delFile);
delFile.innerHTML = "<span>Delete</span>";
delFile.onclick = function(e){
httpDelete(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
function showContextMenu(e, path, isfile){
var divContext = document.createElement("div");
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
var left = event.clientX + scrollLeft;
var top = event.clientY + scrollTop;
divContext.className = 'contextMenu';
divContext.style.display = 'block';
divContext.style.left = left + 'px';
divContext.style.top = top + 'px';
if(isfile) fillFileMenu(divContext, path);
else fillFolderMenu(divContext, path);
document.body.appendChild(divContext);
var width = divContext.offsetWidth;
var height = divContext.offsetHeight;
divContext.onmouseout = function(e){
if(e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)){
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(divContext);
}
};
}
function createTreeLeaf(path, name, size){
var leaf = document.createElement("li");
leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
var label = document.createElement("span");
label.innerText = name.toLowerCase();
leaf.appendChild(label);
leaf.onclick = function(e){
if(isTextFile(leaf.id)){
editor.loadUrl(leaf.id);
} else if(isImageFile(leaf.id)){
loadPreview(leaf.id);
}
};
leaf.oncontextmenu = function(e){
e.preventDefault();
e.stopPropagation();
showContextMenu(e, leaf.id, true);
};
return leaf;
}
function createTreeBranch(path, name, disabled){
var leaf = document.createElement("li");
var check = document.createElement("input");
check.type = "checkbox";
check.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
if(typeof disabled !== "undefined" && disabled) check.disabled = "disabled";
leaf.appendChild(check);
var label = document.createElement("label");
label.for = check.id;
label.innerText = name.toLowerCase();
leaf.appendChild(label);
check.onchange = function(e){
if(check.checked){
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, check.id);
}
};
label.onclick = function(e){
if(!check.checked){
check.checked = true;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, check.id);
} else {
check.checked = false;
}
};
leaf.oncontextmenu = function(e){
e.preventDefault();
e.stopPropagation();
showContextMenu(e, check.id, false);
}
return leaf;
}
function addList(parent, path, items){
var list = document.createElement("ul");
parent.appendChild(list);
var ll = items.length;
for(var i = 0; i < ll; i++){
var item = items[i];
var itemEl;
if(item.type === "file"){
itemEl = createTreeLeaf(path, item.name, item.size);
} else {
itemEl = createTreeBranch(path, item.name);
}
list.appendChild(itemEl);
}
}
function isTextFile(path){
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if(typeof ext !== undefined){
switch(ext){
case "txt":
case "htm":
case "js":
case "c":
case "cpp":
case "css":
case "xml":
return true;
}
}
return false;
}
function isImageFile(path){
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if(typeof ext !== undefined){
switch(ext){
case "png":
case "jpg":
case "gif":
return true;
}
}
return false;
}
this.refreshPath = function(path){
if(path.lastIndexOf('/') < 1){
path = '/';
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
} else {
path = path.substring(0, path.lastIndexOf('/'));
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
}
};
function delCb(path){
return function(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200){
alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
} else {
if(path.lastIndexOf('/') < 1){
path = '/';
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
} else {
path = path.substring(0, path.lastIndexOf('/'));
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
}
}
}
}
}
function httpDelete(filename){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = delCb(filename);
var formData = new FormData();
formData.append("path", filename);
xmlHttp.open("DELETE", "/edit");
xmlHttp.send(formData);
}
function getCb(parent, path){
return function(){
if (xmlHttp.readyState == 4){
//clear loading
if(xmlHttp.status == 200) addList(parent, path, JSON.parse(xmlHttp.responseText));
}
}
}
function httpGet(parent, path){
xmlHttp = new XMLHttpRequest(parent, path);
xmlHttp.onreadystatechange = getCb(parent, path);
xmlHttp.open("GET", "/list?dir="+path, true);
xmlHttp.send(null);
//start loading
}
httpGet(treeRoot, "/");
return this;
}
function createEditor(element, file, lang, theme, type){
function getLangFromFilename(filename){
var lang = "plain";
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
if(typeof ext !== undefined){
switch(ext){
case "txt": lang = "plain"; break;
case "htm": lang = "html"; break;
case "js": lang = "javascript"; break;
case "c": lang = "c_cpp"; break;
case "cpp": lang = "c_cpp"; break;
case "css":
case "scss":
case "php":
case "html":
case "json":
case "xml":
lang = ext;
}
}
return lang;
}
if(typeof file === "undefined") file = "/index.htm";
if(typeof lang === "undefined"){
lang = getLangFromFilename(file);
}
if(typeof theme === "undefined") theme = "textmate";
if(typeof type === "undefined"){
type = "text/"+lang;
if(lang === "c_cpp") type = "text/plain";
}
var xmlHttp = null;
var editor = ace.edit(element);
//post
function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
}
}
function httpPost(filename, data, type){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("data", new Blob([data], { type: type }), filename);
xmlHttp.open("POST", "/edit");
xmlHttp.send(formData);
}
//get
function httpGetProcessRequest(){
if (xmlHttp.readyState == 4){
document.getElementById("preview").style.display = "none";
document.getElementById("editor").style.display = "block";
if(xmlHttp.status == 200) editor.setValue(xmlHttp.responseText);
else editor.setValue("");
editor.clearSelection();
}
}
function httpGet(theUrl){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpGetProcessRequest;
xmlHttp.open("GET", theUrl, true);
xmlHttp.send(null);
}
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
editor.setTheme("ace/theme/"+theme);
editor.$blockScrolling = Infinity;
editor.getSession().setUseSoftTabs(true);
editor.getSession().setTabSize(2);
editor.setHighlightActiveLine(true);
editor.setShowPrintMargin(false);
editor.commands.addCommand({
name: 'saveCommand',
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
exec: function(editor) {
httpPost(file, editor.getValue()+"", type);
},
readOnly: false
});
editor.commands.addCommand({
name: 'undoCommand',
bindKey: {win: 'Ctrl-Z', mac: 'Command-Z'},
exec: function(editor) {
editor.getSession().getUndoManager().undo(false);
},
readOnly: false
});
editor.commands.addCommand({
name: 'redoCommand',
bindKey: {win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z'},
exec: function(editor) {
editor.getSession().getUndoManager().redo(false);
},
readOnly: false
});
httpGet(file);
editor.loadUrl = function(filename){
file = filename;
lang = getLangFromFilename(file);
type = "text/"+lang;
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
httpGet(file);
}
return editor;
}
function onBodyLoad(){
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; });
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
var tree = createTree("tree", editor);
createFileUploader("uploader", tree, editor);
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js" type="text/javascript" charset="utf-8"></script>
</head>
<body onload="onBodyLoad();">
<div id="uploader"></div>
<div id="tree"></div>
<div id="editor"></div>
<div id="preview" style="display:none;"></div>
<iframe id=download-frame style='display:none;'></iframe>
</body>
</html>

View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
<title>ESP Index</title>
<style>
body {
background-color:black;
color:white;
}
</style>
<script type="text/javascript">
function onBodyLoad(){
console.log("we are loaded!!");
}
</script>
</head>
<body id="index" onload="onBodyLoad()">
<h1>ESP8266 Pin Functions</h1>
<img src="pins.png" />
</body>
</html>

Binary file not shown.

After

Width:  |  Height:  |  Size: 174 KiB

View File

@ -17,6 +17,7 @@
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
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
@ -25,7 +26,8 @@
#include "WiFiClient.h"
#include "ESP8266WebServer.h"
// #define DEBUG
//#define DEBUG
#define DEBUG_OUTPUT Serial1
struct ESP8266WebServer::RequestHandler {
RequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method)
@ -95,7 +97,7 @@ void ESP8266WebServer::handleClient()
}
#ifdef DEBUG
Serial.println("New client");
DEBUG_OUTPUT.println("New client");
#endif
// Wait for data from client to become available
while(client.connected() && !client.available()){
@ -106,86 +108,101 @@ void ESP8266WebServer::handleClient()
String req = client.readStringUntil('\r');
client.readStringUntil('\n');
HTTPMethod method = HTTP_GET;
if (req.startsWith("POST")) {
method = HTTP_POST;
}
// First line of HTTP request looks like "GET /path HTTP/1.1"
// Retrieve the "/path" part by finding the spaces
int addr_start = req.indexOf(' ');
int addr_end = req.indexOf(' ', addr_start + 1);
if (addr_start == -1 || addr_end == -1) {
#ifdef DEBUG
Serial.print("Invalid request: ");
Serial.println(req);
DEBUG_OUTPUT.print("Invalid request: ");
DEBUG_OUTPUT.println(req);
#endif
return;
}
req = req.substring(addr_start + 1, addr_end);
String methodStr = req.substring(0, addr_start);
String url = req.substring(addr_start + 1, addr_end);
String searchStr = "";
int hasSearch = url.indexOf('?');
if(hasSearch != -1){
searchStr = url.substring(hasSearch + 1);
url = url.substring(0, hasSearch);
}
_currentUri = url;
HTTPMethod method = HTTP_GET;
if (methodStr == "POST") {
method = HTTP_POST;
} else if (methodStr == "DELETE") {
method = HTTP_DELETE;
} else if (methodStr == "PUT") {
method = HTTP_PUT;
} else if (methodStr == "PATCH") {
method = HTTP_PATCH;
}
#ifdef DEBUG
DEBUG_OUTPUT.print("method: ");
DEBUG_OUTPUT.print(methodStr);
DEBUG_OUTPUT.print(" url: ");
DEBUG_OUTPUT.print(url);
DEBUG_OUTPUT.print(" search: ");
DEBUG_OUTPUT.println(searchStr);
#endif
String formData;
if (method == HTTP_POST) {
int contentLength = -1;
int headerCount = 0;
while(headerCount < 1024) { // there shouldn't be that much really
String line = client.readStringUntil('\r');
//bellow is needed only when POST type request
if(method == HTTP_POST || method == HTTP_PUT || method == HTTP_PATCH || method == HTTP_DELETE){
String boundaryStr;
String headerName;
String headerValue;
bool isForm = false;
uint32_t contentLength = 0;
//parse headers
while(1){
req = client.readStringUntil('\r');
client.readStringUntil('\n');
if (line.length() > 0) { // this is a header
++headerCount;
if (contentLength < 0 && line.startsWith("Content-Length")) {
// get content length from the header
int valuePos = line.indexOf(' ', 14);
if (valuePos > 0) {
String valueStr = line.substring(valuePos+1);
contentLength = valueStr.toInt();
#ifdef DEBUG
Serial.print("Content-Length: ");
Serial.println(contentLength);
#endif
}
}
}
else {
if(req == "") break;//no moar headers
int headerDiv = req.indexOf(':');
if(headerDiv == -1){
break;
}
headerName = req.substring(0, headerDiv);
headerValue = req.substring(headerDiv + 2);
if(headerName == "Content-Type"){
if(headerValue.startsWith("text/plain")){
isForm = false;
} else if(headerValue.startsWith("multipart/form-data")){
boundaryStr = headerValue.substring(headerValue.indexOf('=')+1);
isForm = true;
}
} else if(headerName == "Content-Length"){
contentLength = headerValue.toInt();
}
}
#ifdef DEBUG
Serial.print("headerCount=");
Serial.println(headerCount);
#endif
if (contentLength >= 0) {
formData = "";
int n = 0; // timeout counter
while (formData.length() < contentLength && ++n < 3)
formData += client.readString();
if(!isForm){
if(searchStr != "") searchStr += '&';
searchStr += client.readStringUntil('\r');
client.readStringUntil('\n');
}
else {
formData = client.readStringUntil('\r'); // will return after timing out once
_parseArguments(searchStr);
if(isForm){
_parseForm(client, boundaryStr, contentLength);
}
} else {
_parseArguments(searchStr);
}
else if (method == HTTP_GET) {
int args_start = req.indexOf('?');
if (args_start != -1) {
formData = req.substring(args_start + 1);
req = req.substring(0, args_start);
}
}
client.flush();
#ifdef DEBUG
Serial.print("Request: ");
Serial.println(req);
Serial.print("Args: ");
Serial.println(formData);
DEBUG_OUTPUT.print("Request: ");
DEBUG_OUTPUT.println(url);
DEBUG_OUTPUT.print(" Arguments: ");
DEBUG_OUTPUT.println(searchStr);
#endif
_parseArguments(formData);
_handleRequest(client, req, method);
_handleRequest(client, url, method);
}
void ESP8266WebServer::send(int code, const char* content_type, String content) {
@ -237,6 +254,10 @@ bool ESP8266WebServer::hasArg(const char* name) {
}
void ESP8266WebServer::_parseArguments(String data) {
#ifdef DEBUG
DEBUG_OUTPUT.print("args: ");
DEBUG_OUTPUT.println(data);
#endif
if (_currentArgs)
delete[] _currentArgs;
_currentArgs = 0;
@ -254,8 +275,8 @@ void ESP8266WebServer::_parseArguments(String data) {
++_currentArgCount;
}
#ifdef DEBUG
Serial.print("args count: ");
Serial.println(_currentArgCount);
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(_currentArgCount);
#endif
_currentArgs = new RequestArgument[_currentArgCount];
@ -265,17 +286,17 @@ void ESP8266WebServer::_parseArguments(String data) {
int equal_sign_index = data.indexOf('=', pos);
int next_arg_index = data.indexOf('&', pos);
#ifdef DEBUG
Serial.print("pos ");
Serial.print(pos);
Serial.print("=@ ");
Serial.print(equal_sign_index);
Serial.print(" &@ ");
Serial.println(next_arg_index);
DEBUG_OUTPUT.print("pos ");
DEBUG_OUTPUT.print(pos);
DEBUG_OUTPUT.print("=@ ");
DEBUG_OUTPUT.print(equal_sign_index);
DEBUG_OUTPUT.print(" &@ ");
DEBUG_OUTPUT.println(next_arg_index);
#endif
if ((equal_sign_index == -1) || ((equal_sign_index > next_arg_index) && (next_arg_index != -1))) {
#ifdef DEBUG
Serial.print("arg missing value: ");
Serial.println(iarg);
DEBUG_OUTPUT.print("arg missing value: ");
DEBUG_OUTPUT.println(iarg);
#endif
if (next_arg_index == -1)
break;
@ -286,12 +307,12 @@ void ESP8266WebServer::_parseArguments(String data) {
arg.key = data.substring(pos, equal_sign_index);
arg.value = data.substring(equal_sign_index + 1, next_arg_index);
#ifdef DEBUG
Serial.print("arg ");
Serial.print(iarg);
Serial.print(" key: ");
Serial.print(arg.key);
Serial.print(" value: ");
Serial.println(arg.value);
DEBUG_OUTPUT.print("arg ");
DEBUG_OUTPUT.print(iarg);
DEBUG_OUTPUT.print(" key: ");
DEBUG_OUTPUT.print(arg.key);
DEBUG_OUTPUT.print(" value: ");
DEBUG_OUTPUT.println(arg.value);
#endif
++iarg;
if (next_arg_index == -1)
@ -300,12 +321,234 @@ void ESP8266WebServer::_parseArguments(String data) {
}
_currentArgCount = iarg;
#ifdef DEBUG
Serial.print("args count: ");
Serial.println(_currentArgCount);
DEBUG_OUTPUT.print("args count: ");
DEBUG_OUTPUT.println(_currentArgCount);
#endif
}
void ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t len){
#ifdef DEBUG
DEBUG_OUTPUT.print("Parse Form: Boundary: ");
DEBUG_OUTPUT.print(boundary);
DEBUG_OUTPUT.print("Length: ");
DEBUG_OUTPUT.println(len);
#endif
String line;
line = client.readStringUntil('\r');
client.readStringUntil('\n');
//start reading the form
if(line == ("--"+boundary)){
RequestArgument* postArgs = new RequestArgument[32];
int postArgsLen = 0;
while(1){
String argName;
String argValue;
String argType;
String argFilename;
bool argIsFile = false;
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if(line.startsWith("Content-Disposition")){
int nameStart = line.indexOf('=');
if(nameStart != -1){
argName = line.substring(nameStart+2);
nameStart = argName.indexOf('=');
if(nameStart == -1){
argName = argName.substring(0, argName.length() - 1);
} else {
argFilename = argName.substring(nameStart+2, argName.length() - 1);
argName = argName.substring(0, argName.indexOf('"'));
argIsFile = true;
#ifdef DEBUG
DEBUG_OUTPUT.print("PostArg FileName: ");
DEBUG_OUTPUT.println(argFilename);
#endif
//use GET to set the filename if uploading using blob
if(argFilename == "blob" && hasArg("filename")) argFilename = arg("filename");
}
#ifdef DEBUG
DEBUG_OUTPUT.print("PostArg Name: ");
DEBUG_OUTPUT.println(argName);
#endif
argType = "text/plain";
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if(line.startsWith("Content-Type")){
argType = line.substring(line.indexOf(':')+2);
//skip next line
client.readStringUntil('\r');
client.readStringUntil('\n');
}
#ifdef DEBUG
DEBUG_OUTPUT.print("PostArg Type: ");
DEBUG_OUTPUT.println(argType);
#endif
if(!argIsFile){
while(1){
line = client.readStringUntil('\r');
client.readStringUntil('\n');
if(line.startsWith("--"+boundary)) break;
if(argValue.length() > 0) argValue += "\n";
argValue += line;
}
#ifdef DEBUG
DEBUG_OUTPUT.print("PostArg Value: ");
DEBUG_OUTPUT.println(argValue);
DEBUG_OUTPUT.println();
#endif
RequestArgument& arg = postArgs[postArgsLen++];
arg.key = argName;
arg.value = argValue;
if(line == ("--"+boundary+"--")){
#ifdef DEBUG
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
break;
}
} else {
_currentUpload.status = UPLOAD_FILE_START;
_currentUpload.name = argName;
_currentUpload.filename = argFilename;
_currentUpload.type = argType;
_currentUpload.size = 0;
_currentUpload.buflen = 0;
#ifdef DEBUG
DEBUG_OUTPUT.print("Start File: ");
DEBUG_OUTPUT.print(_currentUpload.filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.println(_currentUpload.type);
#endif
if(_fileUploadHandler) _fileUploadHandler();
_currentUpload.status = UPLOAD_FILE_WRITE;
uint8_t argByte = client.read();
readfile:
while(argByte != 0x0D){
_currentUpload.buf[_currentUpload.buflen++] = argByte;
if(_currentUpload.buflen == 1460){
#ifdef DEBUG
DEBUG_OUTPUT.println("Write File: 1460");
#endif
if(_fileUploadHandler) _fileUploadHandler();
_currentUpload.size += _currentUpload.buflen;
_currentUpload.buflen = 0;
}
argByte = client.read();
}
argByte = client.read();
if(argByte == 0x0A){
#ifdef DEBUG
DEBUG_OUTPUT.print("Write File: ");
DEBUG_OUTPUT.println(_currentUpload.buflen);
#endif
if(_fileUploadHandler) _fileUploadHandler();
_currentUpload.size += _currentUpload.buflen;
_currentUpload.buflen = 0;
argByte = client.read();
if((char)argByte != '-'){
//continue reading the file
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
_currentUpload.buf[_currentUpload.buflen++] = 0x0A;
goto readfile;
} else {
argByte = client.read();
if((char)argByte != '-'){
//continue reading the file
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
_currentUpload.buf[_currentUpload.buflen++] = 0x0A;
_currentUpload.buf[_currentUpload.buflen++] = (uint8_t)('-');
goto readfile;
}
}
uint8_t endBuf[boundary.length()];
client.readBytes(endBuf, boundary.length());
if(strstr((const char*)endBuf, (const char*)(boundary.c_str())) != NULL){
_currentUpload.status = UPLOAD_FILE_END;
#ifdef DEBUG
DEBUG_OUTPUT.print("End File: ");
DEBUG_OUTPUT.print(_currentUpload.filename);
DEBUG_OUTPUT.print(" Type: ");
DEBUG_OUTPUT.print(_currentUpload.type);
DEBUG_OUTPUT.print(" Size: ");
DEBUG_OUTPUT.println(_currentUpload.size);
#endif
if(_fileUploadHandler) _fileUploadHandler();
line = client.readStringUntil(0x0D);
client.readStringUntil(0x0A);
if(line == "--"){
#ifdef DEBUG
DEBUG_OUTPUT.println("Done Parsing POST");
#endif
break;
}
continue;
} else {
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
_currentUpload.buf[_currentUpload.buflen++] = 0x0A;
uint32_t i = 0;
while(i < boundary.length()){
_currentUpload.buf[_currentUpload.buflen++] = endBuf[i++];
if(_currentUpload.buflen == 1460){
#ifdef DEBUG
DEBUG_OUTPUT.println("Write File: 1460");
#endif
if(_fileUploadHandler) _fileUploadHandler();
_currentUpload.size += _currentUpload.buflen;
_currentUpload.buflen = 0;
}
}
argByte = client.read();
goto readfile;
}
} else {
_currentUpload.buf[_currentUpload.buflen++] = 0x0D;
if(_currentUpload.buflen == 1460){
#ifdef DEBUG
DEBUG_OUTPUT.println("Write File: 1460");
#endif
if(_fileUploadHandler) _fileUploadHandler();
_currentUpload.size += _currentUpload.buflen;
_currentUpload.buflen = 0;
}
goto readfile;
}
break;
}
}
}
}
int iarg;
int totalArgs = ((32 - postArgsLen) < _currentArgCount)?(32 - postArgsLen):_currentArgCount;
for (iarg = 0; iarg < totalArgs; iarg++){
RequestArgument& arg = postArgs[postArgsLen++];
arg.key = _currentArgs[iarg].key;
arg.value = _currentArgs[iarg].value;
}
if (_currentArgs) delete[] _currentArgs;
_currentArgs = new RequestArgument[postArgsLen];
for (iarg = 0; iarg < postArgsLen; iarg++){
RequestArgument& arg = _currentArgs[iarg];
arg.key = postArgs[iarg].key;
arg.value = postArgs[iarg].value;
}
_currentArgCount = iarg;
if (postArgs) delete[] postArgs;
}
}
void ESP8266WebServer::onFileUpload(THandlerFunction fn) {
_fileUploadHandler = fn;
}
void ESP8266WebServer::onNotFound(THandlerFunction fn) {
_notFoundHandler = fn;
}
@ -330,7 +573,7 @@ void ESP8266WebServer::_handleRequest(WiFiClient& client, String uri, HTTPMethod
if (!handler){
#ifdef DEBUG
Serial.println("request handler not found");
DEBUG_OUTPUT.println("request handler not found");
#endif
if(_notFoundHandler) {

View File

@ -17,6 +17,7 @@
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
Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling)
*/
@ -25,8 +26,18 @@
#include <functional>
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST };
enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE };
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END };
typedef struct {
HTTPUploadStatus status;
String filename;
String name;
String type;
size_t size;
size_t buflen;
uint8_t buf[1460];
} HTTPUpload;
class ESP8266WebServer
{
@ -42,10 +53,12 @@ public:
void on(const char* uri, THandlerFunction handler);
void on(const char* uri, HTTPMethod method, THandlerFunction fn);
void onNotFound(THandlerFunction fn); //called when handler is not assigned
void onFileUpload(THandlerFunction fn); //handle file uploads
String uri() { return _currentUri; }
HTTPMethod method() { return _currentMethod; }
WiFiClient client() { return _currentClient; }
HTTPUpload upload() { return _currentUpload; }
String arg(const char* name); // get request argument value by name
String arg(int i); // get request argument value by number
@ -64,6 +77,7 @@ protected:
void _parseArguments(String data);
static const char* _responseCodeToString(int code);
static void _appendHeader(String& response, const char* name, const char* value);
void _parseForm(WiFiClient& client, String boundary, uint32_t len);
struct RequestHandler;
struct RequestArgument {
@ -79,10 +93,12 @@ protected:
size_t _currentArgCount;
RequestArgument* _currentArgs;
HTTPUpload _currentUpload;
RequestHandler* _firstHandler;
RequestHandler* _lastHandler;
THandlerFunction _notFoundHandler;
THandlerFunction _fileUploadHandler;
};