diff --git a/alibabacloud-gateway-oss/golang/client/client.go b/alibabacloud-gateway-oss/golang/client/client.go index ee05ff82..f80a4db7 100644 --- a/alibabacloud-gateway-oss/golang/client/client.go +++ b/alibabacloud-gateway-oss/golang/client/client.go @@ -585,9 +585,9 @@ func (client *Client) BuildCanonicalizedResource(pathname *string, query map[str canonicalizedResource = tea.String(tea.StringValue(canonicalizedResource) + "=" + tea.StringValue(query[tea.StringValue(paramName)])) } + separator = tea.String("&") } - separator = tea.String("&") } _result = canonicalizedResource return _result, _err diff --git a/alibabacloud-gateway-oss/golang/go.mod b/alibabacloud-gateway-oss/golang/go.mod index 73d984b1..ea9501d8 100644 --- a/alibabacloud-gateway-oss/golang/go.mod +++ b/alibabacloud-gateway-oss/golang/go.mod @@ -3,8 +3,8 @@ module github.com/alibabacloud-go/alibabacloud-gateway-oss go 1.14 require ( - github.com/alibabacloud-go/alibabacloud-gateway-oss-util v0.0.3 - github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 + github.com/alibabacloud-go/alibabacloud-gateway-oss-util v0.0.4 + github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 github.com/alibabacloud-go/darabonba-array v0.1.0 github.com/alibabacloud-go/darabonba-encode-util v0.0.2 github.com/alibabacloud-go/darabonba-map v0.0.2 @@ -13,8 +13,8 @@ require ( github.com/alibabacloud-go/openapi-util v0.1.0 github.com/alibabacloud-go/tea v1.1.17 github.com/alibabacloud-go/tea-oss-utils v1.1.0 - github.com/alibabacloud-go/tea-utils/v2 v2.0.5 + github.com/alibabacloud-go/tea-utils/v2 v2.0.6 github.com/alibabacloud-go/tea-xml v1.1.3 - github.com/aliyun/credentials-go v1.3.1 // indirect + github.com/aliyun/credentials-go v1.3.6 // indirect github.com/clbanning/mxj/v2 v2.5.5 // indirect ) diff --git a/alibabacloud-gateway-oss/java/pom.xml b/alibabacloud-gateway-oss/java/pom.xml index 29ef9901..1ad38acc 100644 --- a/alibabacloud-gateway-oss/java/pom.xml +++ b/alibabacloud-gateway-oss/java/pom.xml @@ -49,17 +49,17 @@ com.aliyun alibabacloud-gateway-spi - 0.0.1 + 0.0.2 com.aliyun credentials-java - 0.3.0 + 0.3.6 com.aliyun tea-util - 0.2.21 + 0.2.23 com.aliyun diff --git a/alibabacloud-gateway-oss/java/src/main/java/com/aliyun/gateway/oss/Client.java b/alibabacloud-gateway-oss/java/src/main/java/com/aliyun/gateway/oss/Client.java index 30868abf..c1b1c92b 100644 --- a/alibabacloud-gateway-oss/java/src/main/java/com/aliyun/gateway/oss/Client.java +++ b/alibabacloud-gateway-oss/java/src/main/java/com/aliyun/gateway/oss/Client.java @@ -506,9 +506,9 @@ public String buildCanonicalizedResource(String pathname, java.util.Map str: + if not UtilClient.empty(endpoint): + if StringClient.has_prefix(endpoint, 'oss-') and StringClient.has_suffix(endpoint, '.aliyuncs.com'): + idx = StringClient.index(endpoint, '.aliyuncs.com') + return StringClient.sub_string(endpoint, 4, idx) + return '' + + async def get_region_id_from_endpoint_async( + self, + endpoint: str, + ) -> str: + if not UtilClient.empty(endpoint): + if StringClient.has_prefix(endpoint, 'oss-') and StringClient.has_suffix(endpoint, '.aliyuncs.com'): + idx = StringClient.index(endpoint, '.aliyuncs.com') + return StringClient.sub_string(endpoint, 4, idx) + return '' + def get_endpoint( self, region_id: str, @@ -471,7 +520,10 @@ def get_host( endpoint_type: str, bucket_name: str, endpoint: str, + context: spi_models.InterceptorContext, ) -> str: + if StringClient.contains(endpoint, '.mgw.aliyuncs.com') and not UtilClient.is_unset(context.request.host_map.get('userid')): + return f"{context.request.host_map.get('userid')}.{endpoint}" if UtilClient.empty(bucket_name): return endpoint host = f'{bucket_name}.{endpoint}' @@ -487,7 +539,10 @@ async def get_host_async( endpoint_type: str, bucket_name: str, endpoint: str, + context: spi_models.InterceptorContext, ) -> str: + if StringClient.contains(endpoint, '.mgw.aliyuncs.com') and not UtilClient.is_unset(context.request.host_map.get('userid')): + return f"{context.request.host_map.get('userid')}.{endpoint}" if UtilClient.empty(bucket_name): return endpoint host = f'{bucket_name}.{endpoint}' @@ -599,21 +654,7 @@ def get_signature_v4( object_name = '/' query_map = {} if not UtilClient.empty(pathname): - paths = StringClient.split(pathname, f'?', 2) - object_name = paths[0] - if UtilClient.equal_number(ArrayClient.size(paths), 2): - sub_resources = StringClient.split(paths[1], '&', None) - for sub in sub_resources: - item = StringClient.split(sub, '=', None) - key = item[0] - key = Encoder.percent_encode(key) - key = StringClient.replace(key, '+', '%20', None) - value = None - if UtilClient.equal_number(ArrayClient.size(item), 2): - value = Encoder.percent_encode(item[1]) - value = StringClient.replace(value, '+', '%20', None) - # for go : queryMap[tea.StringValue(key)] = value - query_map[key] = value + object_name = pathname canonicalized_uri = '/' if not UtilClient.empty(bucket_name): canonicalized_uri = f'/{bucket_name}{object_name}' @@ -655,21 +696,7 @@ async def get_signature_v4_async( object_name = '/' query_map = {} if not UtilClient.empty(pathname): - paths = StringClient.split(pathname, f'?', 2) - object_name = paths[0] - if UtilClient.equal_number(ArrayClient.size(paths), 2): - sub_resources = StringClient.split(paths[1], '&', None) - for sub in sub_resources: - item = StringClient.split(sub, '=', None) - key = item[0] - key = Encoder.percent_encode(key) - key = StringClient.replace(key, '+', '%20', None) - value = None - if UtilClient.equal_number(ArrayClient.size(item), 2): - value = Encoder.percent_encode(item[1]) - value = StringClient.replace(value, '+', '%20', None) - # for go : queryMap[tea.StringValue(key)] = value - query_map[key] = value + object_name = pathname canonicalized_uri = '/' if not UtilClient.empty(bucket_name): canonicalized_uri = f'/{bucket_name}{object_name}' @@ -797,45 +824,16 @@ def build_canonicalized_resource( pathname: str, query: Dict[str, str], ) -> str: - sub_resources_map = {} canonicalized_resource = pathname - if not UtilClient.empty(pathname): - paths = StringClient.split(pathname, f'?', 2) - canonicalized_resource = paths[0] - if UtilClient.equal_number(ArrayClient.size(paths), 2): - sub_resources = StringClient.split(paths[1], '&', None) - for sub in sub_resources: - has_excepts = False - for excepts in self._except_signed_params: - if StringClient.contains(sub, excepts): - has_excepts = True - if not has_excepts: - item = StringClient.split(sub, '=', None) - key = item[0] - value = None - if UtilClient.equal_number(ArrayClient.size(item), 2): - value = item[1] - # for go : subResourcesMap[tea.StringValue(key)] = value - sub_resources_map[key] = value - sub_resources_array = MapClient.key_set(sub_resources_map) - new_query_list = sub_resources_array - if not UtilClient.is_unset(query): - query_list = MapClient.key_set(query) - new_query_list = ArrayClient.concat(query_list, sub_resources_array) - sorted_params = ArrayClient.asc_sort(new_query_list) + query_keys = MapClient.key_set(query) + sorted_params = ArrayClient.asc_sort(query_keys) separator = '?' for param_name in sorted_params: - if ArrayClient.contains(self._default_signed_params, param_name): + if ArrayClient.contains(self._default_signed_params, param_name) or StringClient.has_prefix(param_name, 'x-oss-'): canonicalized_resource = f'{canonicalized_resource}{separator}{param_name}' - if not UtilClient.is_unset(query) and not UtilClient.is_unset(query.get(param_name)): + if not UtilClient.empty(query.get(param_name)): canonicalized_resource = f'{canonicalized_resource}={query.get(param_name)}' - elif not UtilClient.is_unset(sub_resources_map.get(param_name)): - canonicalized_resource = f'{canonicalized_resource}={sub_resources_map.get(param_name)}' - elif ArrayClient.contains(sub_resources_array, param_name): - canonicalized_resource = f'{canonicalized_resource}{separator}{param_name}' - if not UtilClient.is_unset(sub_resources_map.get(param_name)): - canonicalized_resource = f'{canonicalized_resource}={sub_resources_map.get(param_name)}' - separator = '&' + separator = '&' return canonicalized_resource async def build_canonicalized_resource_async( @@ -843,45 +841,16 @@ async def build_canonicalized_resource_async( pathname: str, query: Dict[str, str], ) -> str: - sub_resources_map = {} canonicalized_resource = pathname - if not UtilClient.empty(pathname): - paths = StringClient.split(pathname, f'?', 2) - canonicalized_resource = paths[0] - if UtilClient.equal_number(ArrayClient.size(paths), 2): - sub_resources = StringClient.split(paths[1], '&', None) - for sub in sub_resources: - has_excepts = False - for excepts in self._except_signed_params: - if StringClient.contains(sub, excepts): - has_excepts = True - if not has_excepts: - item = StringClient.split(sub, '=', None) - key = item[0] - value = None - if UtilClient.equal_number(ArrayClient.size(item), 2): - value = item[1] - # for go : subResourcesMap[tea.StringValue(key)] = value - sub_resources_map[key] = value - sub_resources_array = MapClient.key_set(sub_resources_map) - new_query_list = sub_resources_array - if not UtilClient.is_unset(query): - query_list = MapClient.key_set(query) - new_query_list = ArrayClient.concat(query_list, sub_resources_array) - sorted_params = ArrayClient.asc_sort(new_query_list) + query_keys = MapClient.key_set(query) + sorted_params = ArrayClient.asc_sort(query_keys) separator = '?' for param_name in sorted_params: - if ArrayClient.contains(self._default_signed_params, param_name): + if ArrayClient.contains(self._default_signed_params, param_name) or StringClient.has_prefix(param_name, 'x-oss-'): canonicalized_resource = f'{canonicalized_resource}{separator}{param_name}' - if not UtilClient.is_unset(query) and not UtilClient.is_unset(query.get(param_name)): + if not UtilClient.empty(query.get(param_name)): canonicalized_resource = f'{canonicalized_resource}={query.get(param_name)}' - elif not UtilClient.is_unset(sub_resources_map.get(param_name)): - canonicalized_resource = f'{canonicalized_resource}={sub_resources_map.get(param_name)}' - elif ArrayClient.contains(sub_resources_array, param_name): - canonicalized_resource = f'{canonicalized_resource}{separator}{param_name}' - if not UtilClient.is_unset(sub_resources_map.get(param_name)): - canonicalized_resource = f'{canonicalized_resource}={sub_resources_map.get(param_name)}' - separator = '&' + separator = '&' return canonicalized_resource def build_canonicalized_headers( diff --git a/alibabacloud-gateway-oss/python/setup.py b/alibabacloud-gateway-oss/python/setup.py index 52f36814..8df82daa 100644 --- a/alibabacloud-gateway-oss/python/setup.py +++ b/alibabacloud-gateway-oss/python/setup.py @@ -24,7 +24,7 @@ """ setup module for alibabacloud_gateway_oss. -Created on 11/03/2024 +Created on 23/08/2024 @author: Alibaba Cloud SDK """ @@ -37,9 +37,9 @@ URL = "https://github.com/aliyun/alibabacloud-gateway" VERSION = __import__(PACKAGE).__version__ REQUIRES = [ - "alibabacloud_gateway_spi>=0.0.1, <1.0.0", - "alibabacloud_credentials>=0.3.1, <1.0.0", - "alibabacloud_tea_util>=0.3.11, <1.0.0", + "alibabacloud_gateway_spi>=0.0.2, <1.0.0", + "alibabacloud_credentials>=0.3.4, <1.0.0", + "alibabacloud_tea_util>=0.3.13, <1.0.0", "alibabacloud_oss_util>=0.0.5, <1.0.0", "alibabacloud_openapi_util>=0.2.1, <1.0.0", "alibabacloud_tea_xml>=0.0.2, <1.0.0", diff --git a/alibabacloud-gateway-oss/util/python/.gitignore b/alibabacloud-gateway-oss/util/python/.gitignore new file mode 100644 index 00000000..2bcfffae --- /dev/null +++ b/alibabacloud-gateway-oss/util/python/.gitignore @@ -0,0 +1,5 @@ +runtime/ +.idea/ +.vscode/ +__pycache__/ +.pytest_cache/ \ No newline at end of file diff --git a/alibabacloud-gateway-oss/util/python/__init__.py b/alibabacloud-gateway-oss/util/python/__init__.py new file mode 100644 index 00000000..6df8ed02 --- /dev/null +++ b/alibabacloud-gateway-oss/util/python/__init__.py @@ -0,0 +1 @@ +__version__ = '1.1.0' \ No newline at end of file diff --git a/alibabacloud-gateway-oss/util/python/client.py b/alibabacloud-gateway-oss/util/python/client.py new file mode 100644 index 00000000..3dae3aaa --- /dev/null +++ b/alibabacloud-gateway-oss/util/python/client.py @@ -0,0 +1,387 @@ +# -*- coding: utf-8 -*- +# import alibabacloud_tea_xml.client + +from Tea.model import TeaModel +from typing import List, Dict, BinaryIO +from xml.etree import ElementTree +from collections import defaultdict +import inspect +from typing_extensions import get_origin, get_args + + +class Owner(TeaModel): + def __init__( + self, + display_name: str = None, + id: str = None, + ): + self.display_name = display_name + self.id = id + + def validate(self): + pass + + def to_map(self): + _map = super().to_map() + if _map is not None: + return _map + + result = dict() + if self.display_name is not None: + result['DisplayName'] = self.display_name + if self.id is not None: + result['ID'] = self.id + return result + + def from_map(self, m: dict = None): + m = m or dict() + if m.get('DisplayName') is not None: + self.display_name = m.get('DisplayName') + if m.get('ID') is not None: + self.id = m.get('ID') + return self + + +class CommonPrefix(TeaModel): + def __init__( + self, + prefix: str = None, + ): + self.prefix = prefix + + def validate(self): + pass + + def to_map(self): + _map = super().to_map() + if _map is not None: + return _map + + result = dict() + if self.prefix is not None: + result['Prefix'] = self.prefix + return result + + def from_map(self, m: dict = None): + m = m or dict() + if m.get('Prefix') is not None: + self.prefix = m.get('Prefix') + return self + + +class ObjectSummary(TeaModel): + def __init__( + self, + etag: str = None, + key: str = None, + last_modified: str = None, + owner: Owner = None, + resore_info: str = None, + size: int = None, + storage_class: str = None, + type: str = None, + ): + self.etag = etag + self.key = key + self.last_modified = last_modified + self.owner = owner + self.resore_info = resore_info + self.size = size + self.storage_class = storage_class + self.type = type + + def validate(self): + if self.owner: + self.owner.validate() + + def to_map(self): + _map = super().to_map() + if _map is not None: + return _map + + result = dict() + if self.etag is not None: + result['ETag'] = self.etag + if self.key is not None: + result['Key'] = self.key + if self.last_modified is not None: + result['LastModified'] = self.last_modified + if self.owner is not None: + result['Owner'] = self.owner.to_map() + if self.resore_info is not None: + result['ResoreInfo'] = self.resore_info + if self.size is not None: + result['Size'] = self.size + if self.storage_class is not None: + result['StorageClass'] = self.storage_class + if self.type is not None: + result['Type'] = self.type + return result + + def from_map(self, m: dict = None): + m = m or dict() + if m.get('ETag') is not None: + self.etag = m.get('ETag') + if m.get('Key') is not None: + self.key = m.get('Key') + if m.get('LastModified') is not None: + self.last_modified = m.get('LastModified') + if m.get('Owner') is not None: + temp_model = Owner() + self.owner = temp_model.from_map(m['Owner']) + if m.get('ResoreInfo') is not None: + self.resore_info = m.get('ResoreInfo') + if m.get('Size') is not None: + self.size = m.get('Size') + if m.get('StorageClass') is not None: + self.storage_class = m.get('StorageClass') + if m.get('Type') is not None: + self.type = m.get('Type') + return self + + +class ListObjectsResponseBodyListBucketResult(TeaModel): + def __init__( + self, + common_prefixes: List[CommonPrefix] = None, + contents: List[ObjectSummary] = None, + delimiter: str = None, + encoding_type: str = None, + is_truncated: bool = None, + marker: str = None, + max_keys: int = None, + name: str = None, + next_marker: str = None, + prefix: str = None, + ): + # If delimiter is specified in the request, the response contains CommonPrefixes. The objects whose names contain the same string from the prefix to the next occurrence of the delimiter are grouped as a single result element in CommonPrefixes. + self.common_prefixes = common_prefixes + # The container that stores the metadata of the returned objects. + self.contents = contents + # The character that is used to group objects by name. The objects whose names contain the same string from the prefix to the next occurrence of the delimiter are grouped as a single result element in CommonPrefixes. + self.delimiter = delimiter + # The encoding type of the content in the response. If you specify encoding-type in the request, the values of Delimiter, Marker, Prefix, NextMarker, and Key are encoded in the response. + self.encoding_type = encoding_type + # Indicates whether the returned list in the result is truncated. Valid values: + # - true + # - false + self.is_truncated = is_truncated + # The name of the object after which the GetBucket (ListObjects) operation begins. + self.marker = marker + # The maximum number of returned objects in the response. + self.max_keys = max_keys + # The name of the bucket. + self.name = name + # If not all results are returned, NextMarker is included in the response to indicate the value of marker in the next request. + self.next_marker = next_marker + # The prefix in the names of the returned objects. + self.prefix = prefix + + def validate(self): + if self.common_prefixes: + for k in self.common_prefixes: + if k: + k.validate() + if self.contents: + for k in self.contents: + if k: + k.validate() + + def to_map(self): + _map = super().to_map() + if _map is not None: + return _map + + result = dict() + result['CommonPrefixes'] = [] + if self.common_prefixes is not None: + for k in self.common_prefixes: + result['CommonPrefixes'].append(k.to_map() if k else None) + result['Contents'] = [] + if self.contents is not None: + for k in self.contents: + result['Contents'].append(k.to_map() if k else None) + if self.delimiter is not None: + result['Delimiter'] = self.delimiter + if self.encoding_type is not None: + result['EncodingType'] = self.encoding_type + if self.is_truncated is not None: + result['IsTruncated'] = self.is_truncated + if self.marker is not None: + result['Marker'] = self.marker + if self.max_keys is not None: + result['MaxKeys'] = self.max_keys + if self.name is not None: + result['Name'] = self.name + if self.next_marker is not None: + result['NextMarker'] = self.next_marker + if self.prefix is not None: + result['Prefix'] = self.prefix + return result + + def from_map(self, m: dict = None): + m = m or dict() + self.common_prefixes = [] + if m.get('CommonPrefixes') is not None: + for k in m.get('CommonPrefixes'): + temp_model = CommonPrefix() + self.common_prefixes.append(temp_model.from_map(k)) + self.contents = [] + if m.get('Contents') is not None: + for k in m.get('Contents'): + temp_model = ObjectSummary() + self.contents.append(temp_model.from_map(k)) + if m.get('Delimiter') is not None: + self.delimiter = m.get('Delimiter') + if m.get('EncodingType') is not None: + self.encoding_type = m.get('EncodingType') + if m.get('IsTruncated') is not None: + self.is_truncated = m.get('IsTruncated') + if m.get('Marker') is not None: + self.marker = m.get('Marker') + if m.get('MaxKeys') is not None: + self.max_keys = m.get('MaxKeys') + if m.get('Name') is not None: + self.name = m.get('Name') + if m.get('NextMarker') is not None: + self.next_marker = m.get('NextMarker') + if m.get('Prefix') is not None: + self.prefix = m.get('Prefix') + return self + + +class ListObjectsResponseBody(TeaModel): + def __init__( + self, + list_bucket_result: ListObjectsResponseBodyListBucketResult = None, + ): + # The container that stores the information about the returned objects. + self.list_bucket_result = list_bucket_result + + def validate(self): + if self.list_bucket_result: + self.list_bucket_result.validate() + + def to_map(self): + _map = super().to_map() + if _map is not None: + return _map + + result = dict() + if self.list_bucket_result is not None: + result['ListBucketResult'] = self.list_bucket_result.to_map() + return result + + def from_map(self, m: dict = None): + m = m or dict() + if m.get('ListBucketResult') is not None: + temp_model = ListObjectsResponseBodyListBucketResult() + self.list_bucket_result = temp_model.from_map(m['ListBucketResult']) + return self + + +class ListObjectsResponse(TeaModel): + def __init__( + self, + headers: Dict[str, str] = None, + status_code: int = None, + body: ListObjectsResponseBody = None, + ): + self.headers = headers + self.status_code = status_code + self.body = body + + def validate(self): + if self.body: + self.body.validate() + + def to_map(self): + _map = super().to_map() + if _map is not None: + return _map + + result = dict() + if self.headers is not None: + result['headers'] = self.headers + if self.status_code is not None: + result['statusCode'] = self.status_code + if self.body is not None: + result['body'] = self.body.to_map() + return result + + def from_map(self, m: dict = None): + m = m or dict() + if m.get('headers') is not None: + self.headers = m.get('headers') + if m.get('statusCode') is not None: + self.status_code = m.get('statusCode') + if m.get('body') is not None: + temp_model = ListObjectsResponseBody() + self.body = temp_model.from_map(m['body']) + return self + + +typeRegistry = {} +typeRegistry["ListObjects"] = ListObjectsResponseBody + +basic_instance = {} +basic_instance[str] = '' +basic_instance[int] = 0 +basic_instance[bool] = False +basic_instance[Dict[str, str]] = {'':''} + +def build_instance_from_model(model): + if model in basic_instance: + return basic_instance[model] + sig = inspect.signature(model.__init__) + params = {} + for para_name, param in sig.parameters.items(): + if para_name == "self": + continue + origin_type = get_origin(param.annotation) + if origin_type is not None and issubclass(origin_type, list): + params[para_name] = [build_instance_from_model(get_args(param.annotation)[0])] + else: + params[para_name] = build_instance_from_model(param.annotation) + return model(**params) + + +instanceRegistry = {} +instanceRegistry["ListObjects"] = build_instance_from_model(ListObjectsResponseBody) + + +def parse_xml_impl(t, m): + d = {t.tag: {} if t.attrib else None} + children = list(t) + if children: + m = m[t.tag] + islist = isinstance(m, list) + mc = m[0] if islist else m + dd = defaultdict(list) + for dc in [parse_xml_impl(c, mc) for c in children]: + for k, v in dc.items(): + dd[k].append(v) + d = {t.tag: {k: v[0] if len(v) == 1 and not isinstance(mc[k], list) else v for k, v in dd.items()}} + + if t.attrib: + d[t.tag].update(('@' + k, v) for k, v in t.attrib.items()) + + if t.text: + text = t.text.strip() + if children or t.attrib: + if text: + d[t.tag]['#text'] = text + else: + d[t.tag] = text + return d + + +def parse_xml(body, model): + return parse_xml_impl(ElementTree.fromstring(body), model) + + +class Client: + @staticmethod + def parse_xml(bodyStr: str, apiName: str): + d = parse_xml(bodyStr, instanceRegistry[apiName].to_map()) + return typeRegistry[apiName]().from_map(d)