Modern ActivityPub compliant server, designed for simplicity and accessibility. Includes calendar and sharing economy features to empower your federated community. https://code.freedombone.net/bashrc/epicyon Docs: https://epicyon.net/#install
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.

siteactive.py 3.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. __filename__ = "siteactive.py"
  2. __author__ = "Bob Mottram"
  3. __credits__ = ["webchk"]
  4. __license__ = "AGPL3+"
  5. __version__ = "1.2.0"
  6. __maintainer__ = "Bob Mottram"
  7. __email__ = "bob@freedombone.net"
  8. __status__ = "Production"
  9. import http.client
  10. from urllib.parse import urlparse
  11. import ssl
  12. class Result:
  13. """Holds result of an URL check.
  14. The redirect attribute is a Result object that the URL was redirected to.
  15. The sitemap_urls attribute will contain a list of Result object if url
  16. is a sitemap file and http_response() was run with parse set to True.
  17. """
  18. def __init__(self, url):
  19. self.url = url
  20. self.status = 0
  21. self.desc = ''
  22. self.headers = None
  23. self.latency = 0
  24. self.content = ''
  25. self.redirect = None
  26. self.sitemap_urls = None
  27. def __repr__(self):
  28. if self.status == 0:
  29. return '{} ... {}'.format(self.url, self.desc)
  30. return '{} ... {} {} ({})'.format(
  31. self.url, self.status, self.desc, self.latency
  32. )
  33. def fill_headers(self, headers):
  34. """Takes a list of tuples and converts it a dictionary."""
  35. self.headers = {h[0]: h[1] for h in headers}
  36. def _siteActiveParseUrl(url):
  37. """Returns an object with properties representing
  38. scheme: URL scheme specifier
  39. netloc: Network location part
  40. path: Hierarchical path
  41. params: Parameters for last path element
  42. query: Query component
  43. fragment: Fragment identifier
  44. username: User name
  45. password: Password
  46. hostname: Host name (lower case)
  47. port: Port number as integer, if present
  48. """
  49. loc = urlparse(url)
  50. # if the scheme (http, https ...) is not available urlparse wont work
  51. if loc.scheme == "":
  52. url = "http://" + url
  53. loc = urlparse(url)
  54. return loc
  55. def _siteACtiveHttpConnect(loc, timeout: int):
  56. """Connects to the host and returns an HTTP or HTTPS connections."""
  57. if loc.scheme == "https":
  58. ssl_context = ssl.SSLContext()
  59. return http.client.HTTPSConnection(
  60. loc.netloc, context=ssl_context, timeout=timeout)
  61. return http.client.HTTPConnection(loc.netloc, timeout=timeout)
  62. def _siteActiveHttpRequest(loc, timeout: int):
  63. """Performs a HTTP request and return response in a Result object.
  64. """
  65. conn = _siteACtiveHttpConnect(loc, timeout)
  66. method = 'HEAD'
  67. conn.request(method, loc.path)
  68. resp = conn.getresponse()
  69. result = Result(loc.geturl())
  70. result.status = resp.status
  71. result.desc = resp.reason
  72. result.fill_headers(resp.getheaders())
  73. conn.close()
  74. return result
  75. def siteIsActive(url: str, timeout=10) -> bool:
  76. """Returns true if the current url is resolvable.
  77. This can be used to check that an instance is online before
  78. trying to send posts to it.
  79. """
  80. if not url.startswith('http'):
  81. return False
  82. if '.onion/' in url or '.i2p/' in url or \
  83. url.endswith('.onion') or \
  84. url.endswith('.i2p'):
  85. # skip this check for onion and i2p
  86. return True
  87. loc = _siteActiveParseUrl(url)
  88. result = Result(url=url)
  89. try:
  90. result = _siteActiveHttpRequest(loc, timeout)
  91. if 400 <= result.status < 500:
  92. return result
  93. return True
  94. except BaseException:
  95. pass
  96. return False