Files
ai_wht_B/venv/Lib/site-packages/oss2/http.py
“shengyudong” 5a384b694e 2026-1-6
2026-01-06 14:18:39 +08:00

154 lines
5.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- coding: utf-8 -*-
"""
oss2.http
~~~~~~~~
这个模块包含了HTTP Adapters。尽管OSS Python SDK内部使用requests库进行HTTP通信但是对使用者是透明的。
该模块中的 `Session` 、 `Request` 、`Response` 对requests的对应的类做了简单的封装。
"""
import platform
import requests
from requests.structures import CaseInsensitiveDict
from . import __version__, defaults
from .compat import to_bytes
from .exceptions import RequestError
from .utils import file_object_remaining_bytes, SizedFileAdapter
import logging
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__)
class Session(object):
"""属于同一个Session的请求共享一组连接池如有可能也会重用HTTP连接。"""
def __init__(self, pool_size=None):
self.session = requests.Session()
psize = pool_size or 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}, proxies: {5}".format(
req.method, req.url, req.params, req.headers, timeout, req.proxies))
return Response(self.session.request(req.method, req.url,
data=req.data,
params=req.params,
headers=req.headers,
stream=True,
timeout=timeout,
proxies=req.proxies))
except requests.RequestException as e:
raise RequestError(e)
class Request(object):
def __init__(self, method, url,
data=None,
params=None,
headers=None,
app_name='',
proxies=None,
region=None,
product=None,
cloudbox_id=None):
self.method = method
self.url = url
self.data = _convert_request_body(data)
self.params = params or {}
self.proxies = proxies
self.region = region
self.product = product
self.cloudbox_id = cloudbox_id
if not isinstance(headers, CaseInsensitiveDict):
self.headers = CaseInsensitiveDict(headers)
else:
self.headers = headers
# tell requests not to add 'Accept-Encoding: gzip, deflate' by default
if 'Accept-Encoding' not in self.headers:
self.headers['Accept-Encoding'] = None
if 'User-Agent' not in self.headers:
if app_name:
self.headers['User-Agent'] = USER_AGENT + '/' + app_name
else:
self.headers['User-Agent'] = USER_AGENT
logger.debug("Init request, method: {0}, url: {1}, params: {2}, headers: {3}".format(method, url, params,
headers))
_CHUNK_SIZE = 8 * 1024
class Response(object):
def __init__(self, response):
self.response = response
self.status = response.status_code
self.headers = response.headers
self.request_id = response.headers.get('x-oss-request-id', '')
# When a response contains no body, iter_content() cannot
# be run twice (requests.exceptions.StreamConsumedError will be raised).
# For details of the issue, please see issue #82
#
# To work around this issue, we simply return b'' when everything has been read.
#
# Note you cannot use self.response.raw.read() to implement self.read(), because
# raw.read() does not uncompress response body when the encoding is gzip etc., and
# we try to avoid depends on details of self.response.raw.
self.__all_read = False
logger.debug("Get response headers, req-id:{0}, status: {1}, headers: {2}".format(self.request_id, self.status,
self.headers))
def read(self, amt=None):
if self.__all_read:
return b''
if amt is None:
content_list = []
for chunk in self.response.iter_content(_CHUNK_SIZE):
content_list.append(chunk)
content = b''.join(content_list)
self.__all_read = True
return content
else:
try:
return next(self.response.iter_content(amt))
except StopIteration:
self.__all_read = True
return b''
def __iter__(self):
return self.response.iter_content(_CHUNK_SIZE)
# requests对于具有fileno()方法的file object会用fileno()的返回值作为Content-Length。
# 这对于已经读取了部分内容或执行了seek()的file object是不正确的。
#
# _convert_request_body()对于支持seek()和tell() file object确保是从
# 当前位置读取,且只读取当前位置到文件结束的内容。
def _convert_request_body(data):
data = to_bytes(data)
if hasattr(data, '__len__'):
return data
if hasattr(data, 'seek') and hasattr(data, 'tell'):
return SizedFileAdapter(data, file_object_remaining_bytes(data))
return data