proxyPrefix: '',
strictAccept: true,
selfBaseUrl: '',
+ staticMetadata: true,
trustProxy: true,
querystring,
};
* @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
*/
default:
this.logger.error(_scope, 'unknown dingus error', { error: e });
handler = this.handlerInternalServerError.bind(this);
- }
+ }
} else if (e instanceof URIError) {
handler = this.handlerBadRequest.bind(this);
} else {
}
+ /**
+ * 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.
// 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);
}
* @param {http.ServerResponse} res
* @param {object} ctx
*/
- async handlerBadRequest(req, res, ctx) {
+ async handlerBadRequest(req, res, ctx) {
this.setResponseType(this.responseTypes, req, res, ctx);
throw new ResponseError(Enum.ErrorResponse.BadRequest);
}
+
/**
* @param {http.ClientRequest} req
* @param {http.ServerResponse} res
* @param {object} ctx
*/
- async handlerInternalServerError(req, res, ctx) {
+ async handlerInternalServerError(req, res, ctx) {
this.setResponseType(this.responseTypes, req, res, ctx);
throw new ResponseError(Enum.ErrorResponse.InternalServerError);
}