azurite
Version:
An open source Azure Storage API compatible server
140 lines • 7.18 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractStoragePartsFromPath = exports.queueStorageContextMiddleware = 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 QueueStorageContext_1 = tslib_1.__importDefault(require("../context/QueueStorageContext"));
const StorageErrorFactory_1 = tslib_1.__importDefault(require("../errors/StorageErrorFactory"));
const constants_3 = require("../utils/constants");
const utils_1 = require("../utils/utils");
function createQueueStorageContextMiddleware(skipApiVersionCheck, disableProductStyleUrl) {
return (req, res, next) => {
return queueStorageContextMiddleware(req, res, next, skipApiVersionCheck, disableProductStyleUrl);
};
}
exports.default = createQueueStorageContextMiddleware;
/**
* A middleware extract related queue 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 queueStorageContextMiddleware(req, res, next, skipApiVersionCheck, disableProductStyleUrl) {
// Set server header in every Azurite response
res.setHeader(constants_3.HeaderConstants.SERVER, `Azurite-Queue/${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 queueContext = new QueueStorageContext_1.default(res.locals, constants_3.DEFAULT_QUEUE_CONTEXT_PATH);
queueContext.startTime = new Date();
queueContext.xMsRequestID = requestID;
Logger_1.default.info(`QueueStorageContextMiddleware: 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, queue, message, messageId, isSecondary] = extractStoragePartsFromPath(req.hostname, req.path, disableProductStyleUrl);
queueContext.account = account;
queueContext.queue = queue;
queueContext.message = message;
queueContext.messageId = messageId;
queueContext.isSecondary = isSecondary;
// Emulator's URL pattern is like http://hostname[:port]/account/queue/messages
// (or, alternatively, http[s]://account.localhost[:port]/queue/messages)
// 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
queueContext.dispatchPattern =
queue !== undefined
? message !== undefined
? messageId !== undefined
? `/queue/messages/messageId`
: `/queue/messages`
: `/queue`
: "/";
// The value of queue may be "" in some cases, e.g. list queue with .../accountname/?comp=list...
if (req.query &&
(req.query.restype === "service" || req.query.comp === "list")) {
queueContext.dispatchPattern = "/";
}
queueContext.authenticationPath = req.path;
if (isSecondary) {
const pos = queueContext.authenticationPath.search(constants_3.SECONDARY_SUFFIX);
if (pos !== -1) {
queueContext.authenticationPath =
queueContext.authenticationPath.substr(0, pos) +
queueContext.authenticationPath.substr(pos + constants_3.SECONDARY_SUFFIX.length);
}
}
if (account === undefined) {
const handlerError = StorageErrorFactory_1.default.getInvalidQueryParameterValue(requestID);
Logger_1.default.error(`QueueStorageContextMiddleware: QueueStorageContextMiddleware: ${handlerError.message}`, requestID);
return next(handlerError);
}
// If it is not and account operations, then the queue name should be validated.
if (queueContext.dispatchPattern !== "/" && queue !== undefined) {
const nameValidateStatus = (0, utils_1.isValidName)(queue);
if (nameValidateStatus === utils_1.nameValidateCode.invalidUri) {
const handlerError = StorageErrorFactory_1.default.getInvalidUri(requestID, {
UriPath: `/${queue}`
});
return next(handlerError);
}
if (nameValidateStatus === utils_1.nameValidateCode.outOfRange) {
const handlerError = StorageErrorFactory_1.default.getOutOfRangeName(requestID);
return next(handlerError);
}
if (nameValidateStatus === utils_1.nameValidateCode.invalidName) {
const handlerError = StorageErrorFactory_1.default.getInvalidResourceName(requestID);
return next(handlerError);
}
}
Logger_1.default.info(`QueueStorageContextMiddleware: Account=${account} Queue=${queue} Message=${message} MessageId=${messageId}`, requestID);
next();
}
exports.queueStorageContextMiddleware = queueStorageContextMiddleware;
/**
* Extract storage account, queue, and massages from URL path.
*
* @param {string} path
* @returns {([string | undefined, string | undefined, string | undefined, boolean | undefined])}
*/
function extractStoragePartsFromPath(hostname, path, disableProductStyleUrl) {
let account;
let queue;
let message;
let messageId;
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++];
}
queue = parts[urlPartIndex++];
// For delete and update, it is messages/messageid?popreceipt=string-value
message = parts[urlPartIndex++];
messageId = parts[urlPartIndex++];
if (account.endsWith(constants_3.SECONDARY_SUFFIX)) {
account = account.substr(0, account.length - constants_3.SECONDARY_SUFFIX.length);
isSecondary = true;
}
return [account, queue, message, messageId, isSecondary];
}
exports.extractStoragePartsFromPath = extractStoragePartsFromPath;
//# sourceMappingURL=queueStorageContext.middleware.js.map