Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Esp32 sd.h #6

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 120 additions & 17 deletions ESPWebDAV.cpp
Original file line number Diff line number Diff line change
@@ -1,27 +1,54 @@
// WebDAV server using ESP8266 and SD card filesystem
// Targeting Windows 7 Explorer WebDav

#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#include <SPI.h>

#ifdef USE_SDFAT
#include <SdFat.h>
#else
#include <SD.h>
#endif
#ifdef ESP32
#include <mbedtls/sha256.h>
#else
#include <Hash.h>
#endif //ESP32
#include <time.h>
#include "ESPWebDAV.h"

// define cal constants
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
}


Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -239,14 +278,29 @@ void ESPWebDAV::handleProp(ResourceType resource) {
sendContent(F("<D:multistatus xmlns:D=\"DAV:\">"));

// 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();
Expand All @@ -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);

Expand All @@ -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
Expand All @@ -303,15 +370,27 @@ void ESPWebDAV::sendPropResponse(boolean recursing, FatFile *curFile) {
sendContent(fileTimeStamp);
sendContent(F("</D:getlastmodified><D:getetag>"));
// append unique tag generated from full path
#ifdef ESP32
sendContent("\"" + sha256(fullResPath + fileTimeStamp) + "\"");
#else
sendContent("\"" + sha1(fullResPath + fileTimeStamp) + "\"");
#endif
sendContent(F("</D:getetag>"));

#ifdef USE_SDFAT
if(curFile->isDir())
#else
if(curFile->isDirectory())
#endif
sendContent(F("<D:resourcetype><D:collection/></D:resourcetype>"));
else {
sendContent(F("<D:resourcetype/><D:getcontentlength>"));
// append the file size
#ifdef USE_SDFAT
sendContent(String(curFile->fileSize()));
#else
sendContent(String(curFile->size()));
#endif
sendContent(F("</D:getcontentlength><D:getcontenttype>"));
// append correct file mime type
sendContent(getMimeType(fullResPath));
Expand All @@ -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")
Expand Down Expand Up @@ -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
Expand All @@ -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();
Expand All @@ -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;
Expand All @@ -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");
}
Expand All @@ -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();
Expand All @@ -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");
Expand Down
25 changes: 25 additions & 0 deletions ESPWebDAV.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
#ifdef ESP32
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif
#ifdef USE_SDFAT
#include <SdFat.h>
#else
#include <SD.h>
#endif

// debugging
// #define DBG_PRINT(...) { Serial.print(__VA_ARGS__); }
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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;
Expand Down