Webdav: listing works
This commit is contained in:
		
							parent
							
								
									210c7b9cdc
								
							
						
					
					
						commit
						be4a4a13bd
					
				| 
						 | 
					@ -1,13 +1,14 @@
 | 
				
			||||||
#include <ESPAsyncWebServer.h>
 | 
					#include <ESPAsyncWebServer.h>
 | 
				
			||||||
#include <FS.h>
 | 
					#include <FS.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define FLASH_TEXT(name)   const char *name
 | 
					#define FLASH_TEXT(name) const char *name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
namespace webdav_constants {
 | 
					namespace webdav_constants
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
    FLASH_TEXT(MULTISTATUS_START) = "<?xml version=\"1.0\" ?><D:multistatus xmlns:D=\"DAV:\">";
 | 
					    FLASH_TEXT(MULTISTATUS_START) = "<?xml version=\"1.0\" ?><D:multistatus xmlns:D=\"DAV:\">";
 | 
				
			||||||
    FLASH_TEXT(MULTISTATUS_END) = "</D:multistatus>";
 | 
					    FLASH_TEXT(MULTISTATUS_END) = "</D:multistatus>";
 | 
				
			||||||
    FLASH_TEXT(RESPONSE_START) = "<D:response>";
 | 
					    FLASH_TEXT(RESPONSE_START) = "<D:response>";
 | 
				
			||||||
    FLASH_TEXT(RESPONSE_END) = "</D:response>";
 | 
					    FLASH_TEXT(RESPONSE_END) = "</D:response>\n";
 | 
				
			||||||
    FLASH_TEXT(HREF_START) = "<D:href>";
 | 
					    FLASH_TEXT(HREF_START) = "<D:href>";
 | 
				
			||||||
    FLASH_TEXT(HREF_END) = "</D:href>";
 | 
					    FLASH_TEXT(HREF_END) = "</D:href>";
 | 
				
			||||||
    FLASH_TEXT(PROPSTAT_START) = "<D:propstat>";
 | 
					    FLASH_TEXT(PROPSTAT_START) = "<D:propstat>";
 | 
				
