oss-client
Version:
Aliyun OSS(Object Storage Service) Node.js Client
323 lines • 24.3 kB
JavaScript
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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