Your new topic does not fit any of the above??? Check first. Then post here. Thanks.

Moderator: igrr

User avatar
By treii28
#69779 I'm wondering if there is anything similar to libgen.h or that might include utilities like basename and dirname that works in conjunction with the types/values of the SPIFFS and FS.h code? I need to manipulate pathnames and prefer not to re-design the wheel if I don't have to. I may try pulling over ligen.h and the associated c files from source code later if need be.
User avatar
By treii28
#69857 Yeah, I kinda figured that out. It tries to emulate them. I was able to get something to work using combinations of .lastIndexOf() and .endsWith() String methods.

Code: Select alltypedef struct pathInfo {
    String path;
    String dir;
    String name;
    String base;
    String ext;
    String type;
    bool gzip = false;
    bool compress = false;
    bool min = false;
} PINF;

PINF getPathInfo(String path) {
    PINF pInfo;
    pInfo.path = path;
    int8_t lastIdx = path.lastIndexOf("/");
    pInfo.dir = "";
    pInfo.name = path;
    if((lastIdx != -1) && (lastIdx > 0)) {
        pInfo.dir = path.substring(0, lastIdx + 1);
        pInfo.name = path.substring(lastIdx+1);
    }
    lastIdx = pInfo.name.lastIndexOf(".");
    if(lastIdx != -1) {
        pInfo.base = pInfo.name.substring(0, lastIdx);
        pInfo.ext = pInfo.name.substring(lastIdx+1);

        // comment out next 6 lines to keep .min. in basenames
        lastIdx = pInfo.base.lastIndexOf(".min");
        if(lastIdx != -1) {
            pInfo.min = true;
            pInfo.base = pInfo.base.substring(0, lastIdx) + pInfo.base.substring(lastIdx+4);
            DBG_OUTPUT_PORT.println("unminified base: " + pInfo.base);
        }

        while((pInfo.ext == "gz") || (pInfo.ext == "Z") || (pInfo.ext == "z")) {
            if(pInfo.ext == "gz") {
                pInfo.gzip = true;
            } else if((pInfo.ext == "Z") || (pInfo.ext == "z")) {
                pInfo.compress = true;
            }
            lastIdx = pInfo.base.lastIndexOf(".");
            if(lastIdx != -1) {
                pInfo.ext = pInfo.base.substring(lastIdx+1);
                pInfo.base = pInfo.base.substring(0, lastIdx);
            }
        }
    } else {
        pInfo.base = pInfo.name;
        pInfo.ext = "";
    }
    pInfo.type = "application/octet-stream";

    if(pInfo.ext == "htm") pInfo.type = "text/html";
    else if(pInfo.ext == "txt") pInfo.type = "text/plain";
    else if(pInfo.ext == "css") pInfo.type = "text/css";
    else if(pInfo.ext == "xml") pInfo.type = "text/xml";
    else if(pInfo.ext == "rtf") pInfo.type = "text/richtext";
    else if(pInfo.ext == "csv") pInfo.type = "text/csv";
    else if(pInfo.ext == "js")  pInfo.type = "application/javascript";
    else if(pInfo.ext == "png") pInfo.type = "image/png";
    else if(pInfo.ext == "gif") pInfo.type = "image/gif";
    else if((pInfo.ext == "jpg") || (pInfo.ext == "jpeg")) pInfo.type = "image/jpeg";
    else if(pInfo.ext == "ico") pInfo.type = "image/x-icon";
    else if(pInfo.ext == "svg") pInfo.type = "image/svg+xml";
    else if(pInfo.ext == "pdf") pInfo.type = "application/pdf";
    else if(pInfo.ext == "zip") pInfo.type = "application/zip";

    return pInfo;
}

