nghttpx.py 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. #***************************************************************************
  4. # _ _ ____ _
  5. # Project ___| | | | _ \| |
  6. # / __| | | | |_) | |
  7. # | (__| |_| | _ <| |___
  8. # \___|\___/|_| \_\_____|
  9. #
  10. # Copyright (C) 2008 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
  11. #
  12. # This software is licensed as described in the file COPYING, which
  13. # you should have received as part of this distribution. The terms
  14. # are also available at https://curl.se/docs/copyright.html.
  15. #
  16. # You may opt to use, copy, modify, merge, publish, distribute and/or sell
  17. # copies of the Software, and permit persons to whom the Software is
  18. # furnished to do so, under the terms of the COPYING file.
  19. #
  20. # This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  21. # KIND, either express or implied.
  22. #
  23. # SPDX-License-Identifier: curl
  24. #
  25. ###########################################################################
  26. #
  27. import datetime
  28. import logging
  29. import os
  30. import signal
  31. import subprocess
  32. import time
  33. from typing import Optional
  34. from .env import Env
  35. log = logging.getLogger(__name__)
  36. class Nghttpx:
  37. def __init__(self, env: Env):
  38. self.env = env
  39. self._cmd = env.nghttpx
  40. self._pid_file = os.path.join(env.gen_dir, 'nghttpx.pid')
  41. self._conf_file = os.path.join(env.gen_dir, 'nghttpx.conf')
  42. self._error_log = os.path.join(env.gen_dir, 'nghttpx.log')
  43. self._stderr = os.path.join(env.gen_dir, 'nghttpx.stderr')
  44. self._process = None
  45. self._process: Optional[subprocess.Popen] = None
  46. def exists(self):
  47. return os.path.exists(self._cmd)
  48. def clear_logs(self):
  49. self._rmf(self._error_log)
  50. self._rmf(self._stderr)
  51. def is_running(self):
  52. if self._process:
  53. self._process.poll()
  54. return self._process.returncode is None
  55. return False
  56. def start(self):
  57. if self._process:
  58. self.stop()
  59. self._write_config()
  60. args = [
  61. self._cmd,
  62. f'--frontend=*,{self.env.h3_port};quic',
  63. f'--backend=127.0.0.1,{self.env.https_port};{self.env.domain1};sni={self.env.domain1};proto=h2;tls',
  64. f'--backend=127.0.0.1,{self.env.http_port}',
  65. f'--log-level=INFO',
  66. f'--pid-file={self._pid_file}',
  67. f'--errorlog-file={self._error_log}',
  68. f'--conf={self._conf_file}',
  69. f'--cacert={self.env.ca.cert_file}',
  70. self.env.get_credentials(self.env.domain1).pkey_file,
  71. self.env.get_credentials(self.env.domain1).cert_file,
  72. ]
  73. ngerr = open(self._stderr, 'a')
  74. self._process = subprocess.Popen(args=args, stderr=ngerr)
  75. return self._process.returncode is None
  76. def stop(self):
  77. if self._process:
  78. self._process.terminate()
  79. self._process.wait(timeout=2)
  80. self._process = None
  81. return True
  82. def restart(self):
  83. self.stop()
  84. return self.start()
  85. def reload(self, timeout: datetime.timedelta):
  86. if self._process:
  87. running = self._process
  88. os.kill(running.pid, signal.SIGQUIT)
  89. self.start()
  90. try:
  91. log.debug(f'waiting for nghttpx({running.pid}) to exit.')
  92. running.wait(timeout=timeout.seconds)
  93. log.debug(f'nghttpx({running.pid}) terminated -> {running.returncode}')
  94. return True
  95. except subprocess.TimeoutExpired:
  96. log.error(f'SIGQUIT nghttpx({running.pid}), but did not shut down.')
  97. return False
  98. def _rmf(self, path):
  99. if os.path.exists(path):
  100. return os.remove(path)
  101. def _mkpath(self, path):
  102. if not os.path.exists(path):
  103. return os.makedirs(path)
  104. def _write_config(self):
  105. with open(self._conf_file, 'w') as fd:
  106. fd.write(f'# nghttpx test config'),
  107. fd.write("\n".join([
  108. '# do we need something here?'
  109. ]))