Settings.js httpStatic feature to pass options to express.static (non-breaking)

I would like to extend the functionality of httpStatic in settings.js to receive an options object and have that passed to express.static(filePath, options).

The change would be non-breaking and give a finer control over how the files are served by express.static. The lines of code where the proposed changes are at line 424 of red.js .

I tested giving express.static bad data, such as a string or number. That will trigger an error stating that it wants an object or null, which is the reason for the mild sanitizing
const options = typeof sp.options === 'object' ? sp.options : null;

before changes:

    if (settings.httpStatic) {
        let appUseMem = {};
        for (let si = 0; si < settings.httpStatic.length; si++) {
            const sp = settings.httpStatic[si];
            const filePath = sp.path;
            const thisRoot = sp.root || "/";
            if(appUseMem[filePath + "::" + thisRoot]) {
                continue;// this path and root already registered!
            }
            appUseMem[filePath + "::" + thisRoot] = true;
            if (settings.httpStaticAuth) {
                app.use(thisRoot, basicAuthMiddleware(settings.httpStaticAuth.user, settings.httpStaticAuth.pass));
            }
            app.use(thisRoot, express.static(filePath));
        }
    }

after changes:

    if (settings.httpStatic) {
        let appUseMem = {};
        for (let si = 0; si < settings.httpStatic.length; si++) {
            const sp = settings.httpStatic[si];
            const filePath = sp.path;
            const thisRoot = sp.root || "/";
            const options = typeof sp.options === 'object' ? sp.options : null;
            if(appUseMem[filePath + "::" + thisRoot]) {
                continue;// this path and root already registered!
            }
            appUseMem[filePath + "::" + thisRoot] = true;
            if (settings.httpStaticAuth) {
                app.use(thisRoot, basicAuthMiddleware(settings.httpStaticAuth.user, settings.httpStaticAuth.pass));
            }
            app.use(thisRoot, express.static(filePath, options));
        }
    }

I have had this running for about 1 week and have had no issues. This is an excerpt from my setting.js that I am using for better integration and control when using nginx as a reverse proxy.

    httpStatic: [
        {
            path: '/run/media/system/surveillance1/cctv/recordings/',
            root: '/recordings/',
            options : {
                setHeaders: (res, path, stat) => {
                    if (path.endsWith('.mp4')) {
                        if (Date.now() - stat.mtimeMs < 60000) {
                            res.header('Cache-Control', 'no-store');
                        } else {
                            res.header('Cache-Control', 'public');
                        }
                    }
                }
            }
        }
    ],

If this seems acceptable, I can make a PR to the dev branch.

1 Like

A pr would be welcome. Much easier to review and comment that way.

1 Like

For anybody that is interested in seeing this small code change, it can be found @ httpStatic feature by kevinGodell · Pull Request #4109 · node-red/node-red · GitHub

Hopefully, I didn't submit this to the wrong branch. :sweat_smile:

1 Like

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.