superstatic
Version:
A static file server for fancy apps
105 lines (104 loc) • 4.07 kB
JavaScript
/**
* Copyright (c) 2022 Google LLC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
let RE2;
const minimatch = require("minimatch");
try {
RE2 = require("re2");
}
catch (er) {
RE2 = null;
}
/**
* Evaluates whether a configured redirect/rewrite/custom header should
* be applied to a request against a specific path. All three features
* are configured with a hash that contains either a Node-like glob path
* specification as its `source` or `glob` field, or a RE2 regular
* expression as its `regex` field.
*
* Since Javascript lacks a native library for RE2, Superstatic uses the C
* bindings as an optional dependency, and falls over to PCRE if the import
* is unavailable. Under most circumstances not involving named capturing
* groups, the two libraries should have identical behavior.
*
* No special consideration is taken if the configuration hash contains both
* a glob and a regex. normalizeConfig() will error in that case.
* @param {string} path The URL path from the request.
* @param {object} config A dictionary from a sanitized JSON configuration.
* @return {boolean} Whether the config should be applied to the request.
*/
function configMatcher(path, config) {
const glob = config.glob || config.source;
const regex = config.regex;
if (glob) {
return minimatch(path, glob);
}
if (regex) {
const pattern = RE2 ? new RE2(regex, "u") : new RegExp(regex, "u");
return path.match(pattern) !== null;
}
return false;
}
/**
* Creates either an RE2 or a Javascript RegExp from a provided string
* pattern, depending on whether or not the RE2 library is available as an
* import.
* @param {string} pattern A regular expression pattern to test against.
* @return {RegExp} A regular expression object, created by either base
* RegExp or RE2, which matches the RegExp prototype
*/
function createRaw(pattern) {
return RE2 ? new RE2(pattern, "u") : new RegExp(pattern, "u");
}
/**
* Returns true if RE2, which is an optional dependency, has been loaded.
* @return {boolean}
*/
function re2Available() {
return RE2 ? true : false;
}
/**
* Is truthy if the provided raw string pattern contains a RE2 named capture
* group opening, ?P<, which is not interpretable when Superstatic is falling
* back on the base Javascript RegExp implementation.
* @param {string} pattern
* @return {boolean}
*/
function containsRE2Capture(pattern) {
return pattern && pattern.includes("?P<");
}
/**
* Is truthy if the provided raw string pattern contains a PCRE named capture
* group opening, ?<, which is not interpretable when Superstatic has loaded
* the RE2 bindings.
* @param {string} pattern
* @return {boolean}
*/
function containsPCRECapture(pattern) {
return pattern && pattern.includes("?<");
}
module.exports = {
configMatcher: configMatcher,
createRaw: createRaw,
re2Available: re2Available,
containsRE2Capture: containsRE2Capture,
containsPCRECapture: containsPCRECapture,
};
;