UNPKG

azurite

Version:

An open source Azure Storage API compatible server

180 lines 9.35 kB
"use strict"; 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