import { NextFunction , Request , RequestHandler , Response } from "express" ; import uuid from "uuid/v4" ; import logger from "../../common/Logger" ; import { IP_REGEX } from "../../common/utils/constants" ; import { NO_ACCOUNT_HOST_NAMES } from "../../common/utils/constants" ; import QueueStorageContext from "../context/QueueStorageContext" ; import StorageErrorFactory from "../errors/StorageErrorFactory" ; import { DEFAULT_QUEUE_CONTEXT_PATH , HeaderConstants , SECONDARY_SUFFIX , ValidAPIVersions , VERSION } from "../utils/constants" ; import { checkApiVersion , isValidName , nameValidateCode } from "../utils/utils" ; export default function createQueueStorageContextMiddleware ( skipApiVersionCheck ? , disableProductStyleUrl ? ) { return ( req , res , next ) => { return queueStorageContextMiddleware ( req , res , next , skipApiVersionCheck , disableProductStyleUrl ) ; } ; } export param { Request } req param { Response } res param { NextFunction } next export function queueStorageContextMiddleware ( req , res , next , skipApiVersionCheck ? , disableProductStyleUrl ? ) { res . setHeader ( HeaderConstants . SERVER , `Azurite-Queue/${ VERSION }` ) ; const requestID = uuid ( ) ; if ( ! skipApiVersionCheck ) { const apiVersion = req . header ( HeaderConstants . X_MS_VERSION ) ; if ( apiVersion !== undefined ) { checkApiVersion ( apiVersion , ValidAPIVersions , requestID ) ; } } const queueContext = new QueueStorageContext ( res . locals , DEFAULT_QUEUE_CONTEXT_PATH ) ; queueContext . startTime = new Date ( ) ; queueContext . xMsRequestID = requestID ; logger . 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 ; queueContext . dispatchPattern = queue !== undefined ? message !== undefined ? messageId !== undefined ? `/queue/messages/messageId` : `/queue/messages` : `/queue` : "/" ; if ( req . query && ( req . query . restype === "service" || req . query . comp === "list" ) ) { queueContext . dispatchPattern = "/" ; } queueContext . authenticationPath = req . path ; if ( isSecondary ) { const pos = queueContext . authenticationPath . search ( SECONDARY_SUFFIX ) ; queueContext . authenticationPath = queueContext . authenticationPath . substr ( 0 , pos ) + queueContext . authenticationPath . substr ( pos + SECONDARY_SUFFIX . length ) ; } if ( account === undefined ) { const handlerError = StorageErrorFactory . getInvalidQueryParameterValue ( requestID ) ; logger . error ( `QueueStorageContextMiddleware: QueueStorageContextMiddleware: ${ handlerError . message }` , requestID ) ; return next ( handlerError ) ; } if ( queueContext . dispatchPattern !== "/" && queue !== undefined ) { const nameValidateStatus = isValidName ( queue ) ; if ( nameValidateStatus === nameValidateCode . invalidUri ) { const handlerError = StorageErrorFactory . getInvalidUri ( requestID , { UriPath : `/${ queue }` } ) ; return next ( handlerError ) ; } if ( nameValidateStatus === nameValidateCode . outOfRange ) { const handlerError = StorageErrorFactory . getOutOfRangeName ( requestID ) ; return next ( handlerError ) ; } if ( nameValidateStatus === nameValidateCode . invalidName ) { const handlerError = StorageErrorFactory . getInvalidResourceName ( requestID ) ; return next ( handlerError ) ; } } logger . info ( `QueueStorageContextMiddleware: Account=${ account } Queue=${ queue } Message=${ message } MessageId=${ messageId }` , requestID ) ; next ( ) ; } param { string } path returns { ( [ string | undefined , string | undefined , string | undefined , boolean | undefined ] ) } export 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 ; const parts = normalizedPath . split ( "/" ) ; let urlPartIndex = 0 ; const isIPAddress = IP_REGEX . test ( hostname ) ; const isNoAccountHostName = NO_ACCOUNT_HOST_NAMES . has ( hostname . toLowerCase ( ) ) ; const firstDotIndex = hostname . indexOf ( "." ) ; if ( ! disableProductStyleUrl && ! isIPAddress && ! isNoAccountHostName && firstDotIndex > 0 ) { account = hostname . substring ( 0 , firstDotIndex ) ; } else { account = parts [ urlPartIndex ++ ] ; } queue = parts [ urlPartIndex ++ ] ; message = parts [ urlPartIndex ++ ] ; messageId = parts [ urlPartIndex ++ ] ; if ( account . endsWith ( SECONDARY_SUFFIX ) ) { account = account . substr ( 0 , account . length - SECONDARY_SUFFIX . length ) ; isSecondary = true ; } return [ account , queue , message , messageId , isSecondary ] ; }