UNPKG

oss-client

Version:

Aliyun OSS(Object Storage Service) Node.js Client

323 lines 24.3 kB
import { debuglog } from 'node:util'; import assert from 'node:assert'; import { createHash } from 'node:crypto'; import { extname } from 'node:path'; import { sendToWormhole } from 'stream-wormhole'; import { parseStringPromise } from 'xml2js'; import { encodeURIComponent as safeEncodeURIComponent } from 'utility'; import mime from 'mime'; import { HttpClient, } from 'urllib'; import ms from 'ms'; import { authorization, buildCanonicalString, computeSignature, } from './util/index.js'; import { OSSClientError } from './error/index.js'; const debug = debuglog('oss-client:client'); export class OSSBaseClient { #httpClient = new HttpClient(); #userAgent; options; constructor(options) { this.options = this.#initOptions(options); this.#userAgent = this.#getUserAgent(); } /** public methods */ /** * get OSS signature */ signature(stringToSign) { debug('authorization stringToSign: %s', stringToSign); return computeSignature(this.options.accessKeySecret, stringToSign); } /** protected methods */ /** * get author header * * "Authorization: OSS " + Access Key Id + ":" + Signature * * Signature = base64(hmac-sha1(Access Key Secret + "\n" * + VERB + "\n" * + CONTENT-MD5 + "\n" * + CONTENT-TYPE + "\n" * + DATE + "\n" * + CanonicalizedOSSHeaders * + CanonicalizedResource)) */ authorization(method, resource, headers, subResource) { const stringToSign = buildCanonicalString(method.toUpperCase(), resource, { headers, parameters: subResource, }); debug('stringToSign: %o', stringToSign); const auth = authorization(this.options.accessKeyId, this.options.accessKeySecret, stringToSign); debug('authorization: %o', auth); return auth; } /** * encodeURIComponent name except '/' */ escape(name) { return safeEncodeURIComponent(name).replaceAll('%2F', '/'); } getRequestURL(params) { let resourcePath = '/'; if (params.object) { // Preserve '/' in result url resourcePath += this.escape(params.object).replaceAll('+', '%2B'); } const urlObject = new URL(this.getRequestEndpoint()); urlObject.pathname = resourcePath; if (params.query) { const query = params.query; for (const key in query) { const value = query[key]; urlObject.searchParams.set(key, `${value}`); } } if (params.subResource) { let subresAsQuery = {}; if (typeof params.subResource === 'string') { subresAsQuery[params.subResource] = ''; } else if (Array.isArray(params.subResource)) { for (const k of params.subResource) { subresAsQuery[k] = ''; } } else { subresAsQuery = params.subResource; } for (const key in subresAsQuery) { urlObject.searchParams.set(key, `${subresAsQuery[key]}`); } } return urlObject.toString(); } getResource(params) { let resource = '/'; if (params.bucket) resource += `${params.bucket}/`; if (params.object) resource += params.object; return resource; } createHttpClientRequestParams(params) { const headers = { ...params.headers, // https://help.aliyun.com/zh/oss/developer-reference/include-signatures-in-the-authorization-header // 此次操作的时间,Date必须为GMT格式,且不能为空。该值取自请求头的Date字段或者x-oss-date字段。当这两个字段同时存在时,以x-oss-date为准。 // e.g.: Sun, 22 Nov 2015 08:16:38 GMT 'x-oss-date': new Date().toUTCString(), 'user-agent': this.#userAgent, }; if (this.options.isRequestPay) { headers['x-oss-request-payer'] = 'requester'; } if (!headers['content-type']) { let contentType = null; if (params.mime) { if (params.mime.includes('/')) { contentType = params.mime; } else { contentType = mime.getType(params.mime); } } else if (params.object) { contentType = mime.getType(extname(params.object)); } if (contentType) { headers['content-type'] = contentType; } } if (params.content) { if (!params.disabledMD5 && !headers['content-md5']) { headers['content-md5'] = createHash('md5') .update(Buffer.from(params.content)) .digest('base64'); } if (!headers['content-length']) { headers['content-length'] = `${params.content.length}`; } } const authResource = this.getResource(params); headers.authorization = this.authorization(params.method, authResource, headers, params.subResource); const url = this.getRequestURL(params); debug('request %s %s, with headers %j, !!stream: %s', params.method, url, headers, !!params.stream); const timeout = params.timeout ?? this.options.timeout; const options = { method: params.method, content: params.content, stream: params.stream, headers, timeout, writeStream: params.writeStream, timing: true, }; if (params.streaming) { options.dataType = 'stream'; } return { url, options }; } /** * request oss server */ // eslint-disable-next-line no-explicit-any async request(params) { const { url, options } = this.createHttpClientRequestParams(params); const result = await this.#httpClient.request(url, options); debug('response %s %s, got %s, headers: %j', params.method, url, result.status, result.headers); if (!params.successStatuses?.includes(result.status)) { const err = await this.#createClientException(result); if (params.streaming && result.res) { // consume the response stream await sendToWormhole(result.res); } throw err; } let data = result.data; if (params.xmlResponse) { data = await this.#xml2json(result.data); } return { data, res: result.res, }; } /** private methods */ #initOptions(options) { assert.ok(options.accessKeyId && options.accessKeySecret, 'require accessKeyId and accessKeySecret'); assert.ok(options.endpoint, 'require endpoint'); let timeout = 60_000; if (options.timeout) { if (typeof options.timeout === 'string') { timeout = ms(options.timeout); } else { timeout = options.timeout; } } const initOptions = { accessKeyId: options.accessKeyId.trim(), accessKeySecret: options.accessKeySecret.trim(), endpoint: options.endpoint, region: options.region ?? 'oss-cn-hangzhou', internal: options.internal ?? false, isRequestPay: options.isRequestPay ?? false, timeout, }; return initOptions; } /** * Get User-Agent for Node.js * @example * oss-client/2.0.0 Node.js/5.3.0 (darwin; arm64) */ #getUserAgent() { // TODO: should read version from package.json const sdk = 'oss-client/2.0.0'; const platform = `Node.js/${process.version.slice(1)} (${process.platform}; ${process.arch})`; return `${sdk} ${platform}`; } // eslint-disable-next-line no-explicit-any async #xml2json(xml) { if (Buffer.isBuffer(xml)) { xml = xml.toString(); } debug('xml2json %o', xml); return (await parseStringPromise(xml, { explicitRoot: false, explicitArray: false, })); } async #createClientException(result) { let err; let requestId = result.headers['x-oss-request-id'] ?? ''; let hostId = ''; const status = result.status; if (!result.data || result.data.length === 0) { // HEAD not exists resource if (status === 404) { err = new OSSClientError(status, 'NoSuchKey', 'Object not exists', requestId, hostId); } else if (status === 412) { err = new OSSClientError(status, 'PreconditionFailed', 'Pre condition failed', requestId, hostId); } else { err = new OSSClientError(status, 'Unknown', `Unknown error, status=${status}, raw error=${result}`, requestId, hostId); } } else { const xml = result.data.toString(); debug('request response error xml: %o', xml); let info; try { info = await this.#xml2json(xml); } catch (e) { const message = e instanceof Error ? e.message : String(e); err = new OSSClientError(status, 'PreconditionFailed', `${message} (raw xml=${JSON.stringify(xml)})`, requestId, hostId); return err; } let message = info?.Message ?? `Unknown request error, status=${result.status}, raw xml=${JSON.stringify(xml)}`; if (info?.Condition) { message += ` (condition=${info.Condition})`; } if (info?.RequestId) { requestId = info.RequestId; } if (info?.HostId) { hostId = info.HostId; } err = new OSSClientError(status, info?.Code ?? 'Unknown', message, requestId, hostId); // https://help.aliyun.com/zh/oss/support/http-status-code-409#section-rmc-hvd-j38 if (info?.Code === 'PositionNotEqualToLength' && result.headers['x-oss-next-append-position']) { err.nextAppendPosition = result.headers['x-oss-next-append-position']; } } debug('generate error %o', err); return err; } } // /** // * Object operations // */ // merge(proto, require('./common/object')); // merge(proto, require('./object')); // merge(proto, require('./common/image')); // /** // * Bucket operations // */ // merge(proto, require('./common/bucket')); // merge(proto, require('./bucket')); // // multipart upload // merge(proto, require('./managed-upload')); // /** // * RTMP operations // */ // merge(proto, require('./rtmp')); // /** // * common multipart-copy // */ // merge(proto, require('./common/multipart-copy')); // /** // * Common module parallel // */ // merge(proto, require('./common/parallel')); // /** // * Multipart operations // */ // merge(proto, require('./common/multipart')); // /** // * ImageClient class // */ // Client.ImageClient = require('./image')(Client); // /** // * Cluster Client class // */ // Client.ClusterClient = require('./cluster')(Client); // /** // * STS Client class // */ // Client.STS = require('./sts'); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT1NTQmFzZUNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9PU1NCYXNlQ2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDckMsT0FBTyxNQUFNLE1BQU0sYUFBYSxDQUFDO0FBQ2pDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDekMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUVwQyxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDakQsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sUUFBUSxDQUFDO0FBQzVDLE9BQU8sRUFBRSxrQkFBa0IsSUFBSSxzQkFBc0IsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUN2RSxPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFDeEIsT0FBTyxFQUlMLFVBQVUsR0FDWCxNQUFNLFFBQVEsQ0FBQztBQUNoQixPQUFPLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDcEIsT0FBTyxFQUNMLGFBQWEsRUFDYixvQkFBb0IsRUFDcEIsZ0JBQWdCLEdBQ2pCLE1BQU0saUJBQWlCLENBQUM7QUFNekIsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGtCQUFrQixDQUFDO0FBRWxELE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBMkI1QyxNQUFNLE9BQWdCLGFBQWE7SUFDeEIsV0FBVyxHQUFHLElBQUksVUFBVSxFQUFFLENBQUM7SUFDL0IsVUFBVSxDQUFTO0lBQ1QsT0FBTyxDQUF1QjtJQUVqRCxZQUFZLE9BQWlDO1FBQzNDLElBQUksQ0FBQyxPQUFPLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxQyxJQUFJLENBQUMsVUFBVSxHQUFHLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQztJQUN6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