diff --git a/dropbox/dropbox.py b/dropbox/dropbox.py index 3a531f57..7c76d527 100644 --- a/dropbox/dropbox.py +++ b/dropbox/dropbox.py @@ -47,6 +47,7 @@ HOST_CONTENT, HOST_NOTIFY, pinned_session, + DEFAULT_TIMEOUT ) PATH_ROOT_HEADER = 'Dropbox-API-Path-Root' @@ -131,9 +132,6 @@ class _DropboxTransport(object): # the HTTP body. _ROUTE_STYLE_RPC = 'rpc' - # This is the default longest time we'll block on receiving data from the server - _DEFAULT_TIMEOUT = 100 - def __init__(self, oauth2_access_token=None, max_retries_on_error=4, @@ -141,7 +139,7 @@ def __init__(self, user_agent=None, session=None, headers=None, - timeout=_DEFAULT_TIMEOUT, + timeout=DEFAULT_TIMEOUT, oauth2_refresh_token=None, oauth2_access_token_expiration=None, app_key=None, @@ -167,7 +165,7 @@ def __init__(self, client will wait for any single packet from the server. After the timeout the client will give up on connection. If `None`, client will wait forever. Defaults - to 30 seconds. + to 100 seconds. :param str oauth2_refresh_token: OAuth2 refresh token for refreshing access token :param datetime oauth2_access_token_expiration: Expiration for oauth2_access_token :param str app_key: application key of requesting application; used for token refresh @@ -387,7 +385,7 @@ def refresh_access_token(self, host=API_HOST, scope=None): scope = " ".join(scope) body['scope'] = scope - timeout = self._DEFAULT_TIMEOUT + timeout = DEFAULT_TIMEOUT if self._timeout: timeout = self._timeout res = self._session.post(url, data=body, timeout=timeout) diff --git a/dropbox/oauth.py b/dropbox/oauth.py index dc5f677f..94859071 100644 --- a/dropbox/oauth.py +++ b/dropbox/oauth.py @@ -23,6 +23,7 @@ API_HOST, WEB_HOST, pinned_session, + DEFAULT_TIMEOUT, ) if six.PY3: @@ -130,7 +131,7 @@ def __repr__(self): class DropboxOAuth2FlowBase(object): def __init__(self, consumer_key, consumer_secret=None, locale=None, token_access_type='legacy', - scope=None, include_granted_scopes=None, use_pkce=False): + scope=None, include_granted_scopes=None, use_pkce=False, timeout=DEFAULT_TIMEOUT): if scope is not None and (len(scope) == 0 or not isinstance(scope, list)): raise BadInputException("Scope list must be of type list") if token_access_type is not None and token_access_type not in TOKEN_ACCESS_TYPES: @@ -148,6 +149,7 @@ def __init__(self, consumer_key, consumer_secret=None, locale=None, token_access self.requests_session = pinned_session() self.scope = scope self.include_granted_scopes = include_granted_scopes + self._timeout = timeout if use_pkce: self.code_verifier = _generate_pkce_code_verifier() @@ -195,7 +197,7 @@ def _finish(self, code, redirect_uri, code_verifier): if redirect_uri is not None: params['redirect_uri'] = redirect_uri - resp = self.requests_session.post(url, data=params) + resp = self.requests_session.post(url, data=params, timeout=self._timeout) resp.raise_for_status() d = resp.json() @@ -285,7 +287,7 @@ class DropboxOAuth2FlowNoRedirect(DropboxOAuth2FlowBase): """ def __init__(self, consumer_key, consumer_secret=None, locale=None, token_access_type='legacy', - scope=None, include_granted_scopes=None, use_pkce=False): # noqa: E501; + scope=None, include_granted_scopes=None, use_pkce=False, timeout=DEFAULT_TIMEOUT): # noqa: E501; """ Construct an instance. @@ -311,6 +313,11 @@ def __init__(self, consumer_key, consumer_secret=None, locale=None, token_access :param bool use_pkce: Whether or not to use Sha256 based PKCE. PKCE should be only use on client apps which doesn't call your server. It is less secure than non-PKCE flow but can be used if you are unable to safely retrieve your app secret + :param Optional[float] timeout: Maximum duration in seconds that + client will wait for any single packet from the + server. After the timeout the client will give up on + connection. If `None`, client will wait forever. Defaults + to 100 seconds. """ super(DropboxOAuth2FlowNoRedirect, self).__init__( consumer_key=consumer_key, @@ -320,6 +327,7 @@ def __init__(self, consumer_key, consumer_secret=None, locale=None, token_access scope=scope, include_granted_scopes=include_granted_scopes, use_pkce=use_pkce, + timeout=timeout ) def start(self): @@ -365,7 +373,7 @@ class DropboxOAuth2Flow(DropboxOAuth2FlowBase): def __init__(self, consumer_key, redirect_uri, session, csrf_token_session_key, consumer_secret=None, locale=None, token_access_type='legacy', scope=None, - include_granted_scopes=None, use_pkce=False): + include_granted_scopes=None, use_pkce=False, timeout=DEFAULT_TIMEOUT): """ Construct an instance. @@ -397,7 +405,13 @@ def __init__(self, consumer_key, redirect_uri, session, team - include team scopes in the grant Note: if this user has never linked the app, include_granted_scopes must be None :param bool use_pkce: Whether or not to use Sha256 based PKCE + :param Optional[float] timeout: Maximum duration in seconds that + client will wait for any single packet from the + server. After the timeout the client will give up on + connection. If `None`, client will wait forever. Defaults + to 100 seconds. """ + super(DropboxOAuth2Flow, self).__init__( consumer_key=consumer_key, consumer_secret=consumer_secret, @@ -405,7 +419,9 @@ def __init__(self, consumer_key, redirect_uri, session, token_access_type=token_access_type, scope=scope, include_granted_scopes=include_granted_scopes, - use_pkce=use_pkce) + use_pkce=use_pkce, + timeout=timeout + ) self.redirect_uri = redirect_uri self.session = session self.csrf_token_session_key = csrf_token_session_key diff --git a/dropbox/session.py b/dropbox/session.py index 7092f2ae..b793620e 100644 --- a/dropbox/session.py +++ b/dropbox/session.py @@ -29,6 +29,9 @@ API_NOTIFICATION_HOST = os.environ.get('DROPBOX_API_NOTIFY_HOST', HOST_NOTIFY + API_DOMAIN) WEB_HOST = os.environ.get('DROPBOX_WEB_HOST', HOST_WWW + WEB_DOMAIN) +# This is the default longest time we'll block on receiving data from the server +DEFAULT_TIMEOUT = 100 + _TRUSTED_CERT_FILE = pkg_resources.resource_filename(__name__, 'trusted-certs.crt') # TODO(kelkabany): We probably only want to instantiate this once so that even