Skip to content

Fix inconsistent behavior in serveStatic() of WebServer on ESP32 using LittleFS #6172

Closed
@technik-gegg

Description

@technik-gegg

Board

ESP32DEV

Device Description

NodeMCU

Hardware Configuration

Not relevant

Version

v2.0.2

IDE Name

PlatformIO

Operating System

Windows 10

Flash frequency

default

PSRAM enabled

no

Upload speed

115200

Description

I'm working on a firmware which is offering a web browser interface for controlling the behavior for both the ESP8266 and ESP32. I've figured inconsistencies in those frameworks when using the serveStatic() method of the WebServer class.
The serveStatic() method mainly serves two purposes:
One is to build a facade to abstract complex page names into a simple URI, i.e.:

serveStatic("/dump", FS, "/www/debug/dump_runtime_vars.html")

The other is to tell the WebServer in which folder(s) to look for files being requested by the browser unconditionally, i.e:

serveStatic("/css", FS, "/www/css/")

In the latter case, any file requested that starts with the URI /css/ is being concatenated to the physical path (/www/css/) and returned to the caller (browser).

This is the way it works in the ESP8266 framework, regardless whether SPIFFS or LittleFS is being used. In the ESP32 framework this doesn't work the same way if LittleFS is being used. One has to explicitly define every possible file which could be requested by the browser, which is not only inconvenient but also requires to modify, recompile and flash the firmware every time new files are being added to the file system.

I've traced down this issue and found out, that the culprit is the constructor of the StaticRequestHandler class (lines 65 ff) utilized by the WebServers serveStatic() method.
The main issue occurs because of the first line this code:

_isFile = fs.exists(path); <--
log_v("StaticRequestHandler: path=%s uri=%s isFile=%d ...
_baseUriLength = _uri.length();

Though this works well on SPIFFS it doesn't on LittleFS, since LittleFS returns true from the .exists() method if the given path is a valid directory.
To overcome this issue one has to change the _isFile = line to:
_isFile = fs.exists(path) && !fs.isDirectory(path);
Although this is a clean solution, unfortunately it won't cut since the FS implementation doesn't come with a .isDirectory() method.

So, to solve that problem I've used the quick & dirty method instead, which is:

_isFile = (strchr(path, '.') != nullptr);

Assuming that only files have an extension in the filename.

Sure, even if this works, this isn't something that should be done in a publicly available framework, so I'd highly recommend going the first path and adding the .isDirectory() method to the FS implementation.

Sketch

See description

Debug Message

Not applicable

Other Steps to Reproduce

None

I have checked existing issues, online documentation and the Troubleshooting Guide

  • I confirm I have checked existing issues, online documentation and Troubleshooting guide.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions