SDWebServer.ino 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /*
  2. SDWebServer - Example WebServer with SD Card backend for esp8266
  3. Copyright (c) 2015 Hristo Gochkov. All rights reserved.
  4. This file is part of the ESP8266WebServer library for Arduino environment.
  5. This library is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public
  7. License as published by the Free Software Foundation; either
  8. version 2.1 of the License, or (at your option) any later version.
  9. This library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public
  14. License along with this library; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. Have a FAT Formatted SD Card connected to the SPI port of the ESP8266
  17. The web root is the SD Card root folder
  18. File extensions with more than 3 charecters are not supported by the SD Library
  19. File Names longer than 8 charecters will be truncated by the SD library, so keep filenames shorter
  20. index.htm is the default index (works on subfolders as well)
  21. upload the contents of SdRoot to the root of the SDcard and access the editor by going to http://esp8266sd.local/edit
  22. */
  23. #include <ESP8266WiFi.h>
  24. #include <WiFiClient.h>
  25. #include <ESP8266WebServer.h>
  26. #include <ESP8266mDNS.h>
  27. #include <SPI.h>
  28. #include <SD.h>
  29. #define DBG_OUTPUT_PORT Serial
  30. const char* ssid = "**********";
  31. const char* password = "**********";
  32. const char* host = "esp8266sd";
  33. ESP8266WebServer server(80);
  34. static bool hasSD = false;
  35. File uploadFile;
  36. void returnOK() {
  37. server.send(200, "text/plain", "");
  38. }
  39. void returnFail(String msg) {
  40. server.send(500, "text/plain", msg + "\r\n");
  41. }
  42. bool loadFromSdCard(String path){
  43. String dataType = "text/plain";
  44. if(path.endsWith("/")) path += "index.htm";
  45. if(path.endsWith(".src")) path = path.substring(0, path.lastIndexOf("."));
  46. else if(path.endsWith(".htm")) dataType = "text/html";
  47. else if(path.endsWith(".css")) dataType = "text/css";
  48. else if(path.endsWith(".js")) dataType = "application/javascript";
  49. else if(path.endsWith(".png")) dataType = "image/png";
  50. else if(path.endsWith(".gif")) dataType = "image/gif";
  51. else if(path.endsWith(".jpg")) dataType = "image/jpeg";
  52. else if(path.endsWith(".ico")) dataType = "image/x-icon";
  53. else if(path.endsWith(".xml")) dataType = "text/xml";
  54. else if(path.endsWith(".pdf")) dataType = "application/pdf";
  55. else if(path.endsWith(".zip")) dataType = "application/zip";
  56. File dataFile = SD.open(path.c_str());
  57. if(dataFile.isDirectory()){
  58. path += "/index.htm";
  59. dataType = "text/html";
  60. dataFile = SD.open(path.c_str());
  61. }
  62. if (!dataFile)
  63. return false;
  64. if (server.hasArg("download")) dataType = "application/octet-stream";
  65. if (server.streamFile(dataFile, dataType) != dataFile.size()) {
  66. DBG_OUTPUT_PORT.println("Sent less data than expected!");
  67. }
  68. dataFile.close();
  69. return true;
  70. }
  71. void handleFileUpload(){
  72. if(server.uri() != "/edit") return;
  73. HTTPUpload& upload = server.upload();
  74. if(upload.status == UPLOAD_FILE_START){
  75. if(SD.exists((char *)upload.filename.c_str())) SD.remove((char *)upload.filename.c_str());
  76. uploadFile = SD.open(upload.filename.c_str(), FILE_WRITE);
  77. DBG_OUTPUT_PORT.print("Upload: START, filename: "); DBG_OUTPUT_PORT.println(upload.filename);
  78. } else if(upload.status == UPLOAD_FILE_WRITE){
  79. if(uploadFile) uploadFile.write(upload.buf, upload.currentSize);
  80. DBG_OUTPUT_PORT.print("Upload: WRITE, Bytes: "); DBG_OUTPUT_PORT.println(upload.currentSize);
  81. } else if(upload.status == UPLOAD_FILE_END){
  82. if(uploadFile) uploadFile.close();
  83. DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
  84. }
  85. }
  86. void deleteRecursive(String path){
  87. File file = SD.open((char *)path.c_str());
  88. if(!file.isDirectory()){
  89. file.close();
  90. SD.remove((char *)path.c_str());
  91. return;
  92. }
  93. file.rewindDirectory();
  94. while(true) {
  95. File entry = file.openNextFile();
  96. if (!entry) break;
  97. String entryPath = path + "/" +entry.name();
  98. if(entry.isDirectory()){
  99. entry.close();
  100. deleteRecursive(entryPath);
  101. } else {
  102. entry.close();
  103. SD.remove((char *)entryPath.c_str());
  104. }
  105. yield();
  106. }
  107. SD.rmdir((char *)path.c_str());
  108. file.close();
  109. }
  110. void handleDelete(){
  111. if(server.args() == 0) return returnFail("BAD ARGS");
  112. String path = server.arg(0);
  113. if(path == "/" || !SD.exists((char *)path.c_str())) {
  114. returnFail("BAD PATH");
  115. return;
  116. }
  117. deleteRecursive(path);
  118. returnOK();
  119. }
  120. void handleCreate(){
  121. if(server.args() == 0) return returnFail("BAD ARGS");
  122. String path = server.arg(0);
  123. if(path == "/" || SD.exists((char *)path.c_str())) {
  124. returnFail("BAD PATH");
  125. return;
  126. }
  127. if(path.indexOf('.') > 0){
  128. File file = SD.open((char *)path.c_str(), FILE_WRITE);
  129. if(file){
  130. file.write((const char *)0);
  131. file.close();
  132. }
  133. } else {
  134. SD.mkdir((char *)path.c_str());
  135. }
  136. returnOK();
  137. }
  138. void printDirectory() {
  139. if(!server.hasArg("dir")) return returnFail("BAD ARGS");
  140. String path = server.arg("dir");
  141. if(path != "/" && !SD.exists((char *)path.c_str())) return returnFail("BAD PATH");
  142. File dir = SD.open((char *)path.c_str());
  143. path = String();
  144. if(!dir.isDirectory()){
  145. dir.close();
  146. return returnFail("NOT DIR");
  147. }
  148. dir.rewindDirectory();
  149. server.setContentLength(CONTENT_LENGTH_UNKNOWN);
  150. server.send(200, "text/json", "");
  151. WiFiClient client = server.client();
  152. server.sendContent("[");
  153. for (int cnt = 0; true; ++cnt) {
  154. File entry = dir.openNextFile();
  155. if (!entry)
  156. break;
  157. String output;
  158. if (cnt > 0)
  159. output = ',';
  160. output += "{\"type\":\"";
  161. output += (entry.isDirectory()) ? "dir" : "file";
  162. output += "\",\"name\":\"";
  163. output += entry.name();
  164. output += "\"";
  165. output += "}";
  166. server.sendContent(output);
  167. entry.close();
  168. }
  169. server.sendContent("]");
  170. dir.close();
  171. }
  172. void handleNotFound(){
  173. if(hasSD && loadFromSdCard(server.uri())) return;
  174. String message = "SDCARD Not Detected\n\n";
  175. message += "URI: ";
  176. message += server.uri();
  177. message += "\nMethod: ";
  178. message += (server.method() == HTTP_GET)?"GET":"POST";
  179. message += "\nArguments: ";
  180. message += server.args();
  181. message += "\n";
  182. for (uint8_t i=0; i<server.args(); i++){
  183. message += " NAME:"+server.argName(i) + "\n VALUE:" + server.arg(i) + "\n";
  184. }
  185. server.send(404, "text/plain", message);
  186. DBG_OUTPUT_PORT.print(message);
  187. }
  188. void setup(void){
  189. DBG_OUTPUT_PORT.begin(115200);
  190. DBG_OUTPUT_PORT.setDebugOutput(true);
  191. DBG_OUTPUT_PORT.print("\n");
  192. WiFi.begin(ssid, password);
  193. DBG_OUTPUT_PORT.print("Connecting to ");
  194. DBG_OUTPUT_PORT.println(ssid);
  195. // Wait for connection
  196. uint8_t i = 0;
  197. while (WiFi.status() != WL_CONNECTED && i++ < 20) {//wait 10 seconds
  198. delay(500);
  199. }
  200. if(i == 21){
  201. DBG_OUTPUT_PORT.print("Could not connect to");
  202. DBG_OUTPUT_PORT.println(ssid);
  203. while(1) delay(500);
  204. }
  205. DBG_OUTPUT_PORT.print("Connected! IP address: ");
  206. DBG_OUTPUT_PORT.println(WiFi.localIP());
  207. if (MDNS.begin(host)) {
  208. MDNS.addService("http", "tcp", 80);
  209. DBG_OUTPUT_PORT.println("MDNS responder started");
  210. DBG_OUTPUT_PORT.print("You can now connect to http://");
  211. DBG_OUTPUT_PORT.print(host);
  212. DBG_OUTPUT_PORT.println(".local");
  213. }
  214. server.on("/list", HTTP_GET, printDirectory);
  215. server.on("/edit", HTTP_DELETE, handleDelete);
  216. server.on("/edit", HTTP_PUT, handleCreate);
  217. server.on("/edit", HTTP_POST, [](){ returnOK(); }, handleFileUpload);
  218. server.onNotFound(handleNotFound);
  219. server.begin();
  220. DBG_OUTPUT_PORT.println("HTTP server started");
  221. if (SD.begin(SS)){
  222. DBG_OUTPUT_PORT.println("SD Card initialized.");
  223. hasSD = true;
  224. }
  225. }
  226. void loop(void){
  227. server.handleClient();
  228. }