			||||||
| 
						 | 
					@ -26,32 +27,148 @@ namespace webdav_constants {
 | 
				
			||||||
    FLASH_TEXT(MODDATE_START) = "<D:getlastmodified>";
 | 
					    FLASH_TEXT(MODDATE_START) = "<D:getlastmodified>";
 | 
				
			||||||
    FLASH_TEXT(MODDATE_END) = "</D:getlastmodified>";
 | 
					    FLASH_TEXT(MODDATE_END) = "</D:getlastmodified>";
 | 
				
			||||||
    FLASH_TEXT(STATUS_OK) = "<D:status>HTTP/1.1 200 OK</D:status>";
 | 
					    FLASH_TEXT(STATUS_OK) = "<D:status>HTTP/1.1 200 OK</D:status>";
 | 
				
			||||||
}
 | 
					} // namespace webdav_constants
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void listFiles(AsyncResponseStream * response, const char *folderPath, Dir * dir)
 | 
					class WebdavFileListCallback
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    WebdavFileListCallback(const String &path)
 | 
				
			||||||
 | 
					        : path_(path), headerWritten_(false), finished_(false)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        dir_ = SPIFFS.openDir(path);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t operator()(uint8_t *buffer, size_t maxLen, size_t index)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Serial.print("index ");
 | 
				
			||||||
 | 
					        Serial.println(index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        using namespace webdav_constants;
 | 
				
			||||||
 | 
					        uint8_t *bufferStart = buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (finished_)
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!headerWritten_)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            toBuffer(buffer, MULTISTATUS_START);
 | 
				
			||||||
 | 
					            headerWritten_ = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        bool fileFound = false;
 | 
				
			||||||
 | 
					        while (dir_.next())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            if (isFirstFileOfTrainingGroup())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                fileFound = true;
 | 
				
			||||||
 | 
					                break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (fileFound)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            toBuffer(buffer, path_.c_str());
 | 
				
			||||||
 | 
					            toBuffer(buffer, RESPONSE_START);
 | 
				
			||||||
 | 
					            toBuffer(buffer, HREF_START);
 | 
				
			||||||
 | 
					            String fileBaseName = dir_.fileName().substring(0, dir_.fileName().indexOf('_'));
 | 
				
			||||||
 | 
					            fileBaseName += ".st";
 | 
				
			||||||
 | 
					            toBuffer(buffer, fileBaseName.c_str());
 | 
				
			||||||
 | 
					            toBuffer(buffer, HREF_END);
 | 
				
			||||||
 | 
					            toBuffer(buffer, PROPSTAT_START);
 | 
				
			||||||
 | 
					            toBuffer(buffer, PROP_START);
 | 
				
			||||||
 | 
					            if (dir_.isDirectory())
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                toBuffer(buffer, RESOURCETYPE_START);
 | 
				
			||||||
 | 
					                toBuffer(buffer, RESOURCE_COLLECTION);
 | 
				
			||||||
 | 
					                toBuffer(buffer, RESOURCETYPE_END);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                toBuffer(buffer, CONTENTLEN_START);
 | 
				
			||||||
 | 
					                String fileSizeStr(getFileSize(dir_.fileName()));
 | 
				
			||||||
 | 
					                toBuffer(buffer, fileSizeStr.c_str());
 | 
				
			||||||
 | 
					                toBuffer(buffer, CONTENTLEN_END);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            toBuffer(buffer, PROP_END);
 | 
				
			||||||
 | 
					            toBuffer(buffer, STATUS_OK);
 | 
				
			||||||
 | 
					            toBuffer(buffer, PROPSTAT_END);
 | 
				
			||||||
 | 
					            toBuffer(buffer, webdav_constants::RESPONSE_END);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            toBuffer(buffer, MULTISTATUS_END);
 | 
				
			||||||
 | 
					            finished_ = true;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        size_t bytesWritten = buffer - bufferStart;
 | 
				
			||||||
 | 
					        assert(bytesWritten < maxLen, "Written too much!");
 | 
				
			||||||
 | 
					        Serial.print("Bytes written ");
 | 
				
			||||||
 | 
					        Serial.println(bytesWritten);
 | 
				
			||||||
 | 
					        Serial.print("Max bytes ");
 | 
				
			||||||
 | 
					        Serial.println(maxLen);
 | 
				
			||||||
 | 
					        return bytesWritten;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    bool isFirstFileOfTrainingGroup()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return !dir_.isDirectory() && dir_.fileName().endsWith("_0");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    size_t getFileSize(const String &fileZero)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        size_t size = 0;
 | 
				
			||||||
 | 
					        auto fileBase = fileZero.substring(0, fileZero.indexOf('_'));
 | 
				
			||||||
 | 
					        auto newDirInstance = SPIFFS.openDir(path_);
 | 
				
			||||||
 | 
					        while (newDirInstance.next())
 | 
				
			||||||
 | 
					            if (newDirInstance.isFile() && newDirInstance.fileName().startsWith(fileBase))
 | 
				
			||||||
 | 
					                size += newDirInstance.fileSize();
 | 
				
			||||||
 | 
					        return size;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void toBuffer(uint8_t *&buffer, const char *text)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        auto len = strlen(text);
 | 
				
			||||||
 | 
					        memcpy(buffer, text, len);
 | 
				
			||||||
 | 
					        buffer += len;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Dir dir_;
 | 
				
			||||||
 | 
					    const String path_;
 | 
				
			||||||
 | 
					    bool headerWritten_;
 | 
				
			||||||
 | 
					    bool finished_;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void listFiles(AsyncResponseStream *response, const char *folderPath, Dir *dir)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    using namespace webdav_constants;
 | 
					    using namespace webdav_constants;
 | 
				
			||||||
    response->println(MULTISTATUS_START);
 | 
					    response->println(MULTISTATUS_START);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Serial.println("Before rewind");
 | 
					    Serial.println("Before rewind");
 | 
				
			||||||
    dir->rewind();
 | 
					    dir->rewind();
 | 
				
			||||||
    Serial.println("After rewind");
 | 
					    Serial.println("After rewind");
 | 
				
			||||||
    while (dir->next()) {
 | 
					    while (dir->next())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        Serial.println("Inside dir loop");
 | 
					        Serial.println("Inside dir loop");
 | 
				
			||||||
        Serial.println(folderPath);
 | 
					        Serial.println(folderPath);
 | 
				
			||||||
        Serial.println(dir->fileName());
 | 
					        Serial.println(dir->fileName());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        response->print(RESPONSE_START);
 | 
					        response->print(RESPONSE_START);
 | 
				
			||||||
        response->print(HREF_START);
 | 
					        response->print(HREF_START);
 | 
				
			||||||
        response->print(folderPath);
 | 
					        //response->print(folderPath);
 | 
				
			||||||
        response->print(dir->fileName());
 | 
					        response->print(dir->fileName());
 | 
				
			||||||
        response->print(HREF_END);
 | 
					        response->print(HREF_END);
 | 
				
			||||||
        response->print(PROPSTAT_START);
 | 
					        response->print(PROPSTAT_START);
 | 
				
			||||||
        response->print(PROP_START);
 | 
					        response->print(PROP_START);
 | 
				
			||||||
        if (dir->isDirectory()) {
 | 
					        if (dir->isDirectory())
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            response->print(RESOURCETYPE_START);
 | 
					            response->print(RESOURCETYPE_START);
 | 
				
			||||||
            response->print(RESOURCE_COLLECTION);
 | 
					            response->print(RESOURCE_COLLECTION);
 | 
				
			||||||
            response->print(RESOURCETYPE_END);
 | 
					            response->print(RESOURCETYPE_END);
 | 
				
			||||||
        } else {
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            response->print(CONTENTLEN_START);
 | 
					            response->print(CONTENTLEN_START);
 | 
				
			||||||
            response->print(dir->fileSize(), DEC);
 | 
					            response->print(dir->fileSize(), DEC);
 | 
				
			||||||
            response->print(CONTENTLEN_END);
 | 
					            response->print(CONTENTLEN_END);
 | 
				
			||||||
| 
						 | 
					@ -61,17 +178,18 @@ void listFiles(AsyncResponseStream * response, const char *folderPath, Dir * dir
 | 
				
			||||||
        response->print(STATUS_OK);
 | 
					        response->print(STATUS_OK);
 | 
				
			||||||
        response->print(PROPSTAT_END);
 | 
					        response->print(PROPSTAT_END);
 | 
				
			||||||
        response->println(webdav_constants::RESPONSE_END);
 | 
					        response->println(webdav_constants::RESPONSE_END);
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    response->println(MULTISTATUS_END);
 | 
					    response->println(MULTISTATUS_END);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
class SpiffsWebDavHandler : public AsyncWebHandler
 | 
					class SpiffsWebDavHandler : public AsyncWebHandler
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
    SpiffsWebDavHandler(const String & prefix, const String & folder)
 | 
					    SpiffsWebDavHandler(const String &prefix, const String &folder)
 | 
				
			||||||
        : prefix_(prefix), folder_(folder)
 | 
					        : prefix_(prefix), folder_(folder)
 | 
				
			||||||
    {}
 | 
					    {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    virtual bool canHandle(AsyncWebServerRequest *request) override final
 | 
					    virtual bool canHandle(AsyncWebServerRequest *request) override final
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
| 
						 | 
					@ -82,13 +200,15 @@ public:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    virtual void handleRequest(AsyncWebServerRequest *request) override final
 | 
					    virtual void handleRequest(AsyncWebServerRequest *request) override final
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        if (request->url() == prefix_ + "/" && request->method() == HTTP_PROPFIND) {
 | 
					        if (request->url() == prefix_ + "/" && (request->method() == HTTP_GET || request->method() == HTTP_PROPFIND))
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            Serial.println("Propfind start");
 | 
					            Serial.println("Propfind start");
 | 
				
			||||||
            AsyncResponseStream * response = request->beginResponseStream("application/xml");
 | 
					            //AsyncResponseStream *response = request->beginResponseStream("application/xml");
 | 
				
			||||||
            Dir dir = SPIFFS.openDir(folder_);
 | 
					            auto response = request->beginChunkedResponse("application/xml",
 | 
				
			||||||
            listFiles(response, "/", &dir);
 | 
					                                                          WebdavFileListCallback(folder_));
 | 
				
			||||||
            request->send(response);
 | 
					            request->send(response);
 | 
				
			||||||
        } else if(request->url() == prefix_ + "/" && request->method() == HTTP_GET) {
 | 
					        } /* 
 | 
				
			||||||
 | 
					        else if(request->url() == prefix_ + "/" && request->method() == HTTP_GET) {
 | 
				
			||||||
            AsyncResponseStream * response = request->beginResponseStream("text/plain", 1460*10);
 | 
					            AsyncResponseStream * response = request->beginResponseStream("text/plain", 1460*10);
 | 
				
			||||||
            Dir dir = SPIFFS.openDir(folder_);
 | 
					            Dir dir = SPIFFS.openDir(folder_);
 | 
				
			||||||
            Serial.print("Opening folder ");
 | 
					            Serial.print("Opening folder ");
 | 
				
			||||||
| 
						 | 
					@ -99,32 +219,42 @@ public:
 | 
				
			||||||
                response->println(dir.fileName());
 | 
					                response->println(dir.fileName());
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            request->send(response);
 | 
					            request->send(response);
 | 
				
			||||||
        }
 | 
					        }*/
 | 
				
			||||||
        else if (request->method() == HTTP_GET) {
 | 
					        else if (request->method() == HTTP_GET)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            auto path = folder_ + request->url().substring(prefix_.length());
 | 
					            auto path = folder_ + request->url().substring(prefix_.length());
 | 
				
			||||||
            if (SPIFFS.exists(path)) {
 | 
					            if (SPIFFS.exists(path))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                request->send(SPIFFS, path, "application/x-msgpack");
 | 
					                request->send(SPIFFS, path, "application/x-msgpack");
 | 
				
			||||||
            } else {
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                request->send(404, "text/plain", "Webdav: File not found");
 | 
					                request->send(404, "text/plain", "Webdav: File not found");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else if (request->method() == HTTP_DELETE) {
 | 
					        }
 | 
				
			||||||
 | 
					        else if (request->method() == HTTP_DELETE)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            auto path = folder_ + request->url().substring(prefix_.length());
 | 
					            auto path = folder_ + request->url().substring(prefix_.length());
 | 
				
			||||||
            if (SPIFFS.exists(path)) {
 | 
					            if (SPIFFS.exists(path))
 | 
				
			||||||
                if(SPIFFS.remove(path))
 | 
					            {
 | 
				
			||||||
 | 
					                if (SPIFFS.remove(path))
 | 
				
			||||||
                    request->send(204, "text/plain", "Success");
 | 
					                    request->send(204, "text/plain", "Success");
 | 
				
			||||||
                else
 | 
					                else
 | 
				
			||||||
                    request->send(404, "text/plain", "Webdav: Invalid delete request");
 | 
					                    request->send(404, "text/plain", "Webdav: Invalid delete request");
 | 
				
			||||||
            } else {
 | 
					            }
 | 
				
			||||||
 | 
					            else
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
                request->send(404, "text/plain", "Webdav: File to delete not found");
 | 
					                request->send(404, "text/plain", "Webdav: File to delete not found");
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        } else {
 | 
					        }
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
            request->send(404, "text/plain", "Webdav: Invalid request");
 | 
					            request->send(404, "text/plain", "Webdav: Invalid request");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    virtual bool isRequestHandlerTrivial() override final {return false;}
 | 
					    virtual bool isRequestHandlerTrivial() override final { return false; }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    String prefix_;
 | 
					    String prefix_;
 | 
				
			||||||
    String folder_;
 | 
					    String folder_;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue