| 63 | raise TypeError(repr(o) + " is not JSON serializable") |
| 64 | |
| 65 | class AuthServiceProxy(): |
| 66 | __id_count = 0 |
| 67 | |
| 68 | # ensure_ascii: escape unicode as \uXXXX, passed to json.dumps |
| 69 | def __init__(self, service_url, service_name=None, timeout=HTTP_TIMEOUT, connection=None, ensure_ascii=True): |
| 70 | self.__service_url = service_url |
| 71 | self._service_name = service_name |
| 72 | self.ensure_ascii = ensure_ascii # can be toggled on the fly by tests |
| 73 | self.__url = urllib.parse.urlparse(service_url) |
| 74 | port = 80 if self.__url.port is None else self.__url.port |
| 75 | user = None if self.__url.username is None else self.__url.username.encode('utf8') |
| 76 | passwd = None if self.__url.password is None else self.__url.password.encode('utf8') |
| 77 | authpair = user + b':' + passwd |
| 78 | self.__auth_header = b'Basic ' + base64.b64encode(authpair) |
| 79 | |
| 80 | if connection: |
| 81 | # Callables re-use the connection of the original proxy |
| 82 | self.__conn = connection |
| 83 | elif self.__url.scheme == 'https': |
| 84 | self.__conn = http.client.HTTPSConnection(self.__url.hostname, port, timeout=timeout) |
| 85 | else: |
| 86 | self.__conn = http.client.HTTPConnection(self.__url.hostname, port, timeout=timeout) |
| 87 | |
| 88 | def __getattr__(self, name): |
| 89 | if name.startswith('__') and name.endswith('__'): |
| 90 | # Python internal stuff |
| 91 | raise AttributeError |
| 92 | if self._service_name is not None: |
| 93 | name = "%s.%s" % (self._service_name, name) |
| 94 | return AuthServiceProxy(self.__service_url, name, connection=self.__conn) |
| 95 | |
| 96 | def _request(self, method, path, postdata): |
| 97 | ''' |
| 98 | Do a HTTP request, with retry if we get disconnected (e.g. due to a timeout). |
| 99 | This is a workaround for https://bugs.python.org/issue3566 which is fixed in Python 3.5. |
| 100 | ''' |
| 101 | headers = {'Host': self.__url.hostname, |
| 102 | 'User-Agent': USER_AGENT, |
| 103 | 'Authorization': self.__auth_header, |
| 104 | 'Content-type': 'application/json'} |
| 105 | try: |
| 106 | self.__conn.request(method, path, postdata, headers) |
| 107 | return self._get_response() |
| 108 | except http.client.BadStatusLine as e: |
| 109 | if e.line == "''": # if connection was closed, try again |
| 110 | self.__conn.close() |
| 111 | self.__conn.request(method, path, postdata, headers) |
| 112 | return self._get_response() |
| 113 | else: |
| 114 | raise |
| 115 | except (BrokenPipeError, ConnectionResetError): |
| 116 | # Python 3.5+ raises BrokenPipeError instead of BadStatusLine when the connection was reset |
| 117 | # ConnectionResetError happens on FreeBSD with Python 3.4 |
| 118 | self.__conn.close() |
| 119 | self.__conn.request(method, path, postdata, headers) |
| 120 | return self._get_response() |
| 121 | |
| 122 | def get_request(self, *args, **argsn): |
no outgoing calls
no test coverage detected