alibabacloud-gateway-oss/main.tea (446 lines of code) (raw):

import SPI; import Credential; import Util; import OSSUtil; import OpenApiUtil; import XML; import String; import Map; import Array; import EncodeUtil; import SignatureUtil; import Time; import OSS_Util; extends SPI; type @default_signed_params = [ string ] type @except_signed_params = [ string ] init(){ super(); @default_signed_params = [ 'response-content-type', 'response-content-language', 'response-cache-control', 'logging', 'response-content-encoding', 'acl', 'uploadId', 'uploads', 'partNumber', 'group', 'link', 'delete', 'website', 'location', 'objectInfo', 'objectMeta', 'response-expires', 'response-content-disposition', 'cors', 'lifecycle', 'restore', 'qos', 'referer', 'stat', 'bucketInfo', 'append', 'position', 'security-token', 'live', 'comp', 'status', 'vod', 'startTime', 'endTime', 'x-oss-process', 'symlink', 'callback', 'callback-var', 'tagging', 'encryption', 'versions', 'versioning', 'versionId', 'policy', 'requestPayment', 'x-oss-traffic-limit', 'qosInfo', 'asyncFetch', 'x-oss-request-payer', 'sequential', 'inventory', 'inventoryId', 'continuation-token', 'callback', 'callback-var', 'worm', 'wormId', 'wormExtend', 'replication', 'replicationLocation', 'replicationProgress', 'transferAcceleration', 'cname', 'metaQuery', 'x-oss-ac-source-ip', 'x-oss-ac-subnet-mask', 'x-oss-ac-vpc-id', 'x-oss-ac-forward-allow', 'resourceGroup', 'style', 'styleName', 'x-oss-async-process', 'rtc', 'accessPoint', 'accessPointPolicy', "httpsConfig", 'regionsV2', 'publicAccessBlock', 'policyStatus', 'redundancyTransition', 'redundancyType', 'redundancyProgress', 'dataAccelerator', 'verbose', 'accessPointForObjectProcess', 'accessPointConfigForObjectProcess', 'accessPointPolicyForObjectProcess', 'bucketArchiveDirectRead', 'responseHeader', 'userDefinedLogFieldsConfig', 'reservedcapacity', 'requesterQosInfo', 'qosRequester', 'resourcePool', 'resourcePoolInfo', 'resourcePoolBuckets', 'processConfiguration', 'img', 'asyncFetch', 'virtualBucket', 'copy', 'userRegion', 'partSize', 'chunkSize', 'partUploadId', 'chunkNumber', 'userRegion', 'regionList', 'eventnotification', 'cacheConfiguration', 'dfs', 'dfsadmin', 'dfssecurity' ]; @except_signed_params = ['list-type', 'regions']; } async function modifyConfiguration(context: SPI.InterceptorContext, attributeMap: SPI.AttributeMap): void { var config = context.configuration; config.endpoint = getEndpoint(config.regionId, config.network, config.endpoint); } async function modifyRequest(context: SPI.InterceptorContext, attributeMap: SPI.AttributeMap): void { var request = context.request; var hostMap : map[string]string = {}; if (!Util.isUnset(request.hostMap)) { hostMap = request.hostMap; } var bucketName = hostMap.bucket; if (Util.isUnset(bucketName)) { bucketName = ''; } if (!Util.isUnset(request.headers['x-oss-meta-*'])) { var tmp : any = Util.parseJSON(request.headers['x-oss-meta-*']); var mapData : map[string]any = Util.assertAsMap(tmp); var metaData : map[string]string = Util.stringifyMapValue(mapData); var metaKeySet : [string] = Map.keySet(metaData); request.headers['x-oss-meta-*'] = null; for(var key : metaKeySet) { var newKey = `x-oss-meta-${key}`; request.headers[newKey] = metaData[key]; } } var config = context.configuration; var regionId = config.regionId; if (Util.isUnset(regionId) || Util.empty(regionId)) { regionId = getRegionIdFromEndpoint(config.endpoint); } var credential : Credential = request.credential; var accessKeyId = credential.getAccessKeyId(); var accessKeySecret = credential.getAccessKeySecret(); var securityToken = credential.getSecurityToken(); if (!Util.empty(securityToken)) { request.headers.x-oss-security-token = securityToken; } if (!Util.isUnset(request.body)) { if (String.equals(request.reqBodyType, 'xml')) { var reqBodyMap = Util.assertAsMap(request.body); // for python: // xml_str = OSS_UtilClient.to_xml(req_body_map) var xmlStr = XML.toXML(reqBodyMap); request.stream = xmlStr; request.headers.content-type = 'application/xml'; request.headers.content-md5 = EncodeUtil.base64EncodeToString(SignatureUtil.MD5Sign(xmlStr)); } else if (String.equals(request.reqBodyType, 'json')) { var reqBodyStr = Util.toJSONString(request.body); request.stream = reqBodyStr; request.headers.content-type = 'application/json; charset=utf-8'; } else if (String.equals(request.reqBodyType, 'formData')) { var reqBodyForm = Util.assertAsMap(request.body); request.stream = OpenApiUtil.toForm(reqBodyForm); request.headers.content-type = 'application/x-www-form-urlencoded'; } else if (String.equals(request.reqBodyType, 'binary')) { attributeMap.key = { crc = '', md5 = '', }; request.stream = OSSUtil.inject(request.stream, attributeMap.key); request.headers.content-type = 'application/octet-stream'; } } var host = getHost(config.endpointType, bucketName, config.endpoint, context); request.headers = { host = host, date = Util.getDateUTCString(), user-agent = request.userAgent, ...request.headers }; var originPath = request.pathname; var originQuery = request.query; if (!Util.empty(originPath)) { var pathAndQueries : [string] = String.split(originPath, `?`, 2); request.pathname = pathAndQueries[0]; if (Util.equalNumber(Array.size(pathAndQueries), 2)) { var pathQueries : [string] = String.split(pathAndQueries[1], '&', null); for (var sub : pathQueries) { var item : [string] = String.split(sub, '=', null); var queryKey : string = item[0]; var queryValue : string = ''; if (Util.equalNumber(Array.size(item), 2)) { queryValue = item[1]; } if (Util.empty(originQuery[queryKey])) { request.query[queryKey] = queryValue; } } } } var signatureVersion = Util.defaultString(request.signatureVersion, 'v4'); request.headers.authorization = getAuthorization(signatureVersion, bucketName, request.pathname, request.method, request.query, request.headers, accessKeyId, accessKeySecret, regionId); } async function modifyResponse(context: SPI.InterceptorContext, attributeMap: SPI.AttributeMap): void { var request = context.request; var response = context.response; var bodyStr : string = null; if (Util.is4xx(response.statusCode) || Util.is5xx(response.statusCode)) { bodyStr = Util.readAsString(response.body); if (!Util.empty(bodyStr)) { var respMap : map[string]any = XML.parseXml(bodyStr, null); var err : map[string]any = Util.assertAsMap(respMap.Error); throw { code = err.Code, message = err.Message, data = { statusCode = response.statusCode, requestId = err.RequestId, ecCode = err.EC, Recommend = err.RecommendDoc, hostId = err.HostId, AccessDeniedDetail = err.AccessDeniedDetail, } }; } else { var headers : map[string]string = response.headers; var requestId = headers.x-oss-request-id; var ecCode = headers.x-oss-ec-code; throw { code = response.statusCode, message = null, data = { statusCode = response.statusCode, requestId = `${requestId}`, ecCode = ecCode, } }; } } var ctx : map[string]string = attributeMap.key; if (!Util.isUnset(ctx)) { if (!Util.isUnset(ctx.crc) && !Util.isUnset(response.headers.x-oss-hash-crc64ecma) && !String.equals(ctx.crc, response.headers.x-oss-hash-crc64ecma)) { throw { code = 'CrcNotMatched', data = { clientCrc = ctx.crc, serverCrc = response.headers.x-oss-hash-crc64ecma, }, }; } if (!Util.isUnset(ctx.md5) && !Util.isUnset(response.headers.content-md5) && !String.equals(ctx.md5, response.headers.content-md5)) { throw { code = 'MD5NotMatched', data = { clientMD5 = ctx.md5, serverMD5 = response.headers.content-md5, }, }; } } if (!Util.isUnset(response.body)) { if (Util.equalNumber(response.statusCode, 204)) { Util.readAsString(response.body); } else if (String.equals(request.bodyType, 'xml')) { bodyStr = Util.readAsString(response.body); response.deserializedBody = bodyStr; if (!Util.empty(bodyStr)) { var result : any = OSS_Util.parseXml(bodyStr, request.action); // for no util language // var result : any = XML.parseXml(bodyStr, null); try { response.deserializedBody = Util.assertAsMap(result); } catch (error) { response.deserializedBody = result; } } } else if (Util.equalString(request.bodyType, 'binary')) { response.deserializedBody = response.body; } else if (Util.equalString(request.bodyType, 'byte')) { var byt = Util.readAsBytes(response.body); response.deserializedBody = byt; } else if (Util.equalString(request.bodyType, 'string')) { response.deserializedBody = Util.readAsString(response.body); } else if (Util.equalString(request.bodyType, 'json')) { var obj = Util.readAsJSON(response.body); var res = Util.assertAsMap(obj); response.deserializedBody = res; } else if (Util.equalString(request.bodyType, 'array')) { response.deserializedBody = Util.readAsJSON(response.body); } else { response.deserializedBody = Util.readAsString(response.body); } } } async function getRegionIdFromEndpoint(endpoint: string) : string { if (!Util.empty(endpoint)) { var idx: integer = -1; if (String.hasPrefix(endpoint, 'oss-') && String.hasSuffix(endpoint, '.aliyuncs.com')) { idx = String.index(endpoint, '.aliyuncs.com'); return String.subString(endpoint, 4, idx); } if (String.hasSuffix(endpoint, '.mgw.aliyuncs.com')) { idx = String.index(endpoint, '.mgw.aliyuncs.com'); return String.subString(endpoint, 0, idx); } if (String.hasSuffix(endpoint, '.mgw-internal.aliyuncs.com')) { idx = String.index(endpoint, '.mgw-internal.aliyuncs.com'); return String.subString(endpoint, 0, idx); } if (String.hasSuffix(endpoint, '-internal.oss-data-acc.aliyuncs.com')) { idx = String.index(endpoint, '-internal.oss-data-acc.aliyuncs.com'); return String.subString(endpoint, 0, idx); } if (String.hasSuffix(endpoint, '.oss-dls.aliyuncs.com')) { idx = String.index(endpoint, '.oss-dls.aliyuncs.com'); return String.subString(endpoint, 0, idx); } } return 'cn-hangzhou'; } async function getEndpoint(regionId: string, network: string, endpoint: string) : string{ if (!Util.empty(endpoint)) { return endpoint; } if (Util.empty(regionId)) { regionId = 'cn-hangzhou'; } if (!Util.empty(network)) { if (String.contains(network, 'internal')) { return `oss-${regionId}-internal.aliyuncs.com`; } else if (String.contains(network, 'ipv6')) { return `${regionId}oss.aliyuncs.com`; } else if (String.contains(network, 'accelerate')) { return `oss-${network}.aliyuncs.com`; } } return `oss-${regionId}.aliyuncs.com`; } async function getHost(endpointType: string, bucketName: string, endpoint: string, context: SPI.InterceptorContext): string { if (String.contains(endpoint,'.mgw.aliyuncs.com') && !Util.isUnset(context.request.hostMap.userid)) { return `${context.request.hostMap.userid}.${endpoint}`; } if (String.contains(endpoint,'.mgw-internal.aliyuncs.com') && !Util.isUnset(context.request.hostMap.userid)) { return `${context.request.hostMap.userid}.${endpoint}`; } if (Util.empty(bucketName)) { return endpoint; } var host : string = `${bucketName}.${endpoint}`; if (!Util.empty(endpointType)) { if (String.equals(endpointType, 'ip')) { host = `${endpoint}/${bucketName}`; } else if (String.equals(endpointType, 'cname')) { host = endpoint; } } return host; } async function getAuthorization(signatureVersion: string, bucketName: string, pathname: string, method: string, query: map[string]string, headers: map[string]string, ak: string, secret: string, regionId: string): string { var sign : string = ''; if (!Util.isUnset(signatureVersion)) { if (String.equals(signatureVersion, 'v1')) { sign = getSignatureV1(bucketName, pathname, method, query, headers, secret); return `OSS ${ak}:${sign}`; } if (String.equals(signatureVersion, 'v2')) { sign = getSignatureV2(bucketName, pathname, method, query, headers, secret); return `OSS2 AccessKeyId:${ak},Signature:${sign}`; } } var dateTime = OpenApiUtil.getTimestamp(); dateTime = String.replace(dateTime, '-', '', null); dateTime = String.replace(dateTime, ':', '', null); headers.x-oss-date = dateTime; headers.x-oss-content-sha256 = 'UNSIGNED-PAYLOAD'; var onlyDate : string = String.subString(dateTime, 0, 8); var cred : string = `${ak}/${onlyDate}/${regionId}/oss/aliyun_v4_request`; sign = getSignatureV4(bucketName, pathname, method, query, headers, onlyDate, regionId, secret); return `OSS4-HMAC-SHA256 Credential=${cred}, Signature=${sign}`; } async function getSignKey(secret: string, onlyDate: string, regionId: string): bytes { var temp = `aliyun_v4${secret}`; var res = SignatureUtil.HmacSHA256Sign(onlyDate, temp); res = SignatureUtil.HmacSHA256SignByBytes(regionId, res); res = SignatureUtil.HmacSHA256SignByBytes('oss', res); res = SignatureUtil.HmacSHA256SignByBytes('aliyun_v4_request', res); return res; } async function getSignatureV4(bucketName: string, pathname: string, method: string, query: map[string]string, headers: map[string]string, onlyDate: string, regionId: string, secret: string): string { var signingkey : bytes = getSignKey(secret, onlyDate, regionId); var canonicalizedUri : string = pathname; if (!Util.empty(pathname)) { if (!Util.empty(bucketName)) { canonicalizedUri = `/${bucketName}${canonicalizedUri}`; } } else { if (!Util.empty(bucketName)) { canonicalizedUri = `/${bucketName}/`; } else { canonicalizedUri = "/"; } } // for java: // String suffix = (!canonicalizedUri.equals("/") && canonicalizedUri.endsWith("/"))? "/" : ""; // canonicalizedUri = com.aliyun.openapiutil.Client.getEncodePath(canonicalizedUri) + suffix; canonicalizedUri = OpenApiUtil.getEncodePath(canonicalizedUri); var queryMap : map[string]string = {}; for (var queryKey : Map.keySet(query)) { var queryValue : string = null; if (!Util.empty(query[queryKey])) { queryValue = EncodeUtil.percentEncode(query[queryKey]); queryValue = String.replace(queryValue, '+', '%20', null); } queryKey = EncodeUtil.percentEncode(queryKey); queryKey = String.replace(queryKey, '+', '%20', null); // for go : queryMap[tea.StringValue(queryKey)] = queryValue queryMap[queryKey] = queryValue; } var canonicalizedQueryString = buildCanonicalizedQueryStringV4(queryMap); var canonicalizedHeaders = buildCanonicalizedHeadersV4(headers); var payload = 'UNSIGNED-PAYLOAD'; var canonicalRequest = `${method}\n${canonicalizedUri}\n${canonicalizedQueryString}\n${canonicalizedHeaders}\n\n${payload}`; var hex = EncodeUtil.hexEncode(EncodeUtil.hash(Util.toBytes(canonicalRequest), 'ACS4-HMAC-SHA256')); var scope :string = `${onlyDate}/${regionId}/oss/aliyun_v4_request`; var stringToSign = `OSS4-HMAC-SHA256\n${headers.x-oss-date}\n${scope}\n${hex}`; var signature = SignatureUtil.HmacSHA256SignByBytes(stringToSign, signingkey); return EncodeUtil.hexEncode(signature); } async function buildCanonicalizedQueryStringV4(queryMap: map[string]string): string { var canonicalizedQueryString : string = ''; if (!Util.isUnset(queryMap)) { var queryArray : [string] = Map.keySet(queryMap); var sortedQueryArray = Array.ascSort(queryArray); var separator : string = ''; for(var key : sortedQueryArray) { canonicalizedQueryString = `${canonicalizedQueryString}${separator}${key}`; if (!Util.empty(queryMap[key])) { canonicalizedQueryString = `${canonicalizedQueryString}=${queryMap[key]}`; } separator = '&'; } } return canonicalizedQueryString; } async function buildCanonicalizedHeadersV4(headers: map[string]string): string { var canonicalizedHeaders : string = ''; var headersArray : [string] = Map.keySet(headers); var sortedHeadersArray = Array.ascSort(headersArray); for(var key : sortedHeadersArray) { var lowerKey = String.toLower(key); if (String.hasPrefix(lowerKey, 'x-oss-') || String.equals(lowerKey, 'content-type') || String.equals(lowerKey, 'content-md5')) { canonicalizedHeaders = `${canonicalizedHeaders}${key}:${String.trim(headers[key])}\n`; } } return canonicalizedHeaders; } async function getSignatureV1(bucketName: string, pathname: string, method: string, query: map[string]string, headers: map[string]string, secret: string): string { var resource : string = ''; var stringToSign : string = ''; if (!Util.empty(bucketName)) { resource = `/${bucketName}`; } resource = `${resource}${pathname}`; var canonicalizedResource = buildCanonicalizedResource(resource, query); var canonicalizedHeaders = buildCanonicalizedHeaders(headers); stringToSign = `${method}\n${canonicalizedHeaders}${canonicalizedResource}`; return EncodeUtil.base64EncodeToString(SignatureUtil.HmacSHA1Sign(stringToSign, secret)); } async function buildCanonicalizedResource(pathname: string, query: map[string]string): string { var canonicalizedResource : string = pathname; var queryKeys : [string] = Map.keySet(query); var sortedParams = Array.ascSort(queryKeys); var separator : string = '?'; for(var paramName : sortedParams) { if (Array.contains(@default_signed_params, paramName) || String.hasPrefix(paramName, 'x-oss-')) { canonicalizedResource = `${canonicalizedResource}${separator}${paramName}`; if (!Util.empty(query[paramName])) { canonicalizedResource = `${canonicalizedResource}=${query[paramName]}`; } separator = '&'; } } return canonicalizedResource; } async function buildCanonicalizedHeaders(headers: map[string]string): string { var canonicalizedHeaders : string = ''; var contentType = headers.content-type; if (Util.isUnset(contentType)) { contentType = ''; } var contentMd5 = headers.content-md5; if (Util.isUnset(contentMd5)) { contentMd5 = ''; } canonicalizedHeaders = `${canonicalizedHeaders}${contentMd5}\n${contentType}\n${headers.date}\n`; var keys = Map.keySet(headers); var sortedHeaders = Array.ascSort(keys); for(var header : sortedHeaders) { if (String.contains(String.toLower(header), 'x-oss-') && !Util.isUnset(headers[header])) { canonicalizedHeaders = `${canonicalizedHeaders}${header}:${headers[header]}\n`; } } return canonicalizedHeaders; } async function getSignatureV2(bucketName: string, pathname: string, method: string, query: map[string]string, headers: map[string]string, secret: string): string { return ''; }