in src/blob/handlers/BlockBlobHandler.ts [169:266]
public async stageBlock(
blockId: string,
contentLength: number,
body: NodeJS.ReadableStream,
options: Models.BlockBlobStageBlockOptionalParams,
context: Context
): Promise<Models.BlockBlobStageBlockResponse> {
const blobCtx = new BlobStorageContext(context);
const accountName = blobCtx.account!;
const containerName = blobCtx.container!;
const blobName = blobCtx.blob!;
const date = blobCtx.startTime!;
// stageBlock operation doesn't have blobHTTPHeaders
// https://learn.microsoft.com/en-us/rest/api/storageservices/put-block
// options.blobHTTPHeaders = options.blobHTTPHeaders || {};
const contentMD5 = context.request!.getHeader("content-md5")
|| context.request!.getHeader("x-ms-blob-content-md5")
? options.transactionalContentMD5 ||
context.request!.getHeader("content-md5")
: undefined;
this.validateBlockId(blockId, blobCtx);
await this.metadataStore.checkContainerExist(
context,
accountName,
containerName
);
const persistency = await this.extentStore.appendExtent(
body,
context.contextId
);
if (persistency.count !== contentLength) {
// TODO: Confirm error code
throw StorageErrorFactory.getInvalidOperation(
blobCtx.contextId!,
`The size of the request body ${persistency.count} mismatches the content-length ${contentLength}.`
);
}
// Calculate MD5 for validation
const stream = await this.extentStore.readExtent(
persistency,
context.contextId
);
const calculatedContentMD5 = await getMD5FromStream(stream);
if (contentMD5 !== undefined) {
if (typeof contentMD5 === "string") {
const calculatedContentMD5String = Buffer.from(
calculatedContentMD5
).toString("base64");
if (contentMD5 !== calculatedContentMD5String) {
throw StorageErrorFactory.getInvalidOperation(
context.contextId!,
"Provided contentMD5 doesn't match."
);
}
} else {
if (!Buffer.from(contentMD5).equals(calculatedContentMD5)) {
throw StorageErrorFactory.getInvalidOperation(
context.contextId!,
"Provided contentMD5 doesn't match."
);
}
}
}
const block: BlockModel = {
accountName,
containerName,
blobName,
isCommitted: false,
name: blockId,
size: contentLength,
persistency
};
// TODO: Verify it.
await this.metadataStore.stageBlock(
context,
block,
options.leaseAccessConditions
);
const response: Models.BlockBlobStageBlockResponse = {
statusCode: 201,
contentMD5: undefined, // TODO: Block content MD5
requestId: blobCtx.contextId,
version: BLOB_API_VERSION,
date,
isServerEncrypted: true,
clientRequestId: options.requestId
};
return response;
}