potentially serve static files with static headers
[squeep-api-dingus] / lib / dingus.js
index c8e4909bf1edca17202e1ca26a3310b9d748ffb3..1cbfd72b8c95ad1d3fe3de38f7a1840349887a15 100644 (file)
@@ -26,6 +26,7 @@ const defaultOptions = {
   proxyPrefix: '',
   strictAccept: true,
   selfBaseUrl: '',
+  staticMetadata: true,
   trustProxy: true,
   querystring,
 };
@@ -38,6 +39,7 @@ class Dingus {
    * @param {string} options.proxyPrefix leading part of url path to strip
    * @param {Boolean} options.strictAccept whether to error on unsupported Accept type
    * @param {string} options.selfBaseUrl for constructing links
+   * @param {Boolean} options.staticMetadata serve static headers with static files
    * @param {Boolean} options.trustProxy trust some header data to be provided by proxy
    * @param {Object} options.querystring alternate qs parser to use
    */
@@ -444,6 +446,41 @@ class Dingus {
   }
 
 
+  /**
+   * Potentially add additional headers from static file meta-file.
+   * @param {http.ServerResponse} res
+   * @param {string} directory
+   * @param {string} fileName - already normalized and filtered
+   */
+  async _serveFileMetaHeaders(res, directory, fileName) {
+    const _scope = _fileScope('_serveFileMetaHeaders');
+    this.logger.debug(_scope, 'called', { directory, fileName });
+
+    const metaPrefix = '.';
+    const metaSuffix = '.meta';
+    const metaFileName = `${metaPrefix}${fileName}${metaSuffix}`;
+    const metaFilePath = path.join(directory, metaFileName);
+
+    const [stat, data] = await this._readFileInfo(metaFilePath);
+    if (!stat) {
+      return;
+    }
+
+    const lineBreakRE = /\r\n|\n|\r/;
+    const lines = data.toString().split(lineBreakRE);
+    common.unfoldHeaderLines(lines);
+
+    const headerParseRE = /^(?<name>[^:]+): +(?<value>.*)$/;
+    lines.forEach((line) => {
+      if (line) {
+        const result = headerParseRE.exec(line);
+        const { groups: header } = result;
+        res.setHeader(header.name, header.value);
+      }
+    });
+  }
+
+
   /**
    * Serve a file from a directory, with rudimentary cache awareness.
    * This will also serve pre-encoded variations if available and requested.
@@ -524,6 +561,10 @@ class Dingus {
     // We presume static files are relatively cacheable.
     res.setHeader(Enum.Header.CacheControl, 'public');
 
+    if (this.staticMetadata) {
+      await this._serveFileMetaHeaders(res, directory, fileName);
+    }
+
     this.logger.debug(_scope, 'serving file', { filePath, contentType });
     res.end(data);
   }
@@ -615,6 +656,7 @@ class Dingus {
     throw new ResponseError(Enum.ErrorResponse.BadRequest);
   }
 
+
   /**
    * @param {http.ClientRequest} req
    * @param {http.ServerResponse} res