mirror of
https://github.com/esp8266/Arduino.git
synced 2025-04-21 10:26:06 +03:00
* ficeto-esp8266: add template methods for stream to stream writes to SD and FS alignment not needed. we use fixed addresses Rework SPIFFS API to be more Arduino like fix missed edits disable automount fix SPIFFS to work pull get/set NoDelay for WiFiClient Add SPIFFS Support export sketch data folder to the build config Revert "Revert "Edit SD Server example to use the new Write(Stream) method"" add template client write Revert "Add WiFiClient.write for Stream" Revert "Edit SD Server example to use the new Write(Stream) method" Edit SD Server example to use the new Write(Stream) method Add WiFiClient.write for Stream make upload callback packets aligned to defined size Conflicts: hardware/esp8266com/esp8266/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h
283 lines
8.3 KiB
C++
283 lines
8.3 KiB
C++
/*
|
|
SDWebServer - Example WebServer with SD Card backend for esp8266
|
|
|
|
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
|
|
|
|
Have a FAT Formatted SD Card connected to the SPI port of the ESP8266
|
|
The web root is the SD Card root folder
|
|
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>
|
|
#include <ESP8266mDNS.h>
|
|
#include <SPI.h>
|
|
#include <SD.h>
|
|
|
|
#define DBG_OUTPUT_PORT Serial
|
|
|
|
const char* ssid = "**********";
|
|
const char* password = "**********";
|
|
const char* hostname = "esp8266sd";
|
|
|
|
MDNSResponder mdns;
|
|
ESP8266WebServer server(80);
|
|
|
|
static bool hasSD = false;
|
|
File uploadFile;
|
|
|
|
|
|
void returnOK() {
|
|
server.sendHeader("Connection", "close");
|
|
server.sendHeader("Access-Control-Allow-Origin", "*");
|
|
server.send(200, "text/plain", "");
|
|
}
|
|
|
|
void returnFail(String msg) {
|
|
server.sendHeader("Connection", "close");
|
|
server.sendHeader("Access-Control-Allow-Origin", "*");
|
|
server.send(500, "text/plain", msg + "\r\n");
|
|
}
|
|
|
|
bool loadFromSdCard(String path){
|
|
String dataType = "text/plain";
|
|
if(path.endsWith("/")) path += "index.htm";
|
|
|
|
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";
|
|
else if(path.endsWith(".js")) dataType = "application/javascript";
|
|
else if(path.endsWith(".png")) dataType = "image/png";
|
|
else if(path.endsWith(".gif")) dataType = "image/gif";
|
|
else if(path.endsWith(".jpg")) dataType = "image/jpeg";
|
|
else if(path.endsWith(".ico")) dataType = "image/x-icon";
|
|
else if(path.endsWith(".xml")) dataType = "text/xml";
|
|
else if(path.endsWith(".pdf")) dataType = "application/pdf";
|
|
else if(path.endsWith(".zip")) dataType = "application/zip";
|
|
|
|
File dataFile = SD.open(path.c_str());
|
|
if(dataFile.isDirectory()){
|
|
path += "/index.htm";
|
|
dataType = "text/html";
|
|
dataFile = SD.open(path.c_str());
|
|
}
|
|
|
|
if (!dataFile)
|
|
return false;
|
|
|
|
if(server.hasArg("download")) dataType = "application/octet-stream";
|
|
|
|
server.sendHeader("Content-Length", String(dataFile.size()));
|
|
server.sendHeader("Connection", "close");
|
|
server.sendHeader("Access-Control-Allow-Origin", "*");
|
|
server.send(200, dataType.c_str(), "");
|
|
|
|
WiFiClient client = server.client();
|
|
size_t totalSize = dataFile.size();
|
|
if (client.write(dataFile, HTTP_DOWNLOAD_UNIT_SIZE) != totalSize) {
|
|
DBG_OUTPUT_PORT.println("Sent less data than expected!");
|
|
}
|
|
|
|
dataFile.close();
|
|
return true;
|
|
}
|
|
|
|
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.currentSize);
|
|
DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.currentSize);
|
|
} else if(upload.status == UPLOAD_FILE_END){
|
|
if(uploadFile) uploadFile.close();
|
|
DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
|
|
}
|
|
}
|
|
|
|
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();
|
|
while(true) {
|
|
File entry = file.openNextFile();
|
|
if (!entry) break;
|
|
String entryPath = path + "/" +entry.name();
|
|
if(entry.isDirectory()){
|
|
entry.close();
|
|
deleteRecursive(entryPath);
|
|
} else {
|
|
entry.close();
|
|
SD.remove((char *)entryPath.c_str());
|
|
}
|
|
yield();
|
|
}
|
|
|
|
SD.rmdir((char *)path.c_str());
|
|
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())) {
|
|
returnFail("BAD PATH");
|
|
return;
|
|
}
|
|
deleteRecursive(path);
|
|
returnOK();
|
|
}
|
|
|
|
void handleCreate(){
|
|
if(server.args() == 0) return returnFail("BAD ARGS");
|
|
String path = server.arg(0);
|
|
if(path == "/" || SD.exists((char *)path.c_str())) {
|
|
returnFail("BAD PATH");
|
|
return;
|
|
}
|
|
|
|
if(path.indexOf('.') > 0){
|
|
File file = SD.open((char *)path.c_str(), FILE_WRITE);
|
|
if(file){
|
|
file.write((const char *)0);
|
|
file.close();
|
|
}
|
|
} else {
|
|
SD.mkdir((char *)path.c_str());
|
|
}
|
|
returnOK();
|
|
}
|
|
|
|
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 = String();
|
|
if(!dir.isDirectory()){
|
|
dir.close();
|
|
return returnFail("NOT DIR");
|
|
}
|
|
dir.rewindDirectory();
|
|
|
|
server.send(200, "text/json", "");
|
|
WiFiClient client = server.client();
|
|
|
|
for (int cnt = 0; true; ++cnt) {
|
|
File entry = dir.openNextFile();
|
|
if (!entry)
|
|
break;
|
|
|
|
String output;
|
|
if (cnt == 0)
|
|
output = '[';
|
|
else
|
|
output = ',';
|
|
|
|
output += "{\"type\":\"";
|
|
output += (entry.isDirectory()) ? "dir" : "file";
|
|
output += "\",\"name\":\"";
|
|
output += entry.name();
|
|
output += "\"";
|
|
output += "}";
|
|
server.sendContent(output);
|
|
entry.close();
|
|
}
|
|
server.sendContent("]");
|
|
dir.close();
|
|
}
|
|
|
|
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){
|
|
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);
|
|
}
|
|
DBG_OUTPUT_PORT.print("Connected! IP address: ");
|
|
DBG_OUTPUT_PORT.println(WiFi.localIP());
|
|
|
|
if (mdns.begin(hostname, WiFi.localIP())) {
|
|
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");
|
|
}
|
|
|
|
|
|
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);
|
|
|
|
server.begin();
|
|
DBG_OUTPUT_PORT.println("HTTP server started");
|
|
|
|
if (SD.begin(SS)){
|
|
DBG_OUTPUT_PORT.println("SD Card initialized.");
|
|
hasSD = true;
|
|
}
|
|
}
|
|
|
|
void loop(void){
|
|
server.handleClient();
|
|
}
|