requests.py 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. ########################################################################
  2. # Searx-qt - Lightweight desktop application for SearX.
  3. # Copyright (C) 2020 CYBERDEViL
  4. #
  5. # This file is part of Searx-qt.
  6. #
  7. # Searx-qt is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU General Public License as published by
  9. # the Free Software Foundation, either version 3 of the License, or
  10. # (at your option) any later version.
  11. #
  12. # Searx-qt is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License
  18. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. #
  20. ########################################################################
  21. import requests
  22. from requests.exceptions import HTTPError, ConnectionError, Timeout
  23. import json
  24. class ErrorType:
  25. HttpError = 0
  26. ConnectionError = 1
  27. Timeout = 3
  28. WrongStatus = 4
  29. DecodeError = 5
  30. NoResults = 6
  31. NotSpecified = 7
  32. ErrorTypeStr = {
  33. ErrorType.HttpError: "HttpError",
  34. ErrorType.ConnectionError: "ConnectionError",
  35. ErrorType.Timeout: "Timeout",
  36. ErrorType.WrongStatus: "WrongStatus",
  37. ErrorType.DecodeError: "DecodeError",
  38. ErrorType.NoResults: "NoResults",
  39. ErrorType.NotSpecified: "NotSpecified"
  40. }
  41. class Result:
  42. def __init__(self, response, err="", errType=None, acceptCodes=None):
  43. self._response = response
  44. self._err = err
  45. self._errType = errType
  46. acceptCodes = acceptCodes
  47. if not acceptCodes:
  48. acceptCodes = [200]
  49. if errType is None and response.status_code not in acceptCodes:
  50. self._errType = ErrorType.WrongStatus
  51. self._err = "WrongStatus: {0}".format(self._response.status_code)
  52. else:
  53. self.verifyFurther()
  54. def __bool__(self):
  55. return not self.failed()
  56. def errorType(self): return self._errType
  57. def error(self): return self._err
  58. def content(self):
  59. """ In case json.loads failed and we want to debug.
  60. """
  61. if self._response == None:
  62. return b''
  63. return self._response.content
  64. def text(self):
  65. if self._response == None:
  66. return ''
  67. return self._response.text
  68. def failed(self):
  69. if self._errType is not None:
  70. return True
  71. return False
  72. def statusCode(self):
  73. if self._response != None:
  74. return self._response.status_code
  75. return 0
  76. def verifyFurther(self):
  77. pass
  78. class JsonResult(Result):
  79. def __init__(self, response, err="", errType=None, acceptCodes=None):
  80. Result.__init__(
  81. self,
  82. response,
  83. err=err,
  84. errType=errType,
  85. acceptCodes=acceptCodes
  86. )
  87. def verifyFurther(self):
  88. try:
  89. self.json()
  90. except json.JSONDecodeError as err:
  91. self._errType = ErrorType.DecodeError
  92. self._err = "DecodeError: `{0}`".format(err)
  93. except UnicodeDecodeError as err:
  94. # This could happen when the response encoding isn't plain ? (gzip)
  95. # Or we just have malformed data/crap.
  96. self._errType = ErrorType.DecodeError
  97. self._err = "DecodeError: `{0}`".format(err)
  98. def json(self):
  99. if self.errorType() is not None:
  100. return {}
  101. return json.loads(self._response.content)
  102. class RequestsHandler:
  103. def __init__(self, settings):
  104. """
  105. @param settings: TODO don't use Qt stuff in core.
  106. @type settings: searxqt.models.RequestSettingsModel
  107. """
  108. self._settings = settings
  109. def failSafeRequestFactory(func):
  110. def failSafeRequest(self, url, data=None, ResultType=None):
  111. response = None
  112. err = ""
  113. errType = None
  114. if not ResultType:
  115. # When 'ResultType' isn't specified, set 'JsonResult' as
  116. # default.
  117. ResultType = JsonResult
  118. print("<NEW Request>")
  119. print("# ------------------------")
  120. print("# ResultType : {0}".format(ResultType))
  121. try:
  122. response = func(self, url, data=data, **self._settings.kwargs)
  123. except HTTPError as e:
  124. print("Request failed! HTTPError: {0}".format(e))
  125. errType = ErrorType.HttpError
  126. err = e
  127. except ConnectionError as e:
  128. print("Request failed! ConnectionError: {0}".format(e))
  129. errType = ErrorType.ConnectionError
  130. err = e
  131. except Timeout as e:
  132. print("Request failed! Timeout: {0}".format(e))
  133. errType = ErrorType.Timeout
  134. err = e
  135. print("# ------------------------")
  136. print()
  137. return ResultType(response=response, err=err, errType=errType)
  138. return failSafeRequest
  139. @failSafeRequestFactory
  140. def get(self, url, data=None, ResultType=None, **settingsKwargs):
  141. print("# Type : GET")
  142. print("# URL : {0}".format(url))
  143. print("# Data : {0}".format(data))
  144. print("# Kwargs : {0}".format(settingsKwargs))
  145. return requests.get(url, data=data, **settingsKwargs)
  146. @failSafeRequestFactory
  147. def post(self, url, data=None, ResultType=None, **settingsKwargs):
  148. print("# Type : POST")
  149. print("# URL : {0}".format(url))
  150. print("# Data : {0}".format(data))
  151. print("# Kwargs : {0}".format(settingsKwargs))
  152. return requests.post(url, data=data, **settingsKwargs)