From 36d0968ada0413dd74fc082d6aebd12e7a059ab7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 14 May 2015 13:33:12 +0300 Subject: [PATCH 1/2] Web server refactoring --- .../examples/SDWebServer/SDWebServer.ino | 160 +++---- .../ESP8266WebServer/src/ESP8266WebServer.cpp | 450 ++---------------- .../ESP8266WebServer/src/ESP8266WebServer.h | 19 +- libraries/ESP8266WebServer/src/Parsing.cpp | 428 +++++++++++++++++ libraries/ESP8266WiFi/src/WiFiClient.h | 24 + 5 files changed, 574 insertions(+), 507 deletions(-) create mode 100644 libraries/ESP8266WebServer/src/Parsing.cpp diff --git a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino index 762e4fe0d..bd8ace28a 100644 --- a/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino +++ b/libraries/ESP8266WebServer/examples/SDWebServer/SDWebServer.ino @@ -34,7 +34,6 @@ #include #include -#define WWW_BUF_SIZE 1460 #define DBG_OUTPUT_PORT Serial const char* ssid = "**********"; @@ -47,28 +46,17 @@ 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); - client.stop(); + +void returnOK() { + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(200, "text/plain", ""); } -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); - client.stop(); +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){ @@ -93,59 +81,40 @@ bool loadFromSdCard(String path){ dataType = "text/html"; dataFile = SD.open(path.c_str()); } + + if (!dataFile) + return false; if(server.hasArg("download")) dataType = "application/octet-stream"; - if (dataFile) { - WiFiClient client = server.client(); - 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 = String(); - path = String(); - - uint8_t obuf[WWW_BUF_SIZE]; - - while (dataFile.available() > WWW_BUF_SIZE){ - dataFile.read(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; - } - } - uint16_t leftLen = dataFile.available(); - dataFile.read(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; + 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, PAYLOAD_UNIT_SIZE) != totalSize) { + DBG_OUTPUT_PORT.println("Sent less data than expected!"); } - return false; + + dataFile.close(); + return true; } void handleFileUpload(){ if(server.uri() != "/edit") return; - HTTPUpload upload = server.upload(); + 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); + 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.size); + DBG_OUTPUT_PORT.print("Upload: END, Size: "); DBG_OUTPUT_PORT.println(upload.totalSize); } } @@ -156,13 +125,12 @@ void deleteRecursive(String path){ SD.remove((char *)path.c_str()); return; } + file.rewindDirectory(); - File entry; - String entryPath; while(true) { - entry = file.openNextFile(); + File entry = file.openNextFile(); if (!entry) break; - entryPath = path + "/" +entry.name(); + String entryPath = path + "/" +entry.name(); if(entry.isDirectory()){ entry.close(); deleteRecursive(entryPath); @@ -170,27 +138,32 @@ void deleteRecursive(String path){ entry.close(); SD.remove((char *)entryPath.c_str()); } - entryPath = String(); yield(); } + SD.rmdir((char *)path.c_str()); - path = String(); 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"); + if(path == "/" || !SD.exists((char *)path.c_str())) { + returnFail("BAD PATH"); + return; + } deleteRecursive(path); returnOK(); - path = String(); } 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 == "/" || 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){ @@ -201,7 +174,6 @@ void handleCreate(){ SD.mkdir((char *)path.c_str()); } returnOK(); - path = String(); } void printDirectory() { @@ -216,31 +188,31 @@ void printDirectory() { } dir.rewindDirectory(); - File entry; + server.send(200, "text/json", ""); 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); - } + + 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(); - output += "]"; - client.write(output.c_str(), output.length()); - client.stop(); - output = String(); } void handleNotFound(){ @@ -280,14 +252,14 @@ void setup(void){ } 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); @@ -304,7 +276,7 @@ void setup(void){ hasSD = true; } } - + void loop(void){ server.handleClient(); } diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp index cc4fffcce..3ca68f563 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.cpp @@ -26,8 +26,8 @@ #include "WiFiClient.h" #include "ESP8266WebServer.h" -//#define DEBUG -#define DEBUG_OUTPUT Serial1 +// #define DEBUG +#define DEBUG_OUTPUT Serial struct ESP8266WebServer::RequestHandler { RequestHandler(ESP8266WebServer::THandlerFunction fn, const char* uri, HTTPMethod method) @@ -99,110 +99,32 @@ void ESP8266WebServer::handleClient() #ifdef DEBUG DEBUG_OUTPUT.println("New client"); #endif + // Wait for data from client to become available while(client.connected() && !client.available()){ delay(1); } - // Read the first line of HTTP request - String req = client.readStringUntil('\r'); - client.readStringUntil('\n'); - - // 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 - DEBUG_OUTPUT.print("Invalid request: "); - DEBUG_OUTPUT.println(req); -#endif + if (!_parseRequest(client)) { return; } - - 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; - //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(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(); - } - } - - if(!isForm){ - if(searchStr != "") searchStr += '&'; - searchStr += client.readStringUntil('\r'); - client.readStringUntil('\n'); - } - _parseArguments(searchStr); - if(isForm){ - _parseForm(client, boundaryStr, contentLength); - } - } else { - _parseArguments(searchStr); + _currentClient = client; + _handleRequest(); +} + +void ESP8266WebServer::sendHeader(String name, String value, bool first) { + String headerLine = name; + headerLine += ": "; + headerLine += value; + headerLine += "\r\n"; + + if (first) { + _responseHeaders = headerLine + _responseHeaders; + } + else { + _responseHeaders += headerLine; } - client.flush(); - -#ifdef DEBUG - DEBUG_OUTPUT.print("Request: "); - DEBUG_OUTPUT.println(url); - DEBUG_OUTPUT.print(" Arguments: "); - DEBUG_OUTPUT.println(searchStr); -#endif - - _handleRequest(client, url, method); } void ESP8266WebServer::send(int code, const char* content_type, String content) { @@ -214,11 +136,28 @@ void ESP8266WebServer::send(int code, const char* content_type, String content) if (!content_type) content_type = "text/html"; - _appendHeader(response, "Content-Type", content_type); + sendHeader("Content-Type", content_type, true); + response += _responseHeaders; response += "\r\n"; response += content; - _currentClient.print(response); + _responseHeaders = String(); + sendContent(response); +} + +void ESP8266WebServer::sendContent(String content) { + size_t size_to_send = content.length(); + size_t size_sent = 0; + while(size_to_send) { + const size_t unit_size = PAYLOAD_UNIT_SIZE; + size_t will_send = (size_to_send < unit_size) ? size_to_send : unit_size; + size_t sent = _currentClient.write(content.c_str() + size_sent, will_send); + size_to_send -= sent; + size_sent += sent; + if (sent == 0) { + break; + } + } } String ESP8266WebServer::arg(const char* name) { @@ -253,298 +192,6 @@ bool ESP8266WebServer::hasArg(const char* name) { return false; } -void ESP8266WebServer::_parseArguments(String data) { -#ifdef DEBUG - DEBUG_OUTPUT.print("args: "); - DEBUG_OUTPUT.println(data); -#endif - if (_currentArgs) - delete[] _currentArgs; - _currentArgs = 0; - if (data.length() == 0) { - _currentArgCount = 0; - return; - } - _currentArgCount = 1; - - for (int i = 0; i < data.length(); ) { - i = data.indexOf('&', i); - if (i == -1) - break; - ++i; - ++_currentArgCount; - } -#ifdef DEBUG - DEBUG_OUTPUT.print("args count: "); - DEBUG_OUTPUT.println(_currentArgCount); -#endif - - _currentArgs = new RequestArgument[_currentArgCount]; - int pos = 0; - int iarg; - for (iarg = 0; iarg < _currentArgCount;) { - int equal_sign_index = data.indexOf('=', pos); - int next_arg_index = data.indexOf('&', pos); -#ifdef DEBUG - 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 - DEBUG_OUTPUT.print("arg missing value: "); - DEBUG_OUTPUT.println(iarg); -#endif - if (next_arg_index == -1) - break; - pos = next_arg_index + 1; - continue; - } - RequestArgument& arg = _currentArgs[iarg]; - arg.key = data.substring(pos, equal_sign_index); - arg.value = data.substring(equal_sign_index + 1, next_arg_index); -#ifdef DEBUG - 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) - break; - pos = next_arg_index + 1; - } - _currentArgCount = iarg; -#ifdef DEBUG - 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; } @@ -553,18 +200,14 @@ void ESP8266WebServer::onNotFound(THandlerFunction fn) { _notFoundHandler = fn; } -void ESP8266WebServer::_handleRequest(WiFiClient& client, String uri, HTTPMethod method) { - _currentClient = client; - _currentUri = uri; - _currentMethod = method; - +void ESP8266WebServer::_handleRequest() { RequestHandler* handler; for (handler = _firstHandler; handler; handler = handler->next) { - if (handler->method != HTTP_ANY && handler->method != method) + if (handler->method != HTTP_ANY && handler->method != _currentMethod) continue; - if (handler->uri != uri) + if (handler->uri != _currentUri) continue; handler->fn(); @@ -580,26 +223,19 @@ void ESP8266WebServer::_handleRequest(WiFiClient& client, String uri, HTTPMethod _notFoundHandler(); } else { - send(404, "text/plain", String("Not found: ") + uri); + send(404, "text/plain", String("Not found: ") + _currentUri); } } _currentClient = WiFiClient(); _currentUri = String(); - } const char* ESP8266WebServer::_responseCodeToString(int code) { switch (code) { case 200: return "OK"; case 404: return "Not found"; + case 500: return "Fail"; default: return ""; } } - -void ESP8266WebServer::_appendHeader(String& response, const char* name, const char* value) { - response += name; - response += ": "; - response += value; - response += "\r\n"; -} diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 423fc6173..e16aa571f 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -29,14 +29,17 @@ 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 }; +#define PAYLOAD_UNIT_SIZE 1460 + typedef struct { HTTPUploadStatus status; String filename; String name; String type; - size_t size; - size_t buflen; - uint8_t buf[1460]; + size_t totalSize; // file size + size_t currentSize; // size of data currently in buf + uint8_t buf[PAYLOAD_UNIT_SIZE]; + } HTTPUpload; class ESP8266WebServer @@ -58,7 +61,7 @@ public: String uri() { return _currentUri; } HTTPMethod method() { return _currentMethod; } WiFiClient client() { return _currentClient; } - HTTPUpload upload() { return _currentUpload; } + 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 @@ -72,11 +75,13 @@ public: // content - actual content body void send(int code, const char* content_type = NULL, String content = String("")); + void sendHeader(String name, String value, bool first = false); + void sendContent(String content); protected: - void _handleRequest(WiFiClient& client, String uri, HTTPMethod method); + void _handleRequest(); + bool _parseRequest(WiFiClient& client); 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; @@ -95,6 +100,8 @@ protected: RequestArgument* _currentArgs; HTTPUpload _currentUpload; + String _responseHeaders; + RequestHandler* _firstHandler; RequestHandler* _lastHandler; THandlerFunction _notFoundHandler; diff --git a/libraries/ESP8266WebServer/src/Parsing.cpp b/libraries/ESP8266WebServer/src/Parsing.cpp new file mode 100644 index 000000000..6c2bd5d22 --- /dev/null +++ b/libraries/ESP8266WebServer/src/Parsing.cpp @@ -0,0 +1,428 @@ +/* + Parsing.cpp - HTTP request parsing. + + Copyright (c) 2015 Ivan Grokhotkov. All rights reserved. + + 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 + Modified 8 May 2015 by Hristo Gochkov (proper post and file upload handling) +*/ + +#include +#include "WiFiServer.h" +#include "WiFiClient.h" +#include "ESP8266WebServer.h" + +// #define DEBUG +#define DEBUG_OUTPUT Serial1 + +bool ESP8266WebServer::_parseRequest(WiFiClient& client) { + // Read the first line of HTTP request + String req = client.readStringUntil('\r'); + client.readStringUntil('\n'); + + // 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 + DEBUG_OUTPUT.print("Invalid request: "); + DEBUG_OUTPUT.println(req); +#endif + return false; + } + + 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; + } + _currentMethod = method; + +#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; + // below 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(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(); + } + } + + if(!isForm){ + if(searchStr != "") searchStr += '&'; + searchStr += client.readStringUntil('\r'); + client.readStringUntil('\n'); + } + _parseArguments(searchStr); + if(isForm){ + _parseForm(client, boundaryStr, contentLength); + } + } else { + _parseArguments(searchStr); + } + client.flush(); + +#ifdef DEBUG + DEBUG_OUTPUT.print("Request: "); + DEBUG_OUTPUT.println(url); + DEBUG_OUTPUT.print(" Arguments: "); + DEBUG_OUTPUT.println(searchStr); +#endif + + return true; +} + + +void ESP8266WebServer::_parseArguments(String data) { +#ifdef DEBUG + DEBUG_OUTPUT.print("args: "); + DEBUG_OUTPUT.println(data); +#endif + if (_currentArgs) + delete[] _currentArgs; + _currentArgs = 0; + if (data.length() == 0) { + _currentArgCount = 0; + return; + } + _currentArgCount = 1; + + for (int i = 0; i < data.length(); ) { + i = data.indexOf('&', i); + if (i == -1) + break; + ++i; + ++_currentArgCount; + } +#ifdef DEBUG + DEBUG_OUTPUT.print("args count: "); + DEBUG_OUTPUT.println(_currentArgCount); +#endif + + _currentArgs = new RequestArgument[_currentArgCount]; + int pos = 0; + int iarg; + for (iarg = 0; iarg < _currentArgCount;) { + int equal_sign_index = data.indexOf('=', pos); + int next_arg_index = data.indexOf('&', pos); +#ifdef DEBUG + 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 + DEBUG_OUTPUT.print("arg missing value: "); + DEBUG_OUTPUT.println(iarg); +#endif + if (next_arg_index == -1) + break; + pos = next_arg_index + 1; + continue; + } + RequestArgument& arg = _currentArgs[iarg]; + arg.key = data.substring(pos, equal_sign_index); + arg.value = data.substring(equal_sign_index + 1, next_arg_index); +#ifdef DEBUG + 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) + break; + pos = next_arg_index + 1; + } + _currentArgCount = iarg; +#ifdef DEBUG + 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.totalSize = 0; + _currentUpload.currentSize = 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.currentSize++] = argByte; + if(_currentUpload.currentSize == PAYLOAD_UNIT_SIZE){ + #ifdef DEBUG + DEBUG_OUTPUT.print("Write File: "); + DEBUG_OUTPUT.println(PAYLOAD_UNIT_SIZE); + #endif + if(_fileUploadHandler) _fileUploadHandler(); + _currentUpload.totalSize += _currentUpload.currentSize; + _currentUpload.currentSize = 0; + } + argByte = client.read(); + } + + argByte = client.read(); + if(argByte == 0x0A){ +#ifdef DEBUG + DEBUG_OUTPUT.print("Write File: "); + DEBUG_OUTPUT.println(_currentUpload.currentSize); +#endif + if(_fileUploadHandler) _fileUploadHandler(); + _currentUpload.totalSize += _currentUpload.currentSize; + _currentUpload.currentSize = 0; + + argByte = client.read(); + if((char)argByte != '-'){ + //continue reading the file + _currentUpload.buf[_currentUpload.currentSize++] = 0x0D; + _currentUpload.buf[_currentUpload.currentSize++] = 0x0A; + goto readfile; + } else { + argByte = client.read(); + if((char)argByte != '-'){ + //continue reading the file + _currentUpload.buf[_currentUpload.currentSize++] = 0x0D; + _currentUpload.buf[_currentUpload.currentSize++] = 0x0A; + _currentUpload.buf[_currentUpload.currentSize++] = (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.totalSize); +#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.currentSize++] = 0x0D; + _currentUpload.buf[_currentUpload.currentSize++] = 0x0A; + uint32_t i = 0; + while(i < boundary.length()){ + _currentUpload.buf[_currentUpload.currentSize++] = endBuf[i++]; + if(_currentUpload.currentSize == PAYLOAD_UNIT_SIZE){ +#ifdef DEBUG + DEBUG_OUTPUT.print("Write File: "); + DEBUG_OUTPUT.println(PAYLOAD_UNIT_SIZE); +#endif + if(_fileUploadHandler) _fileUploadHandler(); + _currentUpload.totalSize += _currentUpload.currentSize; + _currentUpload.currentSize = 0; + } + } + argByte = client.read(); + goto readfile; + } + } else { + _currentUpload.buf[_currentUpload.currentSize++] = 0x0D; + if(_currentUpload.currentSize == PAYLOAD_UNIT_SIZE){ + #ifdef DEBUG + DEBUG_OUTPUT.print("Write File: "); + DEBUG_OUTPUT.println(PAYLOAD_UNIT_SIZE); + #endif + if(_fileUploadHandler) _fileUploadHandler(); + _currentUpload.totalSize += _currentUpload.currentSize; + _currentUpload.currentSize = 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; + } +} + diff --git a/libraries/ESP8266WiFi/src/WiFiClient.h b/libraries/ESP8266WiFi/src/WiFiClient.h index 251f2b3e3..d1bdb35df 100644 --- a/libraries/ESP8266WiFi/src/WiFiClient.h +++ b/libraries/ESP8266WiFi/src/WiFiClient.h @@ -25,6 +25,7 @@ #include "Print.h" #include "Client.h" #include "IPAddress.h" +#include class ClientContext; class WiFiServer; @@ -44,6 +45,9 @@ public: virtual int connect(const char *host, uint16_t port); virtual size_t write(uint8_t); virtual size_t write(const uint8_t *buf, size_t size); + template + size_t write(T& source, size_t unitSize); + virtual int available(); virtual int read(); virtual int read(uint8_t *buf, size_t size); @@ -72,4 +76,24 @@ private: }; + +template +inline size_t WiFiClient::write(T& source, size_t unitSize) { + std::unique_ptr buffer(new uint8_t[unitSize]); + size_t size_sent = 0; + while(true) { + size_t left = source.available(); + if (!left) + break; + size_t will_send = (left < unitSize) ? left : unitSize; + source.read(buffer.get(), will_send); + size_t cb = write(buffer.get(), will_send); + size_sent += cb; + if (cb != will_send) { + break; + } + } + return size_sent; +} + #endif From 4644c3bad02b96fdec28fb1cf85051c5d077df63 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 14 May 2015 15:05:24 +0300 Subject: [PATCH 2/2] boolean -> bool --- cores/esp8266/FileSystem.cpp | 47 +++++++++++++++++--------------- cores/esp8266/FileSystem.h | 51 ++++++++++++++++------------------- cores/esp8266/spiffs/spiffs.h | 2 -- 3 files changed, 49 insertions(+), 51 deletions(-) diff --git a/cores/esp8266/FileSystem.cpp b/cores/esp8266/FileSystem.cpp index 7e42af06b..f2517cf98 100755 --- a/cores/esp8266/FileSystem.cpp +++ b/cores/esp8266/FileSystem.cpp @@ -21,41 +21,46 @@ #include "FileSystem.h" #include "Arduino.h" -boolean FSClass::mount(){ - if(_mounted) return true; +bool FSClass::mount() { + if (_mounted) + return true; + _mounted = spiffs_mount(); return _mounted; } -void FSClass::unmount(){ - if(!_mounted) return; +void FSClass::unmount() { + if (!_mounted) + return; + spiffs_unmount(); _mounted = false; } -boolean FSClass::format(){ +bool FSClass::format() { return spiffs_format(); } -boolean FSClass::exists(const char *filename){ +bool FSClass::exists(const char *filename) { spiffs_stat stat = {0}; - if (SPIFFS_stat(&_filesystemStorageHandle, filename, &stat) < 0) return false; + if (SPIFFS_stat(&_filesystemStorageHandle, filename, &stat) < 0) + return false; return stat.name[0] != '\0'; } -boolean FSClass::create(const char *filepath){ +bool FSClass::create(const char *filepath){ return SPIFFS_creat(&_filesystemStorageHandle, filepath, 0) == 0; } -boolean FSClass::remove(const char *filepath){ +bool FSClass::remove(const char *filepath){ return SPIFFS_remove(&_filesystemStorageHandle, filepath) == 0; } -boolean FSClass::rename(const char *filename, const char *newname){ +bool FSClass::rename(const char *filename, const char *newname) { return SPIFFS_rename(&_filesystemStorageHandle, filename, newname) == 0; } -FSFile FSClass::open(const char *filename, uint8_t mode){ +FSFile FSClass::open(const char *filename, uint8_t mode) { int repeats = 0; bool notExist; bool canRecreate = (mode & SPIFFS_CREAT) == SPIFFS_CREAT; @@ -81,25 +86,25 @@ FSFile FSClass::open(const char *filename, uint8_t mode){ FSClass FS; -FSFile::FSFile(){ +FSFile::FSFile() { _file = 0; _stats = {0}; } -FSFile::FSFile(file_t f){ +FSFile::FSFile(file_t f) { _file = f; if(SPIFFS_fstat(&_filesystemStorageHandle, _file, &_stats) != 0){ debugf("mount errno %d\n", SPIFFS_errno(&_filesystemStorageHandle)); } } -void FSFile::close(){ +void FSFile::close() { if (! _file) return; SPIFFS_close(&_filesystemStorageHandle, _file); _file = 0; } -uint32_t FSFile::size(){ +uint32_t FSFile::size() { if(! _file) return 0; uint32_t pos = SPIFFS_tell(&_filesystemStorageHandle, _file); SPIFFS_lseek(&_filesystemStorageHandle, _file, 0, SPIFFS_SEEK_END); @@ -108,31 +113,31 @@ uint32_t FSFile::size(){ return size; } -uint32_t FSFile::seek(uint32_t pos){ +uint32_t FSFile::seek(uint32_t pos) { if (! _file) return 0; return SPIFFS_lseek(&_filesystemStorageHandle, _file, pos, SPIFFS_SEEK_SET); } -uint32_t FSFile::position(){ +uint32_t FSFile::position() { if (! _file) return 0; return SPIFFS_tell(&_filesystemStorageHandle, _file); } -boolean FSFile::eof(){ +bool FSFile::eof() { if (! _file) return 0; return SPIFFS_eof(&_filesystemStorageHandle, _file); } -boolean FSFile::isDirectory(void){ +bool FSFile::isDirectory(void) { return false; } -int FSFile::read(void *buf, uint16_t nbyte){ +int FSFile::read(void *buf, uint16_t nbyte) { if (! _file) return -1; return SPIFFS_read(&_filesystemStorageHandle, _file, buf, nbyte); } -int FSFile::read(){ +int FSFile::read() { if (! _file) return -1; int val; if(SPIFFS_read(&_filesystemStorageHandle, _file, &val, 1) != 1) return -1; diff --git a/cores/esp8266/FileSystem.h b/cores/esp8266/FileSystem.h index 8704f260c..d675da114 100755 --- a/cores/esp8266/FileSystem.h +++ b/cores/esp8266/FileSystem.h @@ -29,7 +29,7 @@ class String; #define FSFILE_WRITE (SPIFFS_RDONLY | SPIFFS_WRONLY | SPIFFS_CREAT | SPIFFS_APPEND | SPIFFS_TRUNC) class FSFile : public Stream { - private: +private: spiffs_stat _stats; file_t _file; @@ -47,34 +47,29 @@ public: uint32_t remove(); uint32_t position(); uint32_t size(); - boolean eof(); + bool eof(); void close(); int lastError(); void clearError(); - operator bool(){ return _file > 0; } + operator bool() { return _file > 0; } char * name(); - boolean isDirectory(void); + bool isDirectory(void); template size_t write(T &src){ - uint8_t obuf[64]; - size_t doneLen = 0; - size_t sentLen; - int i; - - while (src.available() > 64){ - src.read(obuf, 64); - sentLen = write(obuf, 64); - doneLen = doneLen + sentLen; - if(sentLen != 64){ - return doneLen; + const size_t bufferSize = 64; + uint8_t obuf[bufferSize]; + size_t bytesWritten = 0; + while (true){ + size_t available = src.available(); + size_t willWrite = (available < bufferSize) ? available : bufferSize; + src.read(obuf, willWrite); + size_t cb = write(obuf, willWrite); + bytesWritten += cb; + if (cb != willWrite) { + return bytesWritten; } } - - size_t leftLen = src.available(); - src.read(obuf, leftLen); - sentLen = write(obuf, leftLen); - doneLen = doneLen + sentLen; - return doneLen; + return bytesWritten; } using Print::write; @@ -83,16 +78,16 @@ public: class FSClass { private: - boolean _mounted; + bool _mounted; public: - boolean mount(); + bool mount(); void unmount(); - boolean format(); - boolean exists(const char *filename); - boolean create(const char *filepath); - boolean remove(const char *filepath); - boolean rename(const char *filename, const char *newname); + bool format(); + bool exists(const char *filename); + bool create(const char *filepath); + bool remove(const char *filepath); + bool rename(const char *filename, const char *newname); FSFile open(const char *filename, uint8_t mode = FSFILE_READ); diff --git a/cores/esp8266/spiffs/spiffs.h b/cores/esp8266/spiffs/spiffs.h index ad922b4a8..6357b44a7 100755 --- a/cores/esp8266/spiffs/spiffs.h +++ b/cores/esp8266/spiffs/spiffs.h @@ -12,8 +12,6 @@ extern "C" { #endif -//#include "c_stdio.h" -#include #include "spiffs_config.h" #include "flashmem.h"