diff --git a/ESPWebDAV.cpp b/ESPWebDAV.cpp index ba76f15..595f467 100644 --- a/ESPWebDAV.cpp +++ b/ESPWebDAV.cpp @@ -1,10 +1,23 @@ // WebDAV server using ESP8266 and SD card filesystem // Targeting Windows 7 Explorer WebDav +#ifdef ESP32 +#include +#else #include +#endif #include + +#ifdef USE_SDFAT #include +#else +#include +#endif +#ifdef ESP32 +#include +#else #include +#endif //ESP32 #include #include "ESPWebDAV.h" @@ -12,16 +25,30 @@ const char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; const char *wdays[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +String sha256(String input) { + //TODO: Actually do something useful + //unsigned char sha256[32]; + //mbedtls_sha256_ret((const unsigned char*)input.c_str(), sizeof(input.c_str()), sha256, 0); + return input; +} // ------------------------ +#ifdef USE_SDFAT bool ESPWebDAV::init(int chipSelectPin, SPISettings spiSettings, int serverPort) { +#else +bool ESPWebDAV::init(int serverPort) { +#endif // ------------------------ // start the wifi server server = new WiFiServer(serverPort); server->begin(); - + +#ifdef USE_SDFAT // initialize the SD card return sd.begin(chipSelectPin, spiSettings); +#else + return true; +#endif } @@ -86,11 +113,23 @@ void ESPWebDAV::handleRequest(String blank) { ResourceType resource = RESOURCE_NONE; // does uri refer to a file or directory or a null? +#ifdef USE_SDFAT FatFile tFile; if(tFile.open(sd.vwd(), uri.c_str(), O_READ)) { resource = tFile.isDir() ? RESOURCE_DIR : RESOURCE_FILE; tFile.close(); } +#else + File tFile; + if (uri.length() > 1 && uri.endsWith("/")) { + tFile = sd.open(uri.substring(0,uri.length()-1)); + } else { + tFile = sd.open(uri.c_str()); + } + if (tFile) + resource = tFile.isDirectory() ? RESOURCE_DIR : RESOURCE_FILE; + tFile.close(); +#endif DBG_PRINT("\r\nm: "); DBG_PRINT(method); DBG_PRINT(" r: "); DBG_PRINT(resource); @@ -239,14 +278,29 @@ void ESPWebDAV::handleProp(ResourceType resource) { sendContent(F("")); // open this resource +#ifdef USE_SDFAT SdFile baseFile; baseFile.open(uri.c_str(), O_READ); +#else + File baseFile; + if (uri.length() > 1 && uri.endsWith("/")) { + DBG_PRINT("Open shortened uri: "); DBG_PRINT(uri.substring(0,uri.length()-1)); + baseFile = sd.open(uri.substring(0,uri.length()-1)); + } else { + DBG_PRINT("Open uri: "); DBG_PRINT(uri.substring(0,uri.length()-1)); + baseFile = sd.open(uri.c_str()); + } +#endif sendPropResponse(false, &baseFile); if((resource == RESOURCE_DIR) && (depth == DEPTH_CHILD)) { // append children information to message +#ifdef USE_SDFAT SdFile childFile; while(childFile.openNext(&baseFile, O_READ)) { +#else + while(File childFile = baseFile.openNextFile()) { +#endif yield(); sendPropResponse(true, &childFile); childFile.close(); @@ -260,21 +314,30 @@ void ESPWebDAV::handleProp(ResourceType resource) { // ------------------------ -void ESPWebDAV::sendPropResponse(boolean recursing, FatFile *curFile) { +#ifdef USE_SDFAT + void ESPWebDAV::sendPropResponse(boolean recursing, FatFile *curFile) { +#else + void ESPWebDAV::sendPropResponse(boolean recursing, File *curFile) { +#endif // ------------------------ +#ifdef USE_SDFAT char buf[255]; curFile->getName(buf, sizeof(buf)); - +#else + const char* buf = curFile->name()+1; +#endif + DBG_PRINT("SendPropResponse for "); DBG_PRINTLN(buf); // String fullResPath = "http://" + hostHeader + uri; String fullResPath = uri; - if(recursing) + if(recursing) { if(fullResPath.endsWith("/")) fullResPath += String(buf); else fullResPath += "/" + String(buf); - + }; // get file modified time +#ifdef USE_SDFAT dir_t dir; curFile->dirEntry(&dir); @@ -287,11 +350,15 @@ void ESPWebDAV::sendPropResponse(boolean recursing, FatFile *curFile) { tmStr.tm_mon = FAT_MONTH(dir.lastWriteDate) - 1; tmStr.tm_mday = FAT_DAY(dir.lastWriteDate); time_t t2t = mktime(&tmStr); +#else + time_t t2t = curFile->getLastWrite(); +#endif tm *gTm = gmtime(&t2t); // Tue, 13 Oct 2015 17:07:35 GMT - sprintf(buf, "%s, %02d %s %04d %02d:%02d:%02d GMT", wdays[gTm->tm_wday], gTm->tm_mday, months[gTm->tm_mon], gTm->tm_year + 1900, gTm->tm_hour, gTm->tm_min, gTm->tm_sec); - String fileTimeStamp = String(buf); + char tsBuf[255]; + sprintf(tsBuf, "%s, %02d %s %04d %02d:%02d:%02d GMT", wdays[gTm->tm_wday], gTm->tm_mday, months[gTm->tm_mon], gTm->tm_year + 1900, gTm->tm_hour, gTm->tm_min, gTm->tm_sec); + String fileTimeStamp = String(tsBuf); // send the XML information about thyself to client @@ -303,15 +370,27 @@ void ESPWebDAV::sendPropResponse(boolean recursing, FatFile *curFile) { sendContent(fileTimeStamp); sendContent(F("")); // append unique tag generated from full path +#ifdef ESP32 + sendContent("\"" + sha256(fullResPath + fileTimeStamp) + "\""); +#else sendContent("\"" + sha1(fullResPath + fileTimeStamp) + "\""); +#endif sendContent(F("")); +#ifdef USE_SDFAT if(curFile->isDir()) +#else + if(curFile->isDirectory()) +#endif sendContent(F("")); else { sendContent(F("")); // append the file size +#ifdef USE_SDFAT sendContent(String(curFile->fileSize())); +#else + sendContent(String(curFile->size())); +#endif sendContent(F("")); // append correct file mime type sendContent(getMimeType(fullResPath)); @@ -332,13 +411,21 @@ void ESPWebDAV::handleGet(ResourceType resource, bool isGet) { if(resource != RESOURCE_FILE) return handleNotFound(); - SdFile rFile; long tStart = millis(); uint8_t buf[1460]; +#ifdef USE_SDFAT + SdFile rFile; rFile.open(uri.c_str(), O_READ); +#else + File rFile = sd.open(uri.c_str()); +#endif sendHeader("Allow", "PROPFIND,OPTIONS,DELETE,COPY,MOVE,HEAD,POST,PUT,GET"); +#ifdef USE_SDFAT size_t fileSize = rFile.fileSize(); +#else + size_t fileSize = rFile.size(); +#endif setContentLength(fileSize); String contentType = getMimeType(uri); if(uri.endsWith(".gz") && contentType != "application/x-gzip" && contentType != "application/octet-stream") @@ -374,15 +461,18 @@ void ESPWebDAV::handlePut(ResourceType resource) { if(resource == RESOURCE_DIR) return handleNotFound(); - SdFile nFile; sendHeader("Allow", "PROPFIND,OPTIONS,DELETE,COPY,MOVE,HEAD,POST,PUT,GET"); +#ifdef USE_SDFAT + SdFile nFile; // if file does not exist, create it if(resource == RESOURCE_NONE) { if(!nFile.open(uri.c_str(), O_CREAT | O_WRITE)) return handleWriteError("Unable to create a new file", &nFile); } - +#else + File nFile = sd.open(uri.c_str(), FILE_WRITE); +#endif // file is created/open for writing at this point DBG_PRINT(uri); DBG_PRINTLN(" - ready for data"); // did server send any data in put @@ -394,7 +484,7 @@ void ESPWebDAV::handlePut(ResourceType resource) { uint8_t buf[WRITE_BLOCK_CONST]; long tStart = millis(); size_t numRemaining = contentLen; - +#ifdef USE_SDFAT // high speed raw write implementation // close any previous file nFile.close(); @@ -414,7 +504,7 @@ void ESPWebDAV::handlePut(ResourceType resource) { if (!sd.card()->writeStart(bgnBlock, contBlocks)) return handleWriteError("Unable to start writing contiguous range", &nFile); - +#endif // read data from stream and write to the file while(numRemaining > 0) { size_t numToRead = (numRemaining > WRITE_BLOCK_CONST) ? WRITE_BLOCK_CONST : numRemaining; @@ -423,24 +513,29 @@ void ESPWebDAV::handlePut(ResourceType resource) { break; // store whole buffer into file regardless of numRead +#ifdef USE_SDFAT if (!sd.card()->writeData(buf)) +#else + if (!nFile.write(buf, numRead)) +#endif return handleWriteError("Write data failed", &nFile); // reduce the number outstanding numRemaining -= numRead; } +#ifdef USE_SDFAT // stop writing operation if (!sd.card()->writeStop()) return handleWriteError("Unable to stop writing contiguous range", &nFile); - // detect timeout condition - if(numRemaining) - return handleWriteError("Timed out waiting for data", &nFile); - // truncate the file to right length if(!nFile.truncate(contentLen)) return handleWriteError("Unable to truncate the file", &nFile); +#endif + // detect timeout condition + if(numRemaining) + return handleWriteError("Timed out waiting for data", &nFile); DBG_PRINT("File "); DBG_PRINT(contentLen - numRemaining); DBG_PRINT(" bytes stored in: "); DBG_PRINT((millis() - tStart)/1000); DBG_PRINTLN(" sec"); } @@ -457,7 +552,11 @@ void ESPWebDAV::handlePut(ResourceType resource) { // ------------------------ -void ESPWebDAV::handleWriteError(String message, FatFile *wFile) { +#ifdef USE_SDFAT +void ESPWebDAV::handleWriteError(String message, FatFile *wFile) { +#else +void ESPWebDAV::handleWriteError(String message, File *wFile) { +#endif // ------------------------ // close this file wFile->close(); @@ -479,7 +578,11 @@ void ESPWebDAV::handleDirectoryCreate(ResourceType resource) { return handleNotFound(); // create directory +#ifdef USE_SDFAT if (!sd.mkdir(uri.c_str(), true)) { +#else + if (!sd.mkdir(uri.substring(0,uri.length()-1))) { +#endif // send error send("500 Internal Server Error", "text/plain", "Unable to create directory"); DBG_PRINTLN("Unable to create directory"); diff --git a/ESPWebDAV.h b/ESPWebDAV.h index d64835a..82ed5a8 100644 --- a/ESPWebDAV.h +++ b/ESPWebDAV.h @@ -1,5 +1,13 @@ +#ifdef ESP32 +#include +#else #include +#endif +#ifdef USE_SDFAT #include +#else +#include +#endif // debugging // #define DBG_PRINT(...) { Serial.print(__VA_ARGS__); } @@ -19,7 +27,12 @@ enum DepthType { DEPTH_NONE, DEPTH_CHILD, DEPTH_ALL }; class ESPWebDAV { public: +#ifdef USE_SDFAT bool init(int chipSelectPin, SPISettings spiSettings, int serverPort); +#else + ESPWebDAV(): sd(SD) {}; + bool init(int serverPort); +#endif bool isClientWaiting(); void handleClient(String blank = ""); void rejectClient(String rejectMessage); @@ -36,10 +49,18 @@ class ESPWebDAV { void handleUnlock(ResourceType resource); void handlePropPatch(ResourceType resource); void handleProp(ResourceType resource); +#ifdef USE_SDFAT void sendPropResponse(boolean recursing, FatFile *curFile); +#else + void sendPropResponse(boolean recursing, File *curFile); +#endif void handleGet(ResourceType resource, bool isGet); void handlePut(ResourceType resource); +#ifdef USE_SDFAT void handleWriteError(String message, FatFile *wFile); +#else + void handleWriteError(String message, File *wFile); +#endif void handleDirectoryCreate(ResourceType resource); void handleMove(ResourceType resource); void handleDelete(ResourceType resource); @@ -61,7 +82,11 @@ class ESPWebDAV { // variables pertaining to current most HTTP request being serviced WiFiServer *server; +#ifdef USE_SDFAT SdFat sd; +#else + fs::SDFS sd; +#endif WiFiClient client; String method; diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..9f41337 --- /dev/null +++ b/library.properties @@ -0,0 +1,9 @@ +name=ESPWebDAV +version=1.0.0 +author=ardyesp +maintainer=ardyesp +sentence=With this library you can easily build a WebDAV server with your ESP8266 or ESP32. +paragraph=Read and write data to your SD card from any WebDAV-enabled client on the the network. +category=Communication +url=https://github.com/ardyesp/ESPWebDAV +architectures=esp8266,esp32 \ No newline at end of file