diff --git a/examples/object_http20.py b/examples/object_http20.py new file mode 100644 index 00000000..ad075022 --- /dev/null +++ b/examples/object_http20.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- + +import os +import shutil + +import oss2 + + +# 以下代码展示了如何启用Http2.0来发送请求。 + + +# 首先初始化AccessKeyId、AccessKeySecret、Endpoint等信息。 +# 通过环境变量获取,或者把诸如“<你的AccessKeyId>”替换成真实的AccessKeyId等。 +# +# 以杭州区域为例,Endpoint可以是: +# https://oss-cn-hangzhou.aliyuncs.com +# 目前Http2.0只支持HTTPS协议访问。 +access_key_id = os.getenv('OSS_TEST_ACCESS_KEY_ID', '<你的AccessKeyId>') +access_key_secret = os.getenv('OSS_TEST_ACCESS_KEY_SECRET', '<你的AccessKeySecret>') +bucket_name = os.getenv('OSS_TEST_BUCKET', '<你的Bucket>') +endpoint = os.getenv('OSS_TEST_ENDPOINT', '<你的访问域名>') + + +# 确认上面的参数都填写正确了 +for param in (access_key_id, access_key_secret, bucket_name, endpoint): + assert '<' not in param, '请设置参数:' + param + +# 创建Bucket对象,所有Object相关的接口都可以通过Bucket对象来进行 +bucket = oss2.Bucket(oss2.Auth(access_key_id, access_key_secret), endpoint, bucket_name, http_version=oss2.HTTP_VERSION_20) + +# 上传一段字符串。Object名是motto.txt,内容是一段名言。 +bucket.put_object('motto.txt', 'Never give up. - Jack Ma') + +# 下载到本地文件 +bucket.get_object_to_file('motto.txt', '本地文件名.txt') + +# 清除本地文件 +os.remove(u'本地文件名.txt') diff --git a/oss2/__init__.py b/oss2/__init__.py index 66b60b4b..3f05e208 100644 --- a/oss2/__init__.py +++ b/oss2/__init__.py @@ -4,7 +4,7 @@ from .api import Service, Bucket, CryptoBucket from .auth import Auth, AuthV2, AnonymousAuth, StsAuth, AUTH_VERSION_1, AUTH_VERSION_2, make_auth -from .http import Session, CaseInsensitiveDict +from .http import Session, CaseInsensitiveDict, HTTP_VERSION_11, HTTP_VERSION_20 from .iterators import (BucketIterator, ObjectIterator, diff --git a/oss2/api.py b/oss2/api.py index 4ae39db6..bdb3178d 100644 --- a/oss2/api.py +++ b/oss2/api.py @@ -186,10 +186,10 @@ def progress_callback(bytes_consumed, total_bytes): class _Base(object): def __init__(self, auth, endpoint, is_cname, session, connect_timeout, - app_name='', enable_crc=True): + app_name='', enable_crc=True, http_version=http.HTTP_VERSION_11): self.auth = auth - self.endpoint = _normalize_endpoint(endpoint.strip()) - self.session = session or http.Session() + self.endpoint = _normalize_endpoint(endpoint.strip(), http_version) + self.session = session or http.Session(http_version=http_version) self.timeout = defaults.get(connect_timeout, defaults.connect_timeout) self.app_name = app_name self.enable_crc = enable_crc @@ -268,11 +268,12 @@ class Service(_Base): def __init__(self, auth, endpoint, session=None, connect_timeout=None, - app_name=''): + app_name='', + http_version=http.HTTP_VERSION_11): logger.info("Init oss service, endpoint: {0}, connect_timeout: {1}, app_name: {2}".format( endpoint, connect_timeout, app_name)) super(Service, self).__init__(auth, endpoint, False, session, connect_timeout, - app_name=app_name) + app_name=app_name, http_version=http_version) def list_buckets(self, prefix='', marker='', max_keys=100): """根据前缀罗列用户的Bucket。 @@ -341,11 +342,12 @@ def __init__(self, auth, endpoint, bucket_name, session=None, connect_timeout=None, app_name='', - enable_crc=True): + enable_crc=True, + http_version=http.HTTP_VERSION_11): logger.info("Init oss bucket, endpoint: {0}, isCname: {1}, connect_timeout: {2}, app_name: {3}, enabled_crc: " "{4}".format(endpoint, is_cname, connect_timeout, app_name, enable_crc)) super(Bucket, self).__init__(auth, endpoint, is_cname, session, connect_timeout, - app_name, enable_crc) + app_name, enable_crc, http_version=http_version) self.bucket_name = bucket_name.strip() @@ -1625,7 +1627,8 @@ def __init__(self, auth, endpoint, bucket_name, crypto_provider, session=None, connect_timeout=None, app_name='', - enable_crc=True): + enable_crc=True, + http_version=http.HTTP_VERSION_11): if not isinstance(crypto_provider, BaseCryptoProvider): raise ClientError('Crypto bucket must provide a valid crypto_provider') @@ -1634,7 +1637,7 @@ def __init__(self, auth, endpoint, bucket_name, crypto_provider, self.bucket_name = bucket_name.strip() self.enable_crc = enable_crc self.bucket = Bucket(auth, endpoint, bucket_name, is_cname, session, connect_timeout, - app_name, enable_crc=False) + app_name, enable_crc=False, http_version=http_version) def put_object(self, key, data, headers=None, @@ -1758,9 +1761,12 @@ def get_object_to_file(self, key, filename, return result -def _normalize_endpoint(endpoint): +def _normalize_endpoint(endpoint, http_version): if not endpoint.startswith('http://') and not endpoint.startswith('https://'): - return 'http://' + endpoint + if http_version is http.HTTP_VERSION_20: + return 'https://' + endpoint + else: + return 'http://' + endpoint else: return endpoint diff --git a/oss2/headers.py b/oss2/headers.py index 5ddf76ca..eed2da5b 100644 --- a/oss2/headers.py +++ b/oss2/headers.py @@ -47,3 +47,6 @@ def set_server_side_encryption(self, algorithm=None, cmk_id=None): self[OSS_SERVER_SIDE_ENCRYPTION] = "KMS" if cmk_id is not None: self[OSS_SERVER_SIDE_ENCRYPTION_KEY_ID] = cmk_id + + def set_content_length(self, content_length): + self["Content-Length"] = content_length diff --git a/oss2/http.py b/oss2/http.py index 8e8c2ca9..097ec52d 100644 --- a/oss2/http.py +++ b/oss2/http.py @@ -19,26 +19,47 @@ from .utils import file_object_remaining_bytes, SizedFileAdapter import logging +from hyper.contrib import HTTP20Adapter +import threading _USER_AGENT = 'aliyun-sdk-python/{0}({1}/{2}/{3};{4})'.format( __version__, platform.system(), platform.release(), platform.machine(), platform.python_version()) logger = logging.getLogger(__name__) +HTTP_VERSION_11 = 'http11' +HTTP_VERSION_20 = 'http20' + class Session(object): """属于同一个Session的请求共享一组连接池,如有可能也会重用HTTP连接。""" - def __init__(self): + def __init__(self, http_version=HTTP_VERSION_11): self.session = requests.Session() - psize = defaults.connection_pool_size - self.session.mount('http://', requests.adapters.HTTPAdapter(pool_connections=psize, pool_maxsize=psize)) - self.session.mount('https://', requests.adapters.HTTPAdapter(pool_connections=psize, pool_maxsize=psize)) + self.http_version = http_version + self.__lock = threading.Lock() + + if http_version is HTTP_VERSION_20: + self.session.mount('https://', HTTP20Adapter()) + else: + psize = defaults.connection_pool_size + self.session.mount('http://', requests.adapters.HTTPAdapter(pool_connections=psize, pool_maxsize=psize)) + self.session.mount('https://', requests.adapters.HTTPAdapter(pool_connections=psize, pool_maxsize=psize)) def do_request(self, req, timeout): try: - logger.debug("Send request, method: {0}, url: {1}, params: {2}, headers: {3}, timeout: {4}".format( - req.method, req.url, req.params, req.headers, timeout)) - return Response(self.session.request(req.method, req.url, + logger.debug("Send request, method: {0}, url: {1}, params: {2}, headers: {3}, timeout: {4}, http_version: {5}".format( + req.method, req.url, req.params, req.headers, timeout, self.http_version)) + if self.http_version is HTTP_VERSION_20: + with self.__lock: + resp = Response(self.session.request(req.method, req.url, + data=req.data, + params=req.params, + headers=req.headers, + stream=True, + timeout=timeout)) + return resp + else: + return Response(self.session.request(req.method, req.url, data=req.data, params=req.params, headers=req.headers, diff --git a/scripts/patch_hyper.py b/scripts/patch_hyper.py new file mode 100755 index 00000000..6f8f51fe --- /dev/null +++ b/scripts/patch_hyper.py @@ -0,0 +1,55 @@ +#!/usr/bin/python + +import os +import hyper +import h2 + +def fix_hyper(): + if hyper.__version__ == "0.7.0": + hyper_dir = os.path.dirname(hyper.__file__) + fix_file_path = hyper_dir + "/common/headers.py" + + f_read = open(fix_file_path,'r+') + flist = f_read.readlines() + if flist[244] == """ SPECIAL_SNOWFLAKES = set([b'set-cookie', b'set-cookie2'])\n""": + flist[244] = """ SPECIAL_SNOWFLAKES = set([b'set-cookie', b'set-cookie2', b'date', b'if-modified-since', b'if-unmodified-since', b'authorization'])\n""" + + print " =====================================================================================" + print " # OSS already patch to fix hyper library " + print " # fixed file name: ", fix_file_path + print " # fixed line number: 244" + print " # More detail to see: https://github.com/Lukasa/hyper/issues/314 " + print " =====================================================================================" + f_read.close() + + f_wte = open(fix_file_path, 'w+') + f_wte.writelines(flist) + f_wte.close() + +def fix_h2(): + if h2.__version__ == "2.6.2": + h2_dir = os.path.dirname(h2.__file__) + fix_file_path = h2_dir + "/stream.py" + + f_read = open(fix_file_path, 'r+') + flist = f_read.readlines() + if flist[337] == """ raise StreamClosedError(self.stream_id)\n""": + flist[337] = """ #raise StreamClosedError(self.stream_id)\n return []\n""" + print " =====================================================================================" + print " # OSS already patch to fix h2 library " + print " # fixed file name: ", fix_file_path + print " # fixed line number: 337" + print " =====================================================================================" + f_read.close() + + f_wte = open(fix_file_path, 'w+') + f_wte.writelines(flist) + f_wte.close() + +def main(): + fix_hyper() + fix_h2() + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 6cfe286a..a5badd76 100644 --- a/setup.py +++ b/setup.py @@ -29,6 +29,7 @@ packages=['oss2'], install_requires=['requests!=2.9.0', 'crcmod>=1.7', + 'hyper>=0.7.0', 'pycryptodome>=3.4.7', 'aliyun-python-sdk-kms>=2.4.1', 'aliyun-python-sdk-core>=2.6.2' if sys.version_info[0] == 2 else 'aliyun-python-sdk-core-v3>=2.5.5'], diff --git a/tests/common.py b/tests/common.py index eb39edee..d88cf626 100644 --- a/tests/common.py +++ b/tests/common.py @@ -26,6 +26,7 @@ OSS_STS_ARN = os.getenv("OSS_TEST_STS_ARN") OSS_AUTH_VERSION = None +OSS_HTTP_VERSION = None def random_string(n): return ''.join(random.choice(string.ascii_lowercase) for i in range(n)) @@ -80,10 +81,11 @@ def setUp(self): oss2.defaults.multiget_part_size = self.default_multiget_part_size oss2.defaults.multiget_num_threads = random.randint(1, 5) - global OSS_AUTH_VERSION + global OSS_AUTH_VERSION, OSS_HTTP_VERSION OSS_AUTH_VERSION = os.getenv('OSS_TEST_AUTH_VERSION') + OSS_HTTP_VERSION = os.getenv('OSS_TEST_HTTP_VERSION') - self.bucket = oss2.Bucket(oss2.make_auth(OSS_ID, OSS_SECRET, OSS_AUTH_VERSION), OSS_ENDPOINT, OSS_BUCKET) + self.bucket = oss2.Bucket(oss2.make_auth(OSS_ID, OSS_SECRET, OSS_AUTH_VERSION), OSS_ENDPOINT, OSS_BUCKET, http_version=OSS_HTTP_VERSION) try: self.bucket.create_bucket() @@ -91,10 +93,11 @@ def setUp(self): pass self.rsa_crypto_bucket = oss2.CryptoBucket(oss2.make_auth(OSS_ID, OSS_SECRET, OSS_AUTH_VERSION), OSS_ENDPOINT, OSS_BUCKET, - crypto_provider=oss2.LocalRsaProvider()) + crypto_provider=oss2.LocalRsaProvider(), http_version=OSS_HTTP_VERSION) + # Special handle for http20, Because now KMS don't support http20, kms_crypto_bucket create with http11 self.kms_crypto_bucket = oss2.CryptoBucket(oss2.make_auth(OSS_ID, OSS_SECRET, OSS_AUTH_VERSION), OSS_ENDPOINT, OSS_BUCKET, - crypto_provider=oss2.AliKMSProvider(OSS_ID, OSS_SECRET, OSS_REGION, OSS_CMK)) + crypto_provider=oss2.AliKMSProvider(OSS_ID, OSS_SECRET, OSS_REGION, OSS_CMK), http_version=oss2.HTTP_VERSION_11) self.key_list = [] self.temp_files = [] diff --git a/tests/test_bucket.py b/tests/test_bucket.py index 8f75849b..8bfdb519 100644 --- a/tests/test_bucket.py +++ b/tests/test_bucket.py @@ -541,6 +541,26 @@ def test_xml_input_output(self): self.assertEqual(result.allow_empty_referer, True) self.assertEqual(result.referers[0], to_string(u'阿里云')) +class TestHttp20OverBucket(TestBucket): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestBucket,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverBucket, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverBucket, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverBucket, self).tearDown() if __name__ == '__main__': unittest.main() diff --git a/tests/test_chinese.py b/tests/test_chinese.py index f73fb994..cb19f40a 100644 --- a/tests/test_chinese.py +++ b/tests/test_chinese.py @@ -63,7 +63,27 @@ def test_get_symlink(self): result = self.bucket.get_symlink(symlink) self.assertEqual(result.target_key, key) - + +class TestHttp20OverChinese(TestChinese): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestChinese,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverChinese, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverChinese, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverChinese, self).tearDown() if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_download.py b/tests/test_download.py index d171a4c6..142c3ed0 100644 --- a/tests/test_download.py +++ b/tests/test_download.py @@ -609,6 +609,27 @@ def test_resumable_incomplete_download(self): except: self.assertTrue(False) +class TestHttp20OverDownload(TestDownload): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestDownload,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverDownload, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverDownload, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverDownload, self).tearDown() + if __name__ == '__main__': unittest.main() diff --git a/tests/test_headers.py b/tests/test_headers.py index 62bc3797..757871a6 100644 --- a/tests/test_headers.py +++ b/tests/test_headers.py @@ -23,6 +23,14 @@ def test_check_requestHeader(self): self.assertTrue("x-oss-server-side-encryption" not in myHeader) self.assertTrue("x-oss-server-side-encryption-key-id" not in myHeader) + def test_set_content_length(self): + myHeader = RequestHeader() + + myHeader.set_content_length("100") + self.assertTrue(myHeader["Content-Length"] is "100") + + myHeader.set_content_length("200") + self.assertTrue(myHeader["Content-Length"] is "200") if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_image.py b/tests/test_image.py index ff8c6253..b991b10f 100644 --- a/tests/test_image.py +++ b/tests/test_image.py @@ -6,6 +6,7 @@ import json from common import * +from oss2.headers import * class TestImage(OssTestCase): @@ -19,7 +20,14 @@ def __prepare(self): def __test(self, original_image, new_image, image_style): original_image_content = self.bucket.get_object(original_image, process=image_style) - self.bucket.put_object(new_image, original_image_content) + + # Special handle for http20, Need add Content-Length to request header in this test case + if self.bucket.session.http_version is oss2.HTTP_VERSION_20: + test_header = RequestHeader() + test_header.set_content_length(original_image_content.headers['Content-Length']) + self.bucket.put_object(new_image, original_image_content, headers=test_header) + else: + self.bucket.put_object(new_image, original_image_content) def __test_to_file(self, original_image, new_image, image_style): self.bucket.get_object_to_file(original_image, new_image, process=image_style) @@ -86,5 +94,26 @@ def test_resize_to_file(self): self.__check(new_image, 100, 100, 3267, 'jpg') +class TestHttp20OverImage(TestImage): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestImage,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverImage, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverImage, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverImage, self).tearDown() + if __name__ == '__main__': unittest.main() diff --git a/tests/test_iterator.py b/tests/test_iterator.py index bce09f01..910beeec 100644 --- a/tests/test_iterator.py +++ b/tests/test_iterator.py @@ -182,6 +182,26 @@ def test_live_channel_iterator(self): for live_channel in channel_name_list: self.bucket.delete_live_channel(live_channel) +class TestHttp20OverIterator(TestIterator): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestIterator,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverIterator, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverIterator, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverIterator, self).tearDown() if __name__ == '__main__': - unittest.main() \ No newline at end of file + unittest.main() diff --git a/tests/test_live_channel.py b/tests/test_live_channel.py index b099734f..89a458a7 100644 --- a/tests/test_live_channel.py +++ b/tests/test_live_channel.py @@ -251,8 +251,29 @@ def test_anonymous_auth(self): self.assertEqual(signed_url, self._get_publish_url(self.bucket.bucket_name, channel_name) + "?playlistName=" + playlist_name) - self.assertRaises(oss2.exceptions.AccessDenied, bucket.delete_live_channel, 'test-live-chan') - + self.assertRaises(oss2.exceptions.AccessDenied, bucket.delete_live_channel, 'test-live-chan') + +class TestHttp20OverLiveChannel(TestLiveChannel): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestLiveChannel,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverLiveChannel, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverLiveChannel, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverLiveChannel, self).tearDown() + if __name__ == '__main__': unittest.main() diff --git a/tests/test_multipart.py b/tests/test_multipart.py index 3bf840d0..5a071804 100644 --- a/tests/test_multipart.py +++ b/tests/test_multipart.py @@ -97,6 +97,27 @@ def test_upload_part_copy(self): self.assertEqual(len(content_got), len(content)) self.assertEqual(content_got, content) +class TestHttp20OverMultipart(TestMultipart): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestMultipart,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverMultipart, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverMultipart, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverMultipart, self).tearDown() + if __name__ == '__main__': unittest.main() diff --git a/tests/test_object.py b/tests/test_object.py index 31d22417..19c86e5e 100644 --- a/tests/test_object.py +++ b/tests/test_object.py @@ -10,6 +10,7 @@ NotFound, NoSuchKey, Conflict, PositionNotEqualToLength, ObjectNotAppendable) from oss2.compat import is_py2, is_py33 +from oss2.headers import * from common import * @@ -188,7 +189,14 @@ def test_object_empty(self): key = self.random_key() content = b'' - self.bucket.put_object(key, content) + # Special handle for http20, Need add Content-Length to request header in this test case + if self.bucket.session.http_version is oss2.HTTP_VERSION_20: + test_header = RequestHeader() + test_header.set_content_length("0") + self.bucket.put_object(key, content, headers=test_header) + else: + self.bucket.put_object(key, content) + res = self.bucket.get_object(key) self.assertEqual(res.read(), b'') @@ -203,7 +211,14 @@ def test_file_empty(self): with open(input_filename, 'wb') as f: f.write(content) - self.bucket.put_object_from_file(key, input_filename) + # Special handle for http20, Need add Content-Length to request header in this test case + if self.bucket.session.http_version is oss2.HTTP_VERSION_20: + test_header = RequestHeader() + test_header.set_content_length("0") + self.bucket.put_object_from_file(key, input_filename, headers=test_header) + else: + self.bucket.put_object_from_file(key, input_filename) + self.bucket.get_object_to_file(key, output_filename) self.assertTrue(filecmp.cmp(input_filename, output_filename)) @@ -218,7 +233,14 @@ def test_streaming(self): # 获取OSS上的文件,一边读取一边写入到另外一个OSS文件 src = self.bucket.get_object(src_key) - result = self.bucket.put_object(dst_key, src) + + # Special handle for http20, Need add Content-Length to request header in this test case + if self.bucket.session.http_version is oss2.HTTP_VERSION_20: + test_header = RequestHeader() + test_header.set_content_length("1048576") + result = self.bucket.put_object(dst_key, src, headers=test_header) + else: + result = self.bucket.put_object(dst_key, src) # verify self.assertTrue(src.client_crc is not None) @@ -239,6 +261,10 @@ def generator(): return generator() def test_data_generator(self): + # Special handle for http20, Ignore this test if http20 + if self.bucket.session.http_version is oss2.HTTP_VERSION_20: + return + key = self.random_key() key2 = self.random_key() content = random_bytes(1024 * 1024 + 1) @@ -406,7 +432,7 @@ def test_private_download_url(self): resp = requests.get(url) self.assertEqual(content, resp.content) - + def test_sign_url_with_callback(self): key = self.random_key() @@ -587,8 +613,12 @@ def test_object_acl(self): self.bucket.delete_object(key) def test_object_exists(self): + # Special handle for http20, Ignore this test if http20 + if self.bucket.session.http_version is oss2.HTTP_VERSION_20: + return + key = self.random_key() - + auth = oss2.Auth(OSS_ID, OSS_SECRET) bucket = oss2.Bucket(auth, OSS_ENDPOINT, random_string(63).lower()) self.assertRaises(NoSuchBucket, bucket.object_exists, key) @@ -609,20 +639,23 @@ def test_user_meta(self): self.assertEqual(headers['x-oss-meta-key2'], 'value2') def test_get_object_meta(self): + # Special handle for http20, Ignore this test if http20 + if self.bucket.session.http_version is oss2.HTTP_VERSION_20: + return + key = self.random_key() content = 'hello' - + # bucket no exist auth = oss2.Auth(OSS_ID, OSS_SECRET) bucket = oss2.Bucket(auth, OSS_ENDPOINT, random_string(63).lower()) - + self.assertRaises(NoSuchBucket, bucket.get_object_meta, key) - + # object no exist self.assertRaises(NoSuchKey, self.bucket.get_object_meta, key) self.bucket.put_object(key, content) - # get meta normal result = self.bucket.get_object_meta(key) @@ -861,6 +894,10 @@ def test_get_symlink(self): self.assertEqual(result.target_key, key) def test_process_object(self): + # Special handle for http20, Ignore this test if http20 + if self.bucket.session.http_version is oss2.HTTP_VERSION_20: + return + key = self.random_key(".jpg") result = self.bucket.put_object_from_file(key, "tests/example.jpg") self.assertEqual(result.status, 200) @@ -910,6 +947,47 @@ def tearDown(self): os.environ['OSS_TEST_AUTH_VERSION'] = oss2.AUTH_VERSION_2 super(TestSign, self).tearDown() +class TestHttp20OverObject(TestObject): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestObject,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverObject, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverObject, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverObject, self).tearDown() + +class TestHttp20OverSign(TestSign): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestSign,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverSign, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverSign, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverSign, self).tearDown() if __name__ == '__main__': unittest.main() diff --git a/tests/test_sts.py b/tests/test_sts.py index 03243aa5..89282d2f 100644 --- a/tests/test_sts.py +++ b/tests/test_sts.py @@ -72,7 +72,8 @@ def init_bucket(self): self.token = fetch_sts_token(OSS_STS_ID, OSS_STS_KEY, OSS_STS_ARN) auth = oss2.StsAuth(self.token.access_key_id, self.token.access_key_secret, self.token.security_token) - self.bucket = oss2.Bucket(auth, OSS_ENDPOINT, OSS_BUCKET) + OSS_HTTP_VERSION = os.getenv('OSS_TEST_HTTP_VERSION') + self.bucket = oss2.Bucket(auth, OSS_ENDPOINT, OSS_BUCKET, http_version=OSS_HTTP_VERSION) def test_object(self): self.init_bucket() @@ -132,4 +133,49 @@ def tearDown(self): os.environ['OSS_TEST_AUTH_VERSION'] = oss2.AUTH_VERSION_1 else: os.environ['OSS_TEST_AUTH_VERSION'] = oss2.AUTH_VERSION_2 - super(TestSign, self).tearDown() \ No newline at end of file + super(TestSign, self).tearDown() + + class TestHttp20OverSts(TestSts): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestSts,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverSts, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverSts, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverSts, self).tearDown() + + class TestHttp20OverSign(TestSign): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestSign,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverSign, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverSign, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverSign, self).tearDown() + +if __name__ == '__main__': + unittest.main() diff --git a/tests/test_upload.py b/tests/test_upload.py index 6a851234..4bfe4ad0 100644 --- a/tests/test_upload.py +++ b/tests/test_upload.py @@ -258,6 +258,27 @@ def check_not_sane(key, value): check_not_sane('key', None) check_not_sane('parts', None) +class TestHttp20OverUpload(TestUpload): + """ + 当环境变量使用oss2.HTTP11时,则重新设置为HTTP20, 再运行TestUpload,反之亦然 + """ + def __init__(self, *args, **kwargs): + super(TestHttp20OverUpload, self).__init__(*args, **kwargs) + + def setUp(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverUpload, self).setUp() + + def tearDown(self): + if os.getenv('OSS_TEST_HTTP_VERSION') == oss2.HTTP_VERSION_11: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_20 + else: + os.environ['OSS_TEST_HTTP_VERSION'] = oss2.HTTP_VERSION_11 + super(TestHttp20OverUpload, self).tearDown() + if __name__ == '__main__': unittest.main()