PINF getTruePathInfo(String fPath) {
    PINF fpInf = getPathInfo(fPath);
    if(SPIFFS.exists(fpInf.path))
        return fpInf;

    DBG_OUTPUT_PORT.println("path not found, trying alternatives...");

    DBG_OUTPUT_PORT.println("Trying...");
    String altPath = fpInf.path + ".gz";
    DBG_OUTPUT_PORT.println("   " + altPath);
    if((altPath.length() <= fs_info.maxPathLength) && SPIFFS.exists(altPath)) {
        fpInf.gzip = true;
        fpInf.path = altPath;
    } else if(!fpInf.min && !fpInf.gzip && !fpInf.compress) {
        altPath = fpInf.dir + fpInf.base + ".min." + fpInf.ext;
        DBG_OUTPUT_PORT.println("   " + altPath);
        if((altPath.length() <= fs_info.maxPathLength) && SPIFFS.exists(altPath)) {
            fpInf.min = true;
            fpInf.path = altPath;
        } else {
            altPath = altPath + ".gz";
            DBG_OUTPUT_PORT.println("   " + altPath);
            if((altPath.length() <= fs_info.maxPathLength) && SPIFFS.exists(altPath)) {
                fpInf.gzip = true;
                fpInf.path = altPath;
            }
        }
    }
    if(fPath != fpInf.path ) {
        DBG_OUTPUT_PORT.println("using alternate path: " + altPath);
    }
    return fpInf;
}

bool printDir(AsyncWebServerRequest *request) {
    String dPath = request->url();
    // remove any trailing slash
    if(!dPath.endsWith("/"))
        dPath += "/";
    DBG_OUTPUT_PORT.println("attempting printDir on '" + dPath + "'");
    Dir webDir = SPIFFS.openDir(dPath);
    String dirList = "";
    while (webDir.next()) {
        PINF pInfo = getPathInfo(webDir.fileName());
        String fName = pInfo.base + "." + pInfo.ext;
        dirList += "<tr><td><a href=\"" + pInfo.dir + fName + "\">" +fName + "</a></td><td>&nbsp;...&nbsp;</td>";
        File f = webDir.openFile("r");
        dirList += "<td>" + String(f.size()) + "</td></tr>";
        f.close();
    }
    if(dirList != "") {
        DBG_OUTPUT_PORT.println("Sending directory listing.");
        String dirHtml = "<html><head><title>" + dPath + " Directory Listing</title></head>";
        dirHtml += "<body><h1>" + dPath + " Directory Listing</h1><hr /><table>" + dirList + "</table></body></html>";
        request->send(200, "text/html", dirHtml);
        return true;
    } else {
        return false;
    }
}

bool loadFromFlash(AsyncWebServerRequest *request) {
    String path = request->url();
    DBG_OUTPUT_PORT.println("checking flash for " + path);

    PINF upInf = getTruePathInfo(path);

    // if upInf doesn't include an existing file, try index.htm and/or try listing directory
    if(!SPIFFS.exists(upInf.path)) {
        String dAlt;
        if(path.endsWith("/")) { // user seems to be trying to get a dir listing
            // check for index file in dir first
            dAlt = path + "index.htm";
            // filenames must be under 32 characters all told
            if((dAlt.length() <= fs_info.maxPathLength) && SPIFFS.exists(dAlt)) {
                upInf = getTruePathInfo(dAlt);
            } else {
                return printDir(request);
            }
        } else {
            // try slash+index.htm just for kicks
            dAlt = path + "/index.htm";
            if ((dAlt.length() <= fs_info.maxPathLength) && SPIFFS.exists(dAlt)) {
                upInf = getTruePathInfo(dAlt);
            } else {
                return printDir(request);
            }
        }
    }


    File webFile  = SPIFFS.open(upInf.path, "r");

    if (!webFile){
        DBG_OUTPUT_PORT.println("problem opening " + upInf.path);
        return false;
    }

    AsyncWebServerResponse *response = request->beginResponse(
            webFile, upInf.path, upInf.type, false, NULL);

    if(upInf.gzip)
        response->addHeader("Content-Encoding", "gzip");
    else if(upInf.compress)
        response->addHeader("Content-Encoding", "compress");
    request->send(response);

    return true;
}

void handleNotFound(AsyncWebServerRequest *request){
    String path = request->url();
    if(loadFromFlash(request)){
        return;
    }
    String message = "\nNo Handler\r\n";
    message += "URI: ";
    message += request->url();
    message += "\nMethod: ";
    message += (request->method() == HTTP_GET)?"GET":"POST";
    message += "\nParameters: ";
    message += request->params();
    message += "\n";
    for (uint8_t i=0; i<request->params(); i++){
        AsyncWebParameter* p = request->getParam(i);
        message += String(p->name().c_str()) + " : " + String(p->value().c_str()) + "\r\n";
    }
    request->send(404, "text/plain", message);
    DBG_OUTPUT_PORT.print(message);
}