This interface is experemntal!
"); + res->println("This form allows you to upload files. Keep your filenames very short and files small. Big filenames and big " + "files are a known problem.
"); + res->println(""); + + res->println(""); + + if (String(file.name()).substring(1).endsWith(".gz")) { + String modifiedFile = String(file.name()).substring(1); + modifiedFile.remove((modifiedFile.length() - 3), 3); + res->print("" + String(file.name()).substring(1) + ""); + } else { + res->print("" + String(file.name()).substring(1) + ""); + } + res->println(" | "); + res->println(""); + res->print(String(file.size())); + res->println(" | "); + res->println(""); + res->print("X"); + res->println(" | "); + } + + file = root.openNextFile(); + } + res->println("
File not found: %s
\n", filename.c_str()); return; + } + + // Try to open the file from SPIFFS + File file; - } else if (parameter1 == "style.css") { + if (SPIFFS.exists(filename.c_str())) { + file = SPIFFS.open(filename.c_str()); + if (!file.available()) { + DEBUG_MSG("File not available - %s\n", filename.c_str()); + } + + } else if (SPIFFS.exists(filenameGzip.c_str())) { + file = SPIFFS.open(filenameGzip.c_str()); res->setHeader("Content-Encoding", "gzip"); - res->setHeader("Content-Type", "text/css"); - res->write(STATIC_STYLE_CSS_DATA, STATIC_STYLE_CSS_LENGTH); + if (!file.available()) { + DEBUG_MSG("File not available\n"); + } + } + + res->setHeader("Content-Length", httpsserver::intToString(file.size())); + + // Content-Type is guessed using the definition of the contentTypes-table defined above + int cTypeIdx = 0; + do { + if (filename.rfind(contentTypes[cTypeIdx][0]) != std::string::npos) { + res->setHeader("Content-Type", contentTypes[cTypeIdx][1]); + break; + } + cTypeIdx += 1; + } while (strlen(contentTypes[cTypeIdx][0]) > 0); + + // Read the file from SPIFFS and write it to the HTTP response body + size_t length = 0; + do { + char buffer[256]; + length = file.read((uint8_t *)buffer, 256); + std::string bufferString(buffer, length); + res->write((uint8_t *)bufferString.c_str(), bufferString.size()); + } while (length > 0); + + file.close(); + + return; + + } else { + res->println("ERROR: This should not have happened..."); + } +} + +void handleFormUpload(HTTPRequest *req, HTTPResponse *res) +{ + // First, we need to check the encoding of the form that we have received. + // The browser will set the Content-Type request header, so we can use it for that purpose. + // Then we select the body parser based on the encoding. + // Actually we do this only for documentary purposes, we know the form is going + // to be multipart/form-data. + HTTPBodyParser *parser; + std::string contentType = req->getHeader("Content-Type"); + + // The content type may have additional properties after a semicolon, for exampel: + // Content-Type: text/html;charset=utf-8 + // Content-Type: multipart/form-data;boundary=------s0m3w31rdch4r4c73rs + // As we're interested only in the actual mime _type_, we strip everything after the + // first semicolon, if one exists: + size_t semicolonPos = contentType.find(";"); + if (semicolonPos != std::string::npos) { + contentType = contentType.substr(0, semicolonPos); + } + + // Now, we can decide based on the content type: + if (contentType == "multipart/form-data") { + parser = new HTTPMultipartBodyParser(req); + } else { + Serial.printf("Unknown POST Content-Type: %s\n", contentType.c_str()); + return; + } + + res->println("No file found.
"); return; + } - } else { - res->print("Parameter 1: "); - res->printStd(parameter1); + // Double check that it is what we expect + if (filename == "") { + DEBUG_MSG("Skipping unexpected field"); + res->println("No file found.
"); + return; + } + // SPIFFS limits the total lenth of a path + file to 31 characters. + if (filename.length() + 8 > 31) { + DEBUG_MSG("Uploaded filename too long!"); + res->println("Uploaded filename too long! Limit of 23 characters.
"); + delete parser; return; } - } else { - res->println("ERROR: This should not have happened..."); + // You should check file name validity and all that, but we skip that to make the core + // concepts of the body parser functionality easier to understand. + std::string pathname = "/static/" + filename; + + // Create a new file on spiffs to stream the data into + File file = SPIFFS.open(pathname.c_str(), "w"); + size_t fileLength = 0; + didwrite = true; + + // With endOfField you can check whether the end of field has been reached or if there's + // still data pending. With multipart bodies, you cannot know the field size in advance. + while (!parser->endOfField()) { + byte buf[512]; + size_t readLength = parser->read(buf, 512); + file.write(buf, readLength); + fileLength += readLength; + + // Abort the transfer if there is less than 50k space left on the filesystem. + if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < 51200) { + file.close(); + res->println("Write aborted! File is won't fit!
"); + + delete parser; + return; + } + } + file.close(); + res->printf("Saved %d bytes to %s
", (int)fileLength, pathname.c_str()); + } + if (!didwrite) { + res->println("Did not write any file
"); } + res->println(""); + delete parser; } + void handle404(HTTPRequest *req, HTTPResponse *res) { @@ -397,15 +630,22 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) uint32_t len = 1; if (params->getQueryParameter("all", valueAll)) { + + // If all is ture, return all the buffers we have available + // to us at this point in time. if (valueAll == "true") { while (len) { len = webAPI.getFromRadio(txBuf); res->write(txBuf, len); } + + // Otherwise, just return one protobuf } else { len = webAPI.getFromRadio(txBuf); res->write(txBuf, len); } + + // the param "all" was not spcified. Return just one protobuf } else { len = webAPI.getFromRadio(txBuf); res->write(txBuf, len); @@ -458,248 +698,19 @@ void handleAPIv1ToRadio(HTTPRequest *req, HTTPResponse *res) */ void handleRoot(HTTPRequest *req, HTTPResponse *res) { - - String out = ""; - out += - "\n" - "\n" - "\n" - "\n" - "\n" - " \n" - "