import { convertRawHeadersToMetadata , newEtag } from "../../common/utils/utils" ; import BlobStorageContext from "../context/BlobStorageContext" ; import * as Models from "../generated/artifacts/models" ; import Context from "../generated/Context" ; import IContainerHandler from "../generated/handlers/IContainerHandler" ; import { BLOB_API_VERSION , EMULATOR_ACCOUNT_KIND , EMULATOR_ACCOUNT_SKUNAME } from "../utils/constants" ; import { DEFAULT_LIST_BLOBS_MAX_RESULTS } from "../utils/constants" ; import { removeQuotationFromListBlobEtag } from "../utils/utils" ; import BaseHandler from "./BaseHandler" ; export class implements IHandler export default class ContainerHandler extends BaseHandler implements IContainerHandler { param { Models . ContainerCreateOptionalParams } options param { Context } context returns { Promise < Models . ContainerCreateResponse > } memberof public async create ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const lastModified = blobCtx . startTime ! ; const etag = newEtag ( ) ; const metadata = convertRawHeadersToMetadata ( blobCtx . request ! . getRawHeaders ( ) ) ; await this . metadataStore . createContainer ( context , { accountName , name : containerName , metadata , properties : { etag , lastModified , leaseStatus : Models . LeaseStatusType . Unlocked , leaseState : Models . LeaseStateType . Available , publicAccess : options . access , hasImmutabilityPolicy : false , hasLegalHold : false } } ) ; const response = { statusCode : 201 , requestId : blobCtx . contextId , clientRequestId : options . requestId , eTag : etag , lastModified , version : BLOB_API_VERSION } ; return response ; } param { Models . ContainerGetPropertiesOptionalParams } options param { Context } context returns { Promise < Models . ContainerGetPropertiesResponse > } memberof public async getProperties ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const containerProperties = await this . metadataStore . getContainerProperties ( context , accountName , containerName , options . leaseAccessConditions ) ; const response = { statusCode : 200 , requestId : context . contextId , clientRequestId : options . requestId , eTag : containerProperties . properties . etag , ... containerProperties . properties , blobPublicAccess : containerProperties . properties . publicAccess , metadata : containerProperties . metadata , version : BLOB_API_VERSION } ; return response ; } param { Models . ContainerGetPropertiesOptionalParams } options param { Context } context returns { Promise < Models . ContainerGetPropertiesResponse > } memberof public async getPropertiesWithHead ( options , context ) { return this . getProperties ( options , context ) ; } param { Models . ContainerDeleteMethodOptionalParams } options param { Context } context returns { Promise < Models . ContainerDeleteResponse > } memberof public async delete ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; await this . metadataStore . deleteContainer ( context , accountName , containerName , options ) ; const response = { statusCode : 202 , requestId : context . contextId , clientRequestId : options . requestId , date : context . startTime , version : BLOB_API_VERSION } ; return response ; } param { Models . ContainerSetMetadataOptionalParams } options param { Context } context returns { Promise < Models . ContainerSetMetadataResponse > } memberof public async setMetadata ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const date = blobCtx . startTime ! ; const eTag = newEtag ( ) ; const metadata = convertRawHeadersToMetadata ( blobCtx . request ! . getRawHeaders ( ) ) ; await this . metadataStore . setContainerMetadata ( context , accountName , containerName , date , eTag , metadata , options . leaseAccessConditions , options . modifiedAccessConditions ) ; const response = { statusCode : 200 , requestId : context . contextId , clientRequestId : options . requestId , date , eTag , lastModified : date } ; return response ; } param { Models . ContainerGetAccessPolicyOptionalParams } options param { Context } context returns { Promise < Models . ContainerGetAccessPolicyResponse > } memberof public async getAccessPolicy ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const containerAcl = await this . metadataStore . getContainerACL ( context , accountName , containerName , options . leaseAccessConditions ) ; const response = [ ] ; const responseArray = response as Models . SignedIdentifier [ ] ; const responseObject = response as Models . ContainerGetAccessPolicyHeaders & { statusCode : 200 ; } ; if ( containerAcl . containerAcl !== undefined ) { responseArray . push ( ... containerAcl . containerAcl ) ; } responseObject . date = containerAcl . properties . lastModified ; responseObject . blobPublicAccess = containerAcl . properties . publicAccess ; responseObject . eTag = containerAcl . properties . etag ; responseObject . lastModified = containerAcl . properties . lastModified ; responseObject . requestId = context . contextId ; responseObject . version = BLOB_API_VERSION ; responseObject . statusCode = 200 ; responseObject . clientRequestId = options . requestId ; return response ; } param { Models . ContainerSetAccessPolicyOptionalParams } options param { Context } context returns { Promise < Models . ContainerSetAccessPolicyResponse > } memberof public async setAccessPolicy ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const date = blobCtx . startTime ! ; const eTag = newEtag ( ) ; await this . metadataStore . setContainerACL ( context , accountName , containerName , { lastModified : date , etag : eTag , publicAccess : options . access , containerAcl : options . containerAcl , leaseAccessConditions : options . leaseAccessConditions , modifiedAccessConditions : options . modifiedAccessConditions } ) ; const response = { date , eTag , lastModified : date , requestId : context . contextId , version : BLOB_API_VERSION , statusCode : 200 , clientRequestId : options . requestId } ; return response ; } see https param { Models . ContainerAcquireLeaseOptionalParams } options param { Context } context returns { Promise < Models . ContainerAcquireLeaseResponse > } memberof public async acquireLease ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const res = await this . metadataStore . acquireContainerLease ( context , accountName , containerName , options ) ; const response = { statusCode : 201 , requestId : context . contextId , clientRequestId : options . requestId , date : blobCtx . startTime ! , eTag : res . properties . etag , lastModified : res . properties . lastModified , leaseId : res . leaseId , version : BLOB_API_VERSION } ; return response ; } see https param { string } leaseId param { Models . ContainerReleaseLeaseOptionalParams } options param { Context } context returns { Promise < Models . ContainerReleaseLeaseResponse > } memberof public async releaseLease ( leaseId , options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const res = await this . metadataStore . releaseContainerLease ( context , accountName , containerName , leaseId , options ) ; const response = { statusCode : 200 , requestId : context . contextId , clientRequestId : options . requestId , date : blobCtx . startTime ! , eTag : res . etag , lastModified : res . lastModified , version : BLOB_API_VERSION } ; return response ; } see https param { string } leaseId param { Models . ContainerRenewLeaseOptionalParams } options param { Context } context returns { Promise < Models . ContainerRenewLeaseResponse > } memberof public async renewLease ( leaseId , options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const res = await this . metadataStore . renewContainerLease ( context , accountName , containerName , leaseId , options ) ; const response = { statusCode : 200 , requestId : context . contextId , clientRequestId : options . requestId , date : blobCtx . startTime ! , leaseId : res . leaseId , eTag : res . properties . etag , lastModified : res . properties . lastModified , version : BLOB_API_VERSION } ; return response ; } see https param { Models . ContainerBreakLeaseOptionalParams } options param { Context } context returns { Promise < Models . ContainerBreakLeaseResponse > } memberof public async breakLease ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const res = await this . metadataStore . breakContainerLease ( context , accountName , containerName , options . breakPeriod , options ) ; const response = { statusCode : 202 , requestId : context . contextId , clientRequestId : options . requestId , date : blobCtx . startTime ! , eTag : res . properties . etag , lastModified : res . properties . lastModified , leaseTime : res . leaseTime , version : BLOB_API_VERSION } ; return response ; } see https param { string } leaseId param { string } proposedLeaseId param { Models . ContainerChangeLeaseOptionalParams } options param { Context } context returns { Promise < Models . ContainerChangeLeaseResponse > } memberof public async changeLease ( leaseId , proposedLeaseId , options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; const res = await this . metadataStore . changeContainerLease ( context , accountName , containerName , leaseId , proposedLeaseId , options ) ; const response = { statusCode : 200 , requestId : context . contextId , clientRequestId : options . requestId , date : blobCtx . startTime ! , eTag : res . properties . etag , lastModified : res . properties . lastModified , leaseId : res . leaseId , version : BLOB_API_VERSION } ; return response ; } param { Models . ContainerListBlobFlatSegmentOptionalParams } options param { Context } context returns { Promise < Models . ContainerListBlobFlatSegmentResponse > } memberof public async listBlobFlatSegment ( options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; await this . metadataStore . checkContainerExist ( context , accountName , containerName ) ; const request = context . request ! ; const marker = options . marker ; const delimiter = "" ; options . marker = options . marker || "" ; let includeSnapshots = false ; let includeUncommittedBlobs = false ; if ( options . include !== undefined ) { options . include . forEach ( element => { if ( Models . ListBlobsIncludeItem . Snapshots . toLowerCase ( ) === element . toLowerCase ( ) ) { includeSnapshots = true ; } if ( Models . ListBlobsIncludeItem . Uncommittedblobs . toLowerCase ( ) === element . toLowerCase ( ) ) { includeUncommittedBlobs = true ; } } ) ; } if ( options . maxresults === undefined || options . maxresults > DEFAULT_LIST_BLOBS_MAX_RESULTS ) { options . maxresults = DEFAULT_LIST_BLOBS_MAX_RESULTS ; } const [ blobs , nextMarker ] = await this . metadataStore . listBlobs ( context , accountName , containerName , undefined , options . prefix , options . maxresults , marker , includeSnapshots , includeUncommittedBlobs ) ; const serviceEndpoint = `${ request . getEndpoint ( ) }/${ accountName }` ; const response = { statusCode : 200 , contentType : "application/xml" , requestId : context . contextId , version : BLOB_API_VERSION , date : context . startTime , serviceEndpoint , containerName , prefix : options . prefix || "" , marker : options . marker , maxResults : options . maxresults , delimiter , segment : { blobItems : blobs . map ( item => { return { ... item , deleted : item . deleted !== true ? undefined : true , snapshot : item . snapshot || undefined , properties : { ... item . properties , etag : removeQuotationFromListBlobEtag ( item . properties . etag ) , accessTierInferred : item . properties . accessTierInferred === true ? true : undefined } } ; } ) } , clientRequestId : options . requestId , nextMarker : `${ nextMarker || "" }` } ; return response ; } param { string } delimiter param { Models . ContainerListBlobHierarchySegmentOptionalParams } options param { Context } context returns { Promise < Models . ContainerListBlobHierarchySegmentResponse > } memberof public async listBlobHierarchySegment ( delimiter , options , context ) { const blobCtx = new BlobStorageContext ( context ) ; const accountName = blobCtx . account ! ; const containerName = blobCtx . container ! ; await this . metadataStore . checkContainerExist ( context , accountName , containerName ) ; const request = context . request ! ; const marker = options . marker ; delimiter = delimiter === "" ? "/" : delimiter ; options . prefix = options . prefix || "" ; options . marker = options . marker || "" ; let includeSnapshots = false ; let includeUncommittedBlobs = false ; if ( options . include !== undefined ) { options . include . forEach ( element => { if ( Models . ListBlobsIncludeItem . Snapshots . toLowerCase ( ) === element . toLowerCase ( ) ) { includeSnapshots = true ; } if ( Models . ListBlobsIncludeItem . Uncommittedblobs . toLowerCase ( ) === element . toLowerCase ( ) ) { includeUncommittedBlobs = true ; } } ) ; } if ( options . maxresults === undefined || options . maxresults > DEFAULT_LIST_BLOBS_MAX_RESULTS ) { options . maxresults = DEFAULT_LIST_BLOBS_MAX_RESULTS ; } const [ blobs , nextMarker ] = await this . metadataStore . listBlobs ( context , accountName , containerName , undefined , options . prefix , options . maxresults , marker , includeSnapshots , includeUncommittedBlobs ) ; const blobItems = [ ] ; const blobPrefixes = [ ] ; const blobPrefixesSet = new Set < string > ( ) ; const prefixLength = options . prefix . length ; for ( const blob of blobs ) { const delimiterPosAfterPrefix = blob . name . indexOf ( delimiter , prefixLength ) ; if ( delimiterPosAfterPrefix < 0 ) { blob . deleted = blob . deleted !== true ? undefined : true ; blobItems . push ( blob ) ; } else { const prefix = blob . name . substr ( 0 , delimiterPosAfterPrefix + 1 ) ; blobPrefixesSet . add ( prefix ) ; } } const iter = blobPrefixesSet . values ( ) ; let val ; while ( ! ( val = iter . next ( ) ) . done ) { blobPrefixes . push ( { name : val . value } ) ; } const serviceEndpoint = `${ request . getEndpoint ( ) }/${ accountName }` ; const response = { statusCode : 200 , contentType : "application/xml" , requestId : context . contextId , version : BLOB_API_VERSION , date : context . startTime , serviceEndpoint , containerName , prefix : options . prefix , marker : options . marker , maxResults : options . maxresults , delimiter , segment : { blobPrefixes , blobItems : blobItems . map ( item => { return { ... item , snapshot : item . snapshot || undefined , properties : { ... item . properties , etag : removeQuotationFromListBlobEtag ( item . properties . etag ) , accessTierInferred : item . properties . accessTierInferred === true ? true : undefined } } ; } ) } , clientRequestId : options . requestId , nextMarker : `${ nextMarker || "" }` } ; return response ; } param { Context } context returns { Promise < Models . ContainerGetAccountInfoResponse > } memberof public async getAccountInfo ( context ) { const response = { statusCode : 200 , requestId : context . contextId , clientRequestId : context . request ! . getHeader ( "x-ms-client-request-id" ) , skuName : EMULATOR_ACCOUNT_SKUNAME , accountKind : EMULATOR_ACCOUNT_KIND , date : context . startTime ! , version : BLOB_API_VERSION } ; return response ; } param { Context } context returns { Promise < Models . ContainerGetAccountInfoResponse > } memberof public async getAccountInfoWithHead ( context ) { return this . getAccountInfo ( context ) ; } }