Last active
February 17, 2022 22:09
-
-
Save jeremymeng/36c8162b65fe8945c8dae59061d9ce1d to your computer and use it in GitHub Desktop.
workaround for @azure/blob-storage metadata from getProperties() casing issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { | |
BlobServiceClient, | |
ContainerClient, | |
StorageSharedKeyCredential, | |
} from "@azure/storage-blob"; | |
import { ExampleHttpClient } from "./exampleHttpClient.js"; | |
import * as dotenv from "dotenv"; | |
dotenv.config(); | |
async function main() { | |
const accountName = process.env.ACCOUNT_NAME || "<account name>"; | |
const accountKey = process.env.ACCOUNT_KEY || "<account key>"; | |
const containerName = process.env.CONTAINER_NAME || "<container name>"; | |
const sharedKeyCredential = new StorageSharedKeyCredential( | |
accountName, | |
accountKey | |
); | |
const url = `https://${accountName}.blob.core.windows.net/`; | |
const serviceClient = new BlobServiceClient(url, sharedKeyCredential); | |
const containerClient = serviceClient.getContainerClient(containerName); | |
const properties1 = await containerClient.getProperties(); | |
console.log("metadata retrieved:"); | |
console.log(properties1.metadata); | |
const getPropertiesClient = new ContainerClient( | |
containerClient.url, | |
sharedKeyCredential, | |
{ | |
httpClient: new ExampleHttpClient(), | |
} | |
); | |
const properties2 = await getPropertiesClient.getProperties(); | |
console.log("metadata retrieved with custom http client:"); | |
console.log(properties2.metadata); | |
await containerClient.setMetadata({ ...properties2.metadata, caseSensitiveKey: "camelCaseValue" }); | |
const properties3 = await getPropertiesClient.getProperties(); | |
console.log("metadata retrieved with custom http client after setting metadata:"); | |
console.log(properties3.metadata); | |
} | |
main().catch((e) => { | |
console.log("error occurred"); | |
console.log(e); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Copyright (c) Microsoft Corporation. | |
// Licensed under the MIT license. | |
/** | |
* @summary This sample demonstrates how to implement a custom HttpClient. | |
*/ | |
import * as http from "http"; | |
import * as https from "https"; | |
import { | |
HttpClient, | |
HttpHeaders, | |
HttpHeadersLike, | |
HttpOperationResponse, | |
RestError, | |
WebResourceLike, | |
} from "@azure/core-http"; | |
/** | |
* A custom HttpClient that uses `https` to send request and preserve | |
* the casing of 'x-ms-*' http header names. | |
* NOTE: this is for demostrantion purpose only and is not a complete implementation. | |
*/ | |
export class ExampleHttpClient implements HttpClient { | |
private httpsKeepAliveAgent?: https.Agent; | |
public async sendRequest( | |
httpRequest: WebResourceLike | |
): Promise<HttpOperationResponse> { | |
let body = httpRequest.body | |
? typeof httpRequest.body === "function" | |
? httpRequest.body() | |
: httpRequest.body | |
: undefined; | |
const result = await new Promise<HttpOperationResponse>( | |
(resolve, reject) => { | |
const req = this.makeRequest(httpRequest, async (res) => { | |
const status = res.statusCode ?? 0; | |
const httpHeaders = parseHeaders(res.rawHeaders); | |
const response: HttpOperationResponse = { | |
status, | |
headers: httpHeaders, | |
request: httpRequest, | |
}; | |
response.bodyAsText = await streamToText(res); | |
resolve(response); | |
}); | |
req.on("error", (err) => { | |
reject( | |
new RestError( | |
err.message, | |
RestError.REQUEST_SEND_ERROR, | |
undefined, | |
httpRequest | |
) | |
); | |
}); | |
if (body && isReadableStream(body)) { | |
body.pipe(req); | |
} else if (body) { | |
req.end(body); | |
} else { | |
// streams don't like "undefined" being passed as data | |
req.end(); | |
} | |
} | |
); | |
return result; | |
} | |
private makeRequest( | |
request: WebResourceLike, | |
callback: (res: http.IncomingMessage) => void | |
): http.ClientRequest { | |
const url = new URL(request.url); | |
const agent = this.getOrCreateAgent(request?.keepAlive ?? true); | |
const realHeaders = request.headers.rawHeaders(); | |
const options: http.RequestOptions = { | |
agent, | |
hostname: url.hostname, | |
path: `${url.pathname}${url.search}`, | |
port: url.port, | |
method: request.method, | |
headers: realHeaders, | |
}; | |
return https.request(options, callback); | |
} | |
private getOrCreateAgent(keepAlive: boolean): https.Agent { | |
if (keepAlive) { | |
if (!this.httpsKeepAliveAgent) { | |
this.httpsKeepAliveAgent = new https.Agent({ | |
keepAlive: true, | |
}); | |
} | |
return this.httpsKeepAliveAgent; | |
} else { | |
return https.globalAgent; | |
} | |
} | |
} | |
function streamToText(stream: NodeJS.ReadableStream): Promise<string> { | |
return new Promise<string>((resolve, reject) => { | |
const buffer: Buffer[] = []; | |
stream.on("data", (chunk) => { | |
if (Buffer.isBuffer(chunk)) { | |
buffer.push(chunk); | |
} else { | |
buffer.push(Buffer.from(chunk)); | |
} | |
}); | |
stream.on("end", () => { | |
resolve(Buffer.concat(buffer).toString("utf8")); | |
}); | |
stream.on("error", (e) => { | |
reject( | |
new RestError( | |
`Error reading response as text: ${e.message}`, | |
RestError.PARSE_ERROR | |
) | |
); | |
}); | |
}); | |
} | |
export function parseHeaders( | |
rawHeaders: string[] | |
): HttpHeadersLike { | |
const httpHeaders = new HttpHeaders(); | |
for (let i = 0; i < rawHeaders.length; i += 2) { | |
httpHeaders.set(rawHeaders[i], rawHeaders[i + 1]); | |
} | |
return httpHeaders; | |
} | |
function isReadableStream(body: any): body is NodeJS.ReadableStream { | |
return body && typeof body.pipe === "function"; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment