oss2.http 源代码

# -*- coding: utf-8 -*-

"""
oss2.http
~~~~~~~~
This is the HTTP Adapters for requests library. So that the dependency of request library is totally transparent to the SDK caller.
It has the wrapper class `Session`, `Request`, `Response`  for its counterparts in the requests library.
"""

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


_USER_AGENT = 'aliyun-sdk-python/{0}({1}/{2}/{3};{4})'.format(
    __version__, platform.system(), platform.release(), platform.machine(), platform.python_version())


[文档]class Session(object): """Requests of the same session share the same connection pool and possibly the same HTTP connection.""" def __init__(self): 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))
[文档] def do_request(self, req, timeout): try: return Response(self.session.request(req.method, req.url, data=req.data, params=req.params, headers=req.headers, stream=True, timeout=timeout)) except requests.RequestException as e: raise RequestError(e)
[文档]class Request(object): def __init__(self, method, url, data=None, params=None, headers=None, app_name=''): self.method = method self.url = url self.data = _convert_request_body(data) self.params = params or {} 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
_CHUNK_SIZE = 8 * 1024
[文档]class Response(object): def __init__(self, response): self.response = response self.status = response.status_code self.headers = response.headers # 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
[文档] 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)
# For data which has the len() method (which means it has the length), returns the whole data as the request's content. # For data which supports seek() and tell(), but not len(), then returns the remaining data from the current position. # Note that for file, it does not support len(), but it supports seek() and tell(). 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