azurite
Version:
An open source Azure Storage API compatible server
180 lines • 9.35 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractStoragePartsFromPath = exports.blobStorageContextMiddleware = exports.internalBlobStorageContextMiddleware = void 0;
const tslib_1 = require("tslib");
const v4_1 = tslib_1.__importDefault(require("uuid/v4"));
const Logger_1 = tslib_1.__importDefault(require("../../common/Logger"));
const constants_1 = require("../../common/utils/constants");
const constants_2 = require("../../common/utils/constants");
const BlobStorageContext_1 = tslib_1.__importDefault(require("../context/BlobStorageContext"));
const StorageErrorFactory_1 = tslib_1.__importDefault(require("../errors/StorageErrorFactory"));
const constants_3 = require("../utils/constants");
const utils_1 = require("../utils/utils");
function createStorageBlobContextMiddleware(skipApiVersionCheck, disableProductStyleUrl, loose) {
return (req, res, next) => {
return blobStorageContextMiddleware(req, res, next, skipApiVersionCheck, disableProductStyleUrl, loose);
};
}
exports.default = createStorageBlobContextMiddleware;
/**
* A middleware extract related blob service context.
*
* @export
* @param {Request} req An express compatible Request object
* @param {Response} res An express compatible Response object
* @param {NextFunction} next An express middleware next callback
*/
function internalBlobStorageContextMiddleware(blobContext, req, res, reqHost, reqPath, next, skipApiVersionCheck, disableProductStyleUrl, loose) {
// Set server header in every Azurite response
res.setHeader(constants_3.HeaderConstants.SERVER, `Azurite-Blob/${constants_3.VERSION}`);
const requestID = (0, v4_1.default)();
if (!skipApiVersionCheck) {
const apiVersion = req.getHeader(constants_3.HeaderConstants.X_MS_VERSION);
if (apiVersion !== undefined) {
(0, utils_1.checkApiVersion)(apiVersion, constants_3.ValidAPIVersions, requestID);
}
}
blobContext.startTime = new Date();
blobContext.disableProductStyleUrl = disableProductStyleUrl;
blobContext.loose = loose;
blobContext.xMsRequestID = requestID;
Logger_1.default.info(`BlobStorageContextMiddleware: RequestMethod=${req.getMethod()} RequestURL=${req.getUrl()} RequestHeaders:${JSON.stringify(req.getHeaders())} ClientIP=${req.getEndpoint()} Protocol=${req.getProtocol()} HTTPVersion=version`, requestID);
const [account, container, blob, isSecondary] = extractStoragePartsFromPath(reqHost, reqPath, disableProductStyleUrl);
blobContext.account = account;
blobContext.container = container;
blobContext.blob = blob;
blobContext.isSecondary = isSecondary;
// Emulator's URL pattern is like http://hostname[:port]/account/container
// (or, alternatively, http[s]://account.localhost[:port]/container)
// Create a router to exclude account name from req.path, as url path in swagger doesn't include account
// Exclude account name from req.path for dispatchMiddleware
blobContext.dispatchPattern = container
? blob
? `/container/blob`
: `/container`
: "/";
blobContext.authenticationPath = reqPath;
if (isSecondary) {
const pos = blobContext.authenticationPath.search(constants_3.SECONDARY_SUFFIX);
if (pos !== -1) {
blobContext.authenticationPath =
blobContext.authenticationPath.substr(0, pos) +
blobContext.authenticationPath.substr(pos + constants_3.SECONDARY_SUFFIX.length);
}
}
if (!account) {
const handlerError = StorageErrorFactory_1.default.getInvalidQueryParameterValue(requestID);
Logger_1.default.error(`BlobStorageContextMiddleware: BlobStorageContextMiddleware: ${handlerError.message}`, requestID);
return next(handlerError);
}
// validate container name, when container name has value (not undefined or empty string)
// skip validate system container
if (container && !container.startsWith("$")) {
(0, utils_1.validateContainerName)(requestID, container);
}
Logger_1.default.info(`BlobStorageContextMiddleware: Account=${account} Container=${container} Blob=${blob}`, requestID);
next();
}
exports.internalBlobStorageContextMiddleware = internalBlobStorageContextMiddleware;
/**
* A middleware extract related blob service context.
*
* @export
* @param {Request} req An express compatible Request object
* @param {Response} res An express compatible Response object
* @param {NextFunction} next An express middleware next callback
*/
function blobStorageContextMiddleware(req, res, next, skipApiVersionCheck, disableProductStyleUrl, loose) {
// Set server header in every Azurite response
res.setHeader(constants_3.HeaderConstants.SERVER, `Azurite-Blob/${constants_3.VERSION}`);
const requestID = (0, v4_1.default)();
if (!skipApiVersionCheck) {
const apiVersion = req.header(constants_3.HeaderConstants.X_MS_VERSION);
if (apiVersion !== undefined) {
(0, utils_1.checkApiVersion)(apiVersion, constants_3.ValidAPIVersions, requestID);
}
}
const blobContext = new BlobStorageContext_1.default(res.locals, constants_3.DEFAULT_CONTEXT_PATH);
blobContext.startTime = new Date();
blobContext.disableProductStyleUrl = disableProductStyleUrl;
blobContext.loose = loose;
blobContext.xMsRequestID = requestID;
Logger_1.default.info(`BlobStorageContextMiddleware: RequestMethod=${req.method} RequestURL=${req.protocol}://${req.hostname}${req.url} RequestHeaders:${JSON.stringify(req.headers)} ClientIP=${req.ip} Protocol=${req.protocol} HTTPVersion=${req.httpVersion}`, requestID);
const [account, container, blob, isSecondary] = extractStoragePartsFromPath(req.hostname, req.path, disableProductStyleUrl);
blobContext.account = account;
blobContext.container = container;
blobContext.blob = blob;
blobContext.isSecondary = isSecondary;
// Emulator's URL pattern is like http://hostname[:port]/account/container
// (or, alternatively, http[s]://account.localhost[:port]/container)
// Create a router to exclude account name from req.path, as url path in swagger doesn't include account
// Exclude account name from req.path for dispatchMiddleware
blobContext.dispatchPattern = container
? blob
? `/container/blob`
: `/container`
: "/";
blobContext.authenticationPath = req.path;
if (isSecondary) {
const pos = blobContext.authenticationPath.search(constants_3.SECONDARY_SUFFIX);
if (pos !== -1) {
blobContext.authenticationPath =
blobContext.authenticationPath.substr(0, pos) +
blobContext.authenticationPath.substr(pos + constants_3.SECONDARY_SUFFIX.length);
}
}
if (!account) {
const handlerError = StorageErrorFactory_1.default.getInvalidQueryParameterValue(requestID);
Logger_1.default.error(`BlobStorageContextMiddleware: BlobStorageContextMiddleware: ${handlerError.message}`, requestID);
return next(handlerError);
}
// validate container name, when container name has value (not undefined or empty string)
// skip validate system container
if (container && !container.startsWith("$")) {
(0, utils_1.validateContainerName)(requestID, container);
}
Logger_1.default.info(`BlobStorageContextMiddleware: Account=${account} Container=${container} Blob=${blob}`, requestID);
next();
}
exports.blobStorageContextMiddleware = blobStorageContextMiddleware;
/**
* Extract storage account, container, and blob from URL path.
*
* @param {string} path
* @returns {([string | undefined, string | undefined, string | undefined, boolean | undefined])}
*/
function extractStoragePartsFromPath(hostname, path, disableProductStyleUrl) {
let account;
let container;
let blob;
let isSecondary = false;
const decodedPath = decodeURIComponent(path);
const normalizedPath = decodedPath.startsWith("/")
? decodedPath.substr(1)
: decodedPath; // Remove starting "/"
const parts = normalizedPath.split("/");
let urlPartIndex = 0;
const isIPAddress = constants_1.IP_REGEX.test(hostname);
const isNoAccountHostName = constants_2.NO_ACCOUNT_HOST_NAMES.has(hostname.toLowerCase());
const firstDotIndex = hostname.indexOf(".");
// If hostname is not an IP address or a known host name, and has a dot inside,
// we assume user wants to access emulator with a production-like URL.
if (!disableProductStyleUrl && !isIPAddress && !isNoAccountHostName && firstDotIndex > 0) {
account = hostname.substring(0, firstDotIndex);
}
else {
account = parts[urlPartIndex++];
}
container = parts[urlPartIndex++];
blob = parts
.slice(urlPartIndex++)
.join("/")
.replace(/\\/g, "/"); // Azure Storage Server will replace "\" with "/" in the blob names
if (account.endsWith(constants_3.SECONDARY_SUFFIX)) {
account = account.substr(0, account.length - constants_3.SECONDARY_SUFFIX.length);
isSecondary = true;
}
return [account, container, blob, isSecondary];
}
exports.extractStoragePartsFromPath = extractStoragePartsFromPath;
//# sourceMappingURL=blobStorageContext.middleware.js.map
;