1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: Apache-2.0
10 # Default Keep server connection timeout: 2 seconds
11 # Default Keep server read timeout: 256 seconds
12 # Default Keep server bandwidth minimum: 32768 bytes per second
13 # Default Keep proxy connection timeout: 20 seconds
14 # Default Keep proxy read timeout: 256 seconds
15 # Default Keep proxy bandwidth minimum: 32768 bytes per second
16 DEFAULT_TIMEOUT = (2, 256, 32768)
17 DEFAULT_PROXY_TIMEOUT = (20, 256, 32768)
19 def __init__(self, title_case_headers=False):
21 self.title_case_headers = title_case_headers
23 def _socket_open(self, *args, **kwargs):
24 if len(args) + len(kwargs) == 2:
25 return self._socket_open_pycurl_7_21_5(*args, **kwargs)
27 return self._socket_open_pycurl_7_19_3(*args, **kwargs)
29 def _socket_open_pycurl_7_19_3(self, family, socktype, protocol, address=None):
30 return self._socket_open_pycurl_7_21_5(
32 address=collections.namedtuple(
33 'Address', ['family', 'socktype', 'protocol', 'addr'],
34 )(family, socktype, protocol, address))
36 def _socket_open_pycurl_7_21_5(self, purpose, address):
37 """Because pycurl doesn't have CURLOPT_TCP_KEEPALIVE"""
38 s = socket.socket(address.family, address.socktype, address.protocol)
39 s.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
40 # Will throw invalid protocol error on mac. This test prevents that.
41 if hasattr(socket, 'TCP_KEEPIDLE'):
42 s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 75)
43 s.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 75)
47 def _setcurltimeouts(self, curl, timeouts, ignore_bandwidth=False):
50 elif isinstance(timeouts, tuple):
51 if len(timeouts) == 2:
52 conn_t, xfer_t = timeouts
53 bandwidth_bps = self.DEFAULT_TIMEOUT[2]
55 conn_t, xfer_t, bandwidth_bps = timeouts
57 conn_t, xfer_t = (timeouts, timeouts)
58 bandwidth_bps = self.DEFAULT_TIMEOUT[2]
59 curl.setopt(pycurl.CONNECTTIMEOUT_MS, int(conn_t*1000))
60 if not ignore_bandwidth:
61 curl.setopt(pycurl.LOW_SPEED_TIME, int(math.ceil(xfer_t)))
62 curl.setopt(pycurl.LOW_SPEED_LIMIT, int(math.ceil(bandwidth_bps)))
64 def _headerfunction(self, header_line):
65 if isinstance(header_line, bytes):
66 header_line = header_line.decode('iso-8859-1')
67 if ':' in header_line:
68 name, value = header_line.split(':', 1)
69 if self.title_case_headers:
70 name = name.strip().title()
72 name = name.strip().lower()
75 name = self._lastheadername
76 value = self._headers[name] + ' ' + header_line.strip()
77 elif header_line.startswith('HTTP/'):
78 name = 'x-status-line'
81 _logger.error("Unexpected header line: %s", header_line)
83 self._lastheadername = name
84 self._headers[name] = value
85 # Returning None implies all bytes were written