123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- # -*- coding: utf-8 -*-
- """The implementation of the SocketOptionsAdapter."""
- import socket
- import warnings
- import sys
- import requests
- from requests import adapters
- from .._compat import connection
- from .._compat import poolmanager
- from .. import exceptions as exc
- class SocketOptionsAdapter(adapters.HTTPAdapter):
- """An adapter for requests that allows users to specify socket options.
- Since version 2.4.0 of requests, it is possible to specify a custom list
- of socket options that need to be set before establishing the connection.
- Example usage::
- >>> import socket
- >>> import requests
- >>> from requests_toolbelt.adapters import socket_options
- >>> s = requests.Session()
- >>> opts = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 0)]
- >>> adapter = socket_options.SocketOptionsAdapter(socket_options=opts)
- >>> s.mount('http://', adapter)
- You can also take advantage of the list of default options on this class
- to keep using the original options in addition to your custom options. In
- that case, ``opts`` might look like::
- >>> opts = socket_options.SocketOptionsAdapter.default_options + opts
- """
- if connection is not None:
- default_options = getattr(
- connection.HTTPConnection,
- 'default_socket_options',
- [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]
- )
- else:
- default_options = []
- warnings.warn(exc.RequestsVersionTooOld,
- "This version of Requests is only compatible with a "
- "version of urllib3 which is too old to support "
- "setting options on a socket. This adapter is "
- "functionally useless.")
- def __init__(self, **kwargs):
- self.socket_options = kwargs.pop('socket_options',
- self.default_options)
- super(SocketOptionsAdapter, self).__init__(**kwargs)
- def init_poolmanager(self, connections, maxsize, block=False):
- if requests.__build__ >= 0x020400:
- # NOTE(Ian): Perhaps we should raise a warning
- self.poolmanager = poolmanager.PoolManager(
- num_pools=connections,
- maxsize=maxsize,
- block=block,
- socket_options=self.socket_options
- )
- else:
- super(SocketOptionsAdapter, self).init_poolmanager(
- connections, maxsize, block
- )
- class TCPKeepAliveAdapter(SocketOptionsAdapter):
- """An adapter for requests that turns on TCP Keep-Alive by default.
- The adapter sets 4 socket options:
- - ``SOL_SOCKET`` ``SO_KEEPALIVE`` - This turns on TCP Keep-Alive
- - ``IPPROTO_TCP`` ``TCP_KEEPINTVL`` 20 - Sets the keep alive interval
- - ``IPPROTO_TCP`` ``TCP_KEEPCNT`` 5 - Sets the number of keep alive probes
- - ``IPPROTO_TCP`` ``TCP_KEEPIDLE`` 60 - Sets the keep alive time if the
- socket library has the ``TCP_KEEPIDLE`` constant
- The latter three can be overridden by keyword arguments (respectively):
- - ``idle``
- - ``interval``
- - ``count``
- You can use this adapter like so::
- >>> from requests_toolbelt.adapters import socket_options
- >>> tcp = socket_options.TCPKeepAliveAdapter(idle=120, interval=10)
- >>> s = requests.Session()
- >>> s.mount('http://', tcp)
- """
- def __init__(self, **kwargs):
- socket_options = kwargs.pop('socket_options',
- SocketOptionsAdapter.default_options)
- idle = kwargs.pop('idle', 60)
- interval = kwargs.pop('interval', 20)
- count = kwargs.pop('count', 5)
- socket_options = socket_options + [
- (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
- ]
- # NOTE(Ian): OSX does not have these constants defined, so we
- # set them conditionally.
- if getattr(socket, 'TCP_KEEPINTVL', None) is not None:
- socket_options += [(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL,
- interval)]
- elif sys.platform == 'darwin':
- # On OSX, TCP_KEEPALIVE from netinet/tcp.h is not exported
- # by python's socket module
- TCP_KEEPALIVE = getattr(socket, 'TCP_KEEPALIVE', 0x10)
- socket_options += [(socket.IPPROTO_TCP, TCP_KEEPALIVE, interval)]
- if getattr(socket, 'TCP_KEEPCNT', None) is not None:
- socket_options += [(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, count)]
- if getattr(socket, 'TCP_KEEPIDLE', None) is not None:
- socket_options += [(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, idle)]
- super(TCPKeepAliveAdapter, self).__init__(
- socket_options=socket_options, **kwargs
- )
|