You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

249 lines
6.4 KiB

4 years ago
  1. """HTTP related errors."""
  2. import asyncio
  3. import warnings
  4. try:
  5. import ssl
  6. except ImportError: # pragma: no cover
  7. ssl = None # type: ignore
  8. __all__ = (
  9. 'ClientError',
  10. 'ClientConnectionError',
  11. 'ClientOSError', 'ClientConnectorError', 'ClientProxyConnectionError',
  12. 'ClientSSLError',
  13. 'ClientConnectorSSLError', 'ClientConnectorCertificateError',
  14. 'ServerConnectionError', 'ServerTimeoutError', 'ServerDisconnectedError',
  15. 'ServerFingerprintMismatch',
  16. 'ClientResponseError', 'ClientHttpProxyError',
  17. 'WSServerHandshakeError', 'ContentTypeError',
  18. 'ClientPayloadError', 'InvalidURL')
  19. class ClientError(Exception):
  20. """Base class for client connection errors."""
  21. class ClientResponseError(ClientError):
  22. """Connection error during reading response.
  23. request_info: instance of RequestInfo
  24. """
  25. def __init__(self, request_info, history, *,
  26. code=None, status=None, message='', headers=None):
  27. self.request_info = request_info
  28. if code is not None:
  29. if status is not None:
  30. raise ValueError(
  31. "Both code and status arguments are provided; "
  32. "code is deprecated, use status instead")
  33. warnings.warn("code argument is deprecated, use status instead",
  34. DeprecationWarning,
  35. stacklevel=2)
  36. if status is not None:
  37. self.status = status
  38. elif code is not None:
  39. self.status = code
  40. else:
  41. self.status = 0
  42. self.message = message
  43. self.headers = headers
  44. self.history = history
  45. super().__init__("%s, message='%s'" % (self.status, message))
  46. @property
  47. def code(self):
  48. warnings.warn("code property is deprecated, use status instead",
  49. DeprecationWarning,
  50. stacklevel=2)
  51. return self.status
  52. @code.setter
  53. def code(self, value):
  54. warnings.warn("code property is deprecated, use status instead",
  55. DeprecationWarning,
  56. stacklevel=2)
  57. self.status = value
  58. class ContentTypeError(ClientResponseError):
  59. """ContentType found is not valid."""
  60. class WSServerHandshakeError(ClientResponseError):
  61. """websocket server handshake error."""
  62. class ClientHttpProxyError(ClientResponseError):
  63. """HTTP proxy error.
  64. Raised in :class:`aiohttp.connector.TCPConnector` if
  65. proxy responds with status other than ``200 OK``
  66. on ``CONNECT`` request.
  67. """
  68. class TooManyRedirects(ClientResponseError):
  69. """Client was redirected too many times."""
  70. class ClientConnectionError(ClientError):
  71. """Base class for client socket errors."""
  72. class ClientOSError(ClientConnectionError, OSError):
  73. """OSError error."""
  74. class ClientConnectorError(ClientOSError):
  75. """Client connector error.
  76. Raised in :class:`aiohttp.connector.TCPConnector` if
  77. connection to proxy can not be established.
  78. """
  79. def __init__(self, connection_key, os_error):
  80. self._conn_key = connection_key
  81. self._os_error = os_error
  82. super().__init__(os_error.errno, os_error.strerror)
  83. @property
  84. def os_error(self):
  85. return self._os_error
  86. @property
  87. def host(self):
  88. return self._conn_key.host
  89. @property
  90. def port(self):
  91. return self._conn_key.port
  92. @property
  93. def ssl(self):
  94. return self._conn_key.ssl
  95. def __str__(self):
  96. return ('Cannot connect to host {0.host}:{0.port} ssl:{0.ssl} [{1}]'
  97. .format(self, self.strerror))
  98. class ClientProxyConnectionError(ClientConnectorError):
  99. """Proxy connection error.
  100. Raised in :class:`aiohttp.connector.TCPConnector` if
  101. connection to proxy can not be established.
  102. """
  103. class ServerConnectionError(ClientConnectionError):
  104. """Server connection errors."""
  105. class ServerDisconnectedError(ServerConnectionError):
  106. """Server disconnected."""
  107. def __init__(self, message=None):
  108. self.message = message
  109. class ServerTimeoutError(ServerConnectionError, asyncio.TimeoutError):
  110. """Server timeout error."""
  111. class ServerFingerprintMismatch(ServerConnectionError):
  112. """SSL certificate does not match expected fingerprint."""
  113. def __init__(self, expected, got, host, port):
  114. self.expected = expected
  115. self.got = got
  116. self.host = host
  117. self.port = port
  118. def __repr__(self):
  119. return '<{} expected={} got={} host={} port={}>'.format(
  120. self.__class__.__name__, self.expected, self.got,
  121. self.host, self.port)
  122. class ClientPayloadError(ClientError):
  123. """Response payload error."""
  124. class InvalidURL(ClientError, ValueError):
  125. """Invalid URL.
  126. URL used for fetching is malformed, e.g. it doesn't contains host
  127. part."""
  128. # Derive from ValueError for backward compatibility
  129. def __init__(self, url):
  130. super().__init__(url)
  131. @property
  132. def url(self):
  133. return self.args[0]
  134. def __repr__(self):
  135. return '<{} {}>'.format(self.__class__.__name__, self.url)
  136. class ClientSSLError(ClientConnectorError):
  137. """Base error for ssl.*Errors."""
  138. if ssl is not None:
  139. cert_errors = (ssl.CertificateError,)
  140. cert_errors_bases = (ClientSSLError, ssl.CertificateError,)
  141. ssl_errors = (ssl.SSLError,)
  142. ssl_error_bases = (ClientSSLError, ssl.SSLError)
  143. else: # pragma: no cover
  144. cert_errors = tuple()
  145. cert_errors_bases = (ClientSSLError, ValueError,)
  146. ssl_errors = tuple()
  147. ssl_error_bases = (ClientSSLError,)
  148. class ClientConnectorSSLError(*ssl_error_bases): # type: ignore
  149. """Response ssl error."""
  150. class ClientConnectorCertificateError(*cert_errors_bases): # type: ignore
  151. """Response certificate error."""
  152. def __init__(self, connection_key, certificate_error):
  153. self._conn_key = connection_key
  154. self._certificate_error = certificate_error
  155. @property
  156. def certificate_error(self):
  157. return self._certificate_error
  158. @property
  159. def host(self):
  160. return self._conn_key.host
  161. @property
  162. def port(self):
  163. return self._conn_key.port
  164. @property
  165. def ssl(self):
  166. return self._conn_key.is_ssl
  167. def __str__(self):
  168. return ('Cannot connect to host {0.host}:{0.port} ssl:{0.ssl} '
  169. '[{0.certificate_error.__class__.__name__}: '
  170. '{0.certificate_error.args}]'.format(self))