cms-backd 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Simple CMS
  5. #
  6. # Copyright (C) 2011-2024 Michael Büsch <m@bues.ch>
  7. #
  8. # This program is free software: you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License as published by
  10. # the Free Software Foundation, either version 2 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. import sys
  21. sys.path.insert(0, "/opt/cms/lib/python3/site-packages/")
  22. import os, fcntl, socket, atexit, time
  23. try:
  24. from cms_cython.socket import *
  25. from cms_cython import CMS, CMSException
  26. except ImportError as e:
  27. print("cms-backd: Failed to import cms_cython:", e, file=sys.stderr)
  28. from cms.socket import *
  29. from cms import CMS, CMSException
  30. def init_systemd():
  31. notify_socket = os.getenv("NOTIFY_SOCKET")
  32. if not notify_socket:
  33. raise ValueError("env: NOTIFY_SOCKET not set.")
  34. listen_fds = os.getenv("LISTEN_FDS")
  35. if not listen_fds:
  36. raise ValueError("env: LISTEN_FDS not set.")
  37. listen_fds = int(listen_fds, 10)
  38. if listen_fds <= 0 or listen_fds > 1:
  39. raise ValueError("env: Invalid LISTEN_FDS.")
  40. with socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM) as sdsock:
  41. sdsock.connect(notify_socket)
  42. fd = 3
  43. for i in range(fd, fd + listen_fds):
  44. fcntl.fcntl(i, fcntl.F_SETFD, fcntl.FD_CLOEXEC)
  45. backsock = socket.fromfd(fd, socket.AF_UNIX, socket.SOCK_STREAM)
  46. sdsock.sendall(b"READY=1")
  47. return backsock
  48. def run_backd(backsock):
  49. cms = CMS(domain="", debug=True)
  50. atexit.register(cms.shutdown)
  51. while True:
  52. try:
  53. conn, addr = backsock.accept()
  54. msg = recv_message(conn, MAGIC_BACK)
  55. except Exception as e:
  56. print(f"cms-backd: Receive failed: {e}", file=sys.stderr)
  57. continue
  58. if cms.debug:
  59. startStamp = time.monotonic()
  60. status = 200 # Ok
  61. reply_body = b""
  62. reply_mime = ""
  63. extra_headers = []
  64. try:
  65. if isinstance(msg, MsgGet):
  66. cms.domain = msg.host
  67. protocol = "https" if msg.https else "http"
  68. reply_body, reply_mime = cms.get(msg.path, msg.query, protocol)
  69. elif isinstance(msg, MsgPost):
  70. cms.domain = msg.host
  71. protocol = "https" if msg.https else "http"
  72. reply_body, reply_mime = cms.post(msg.path, msg.query, msg.body, msg.body_mime, protocol)
  73. else:
  74. raise RuntimeError("Received invalid message.")
  75. except CMSException as e:
  76. status = e.httpStatusCode
  77. reply_body, reply_mime, extra_headers = cms.getErrorPage(e, protocol)
  78. if cms.debug and "html" in reply_mime:
  79. delta = time.monotonic() - startStamp
  80. ms = delta * 1e3
  81. reply_body += ("\n<!-- generated in %.3f ms -->" % ms).encode("UTF-8", "ignore")
  82. reply = MsgReply(
  83. status=status,
  84. body=reply_body,
  85. mime=reply_mime,
  86. extra_headers=extra_headers,
  87. )
  88. reply_data = reply.pack()
  89. try:
  90. conn.sendall(reply_data)
  91. except Exception as e:
  92. print(f"cms-backd: Failed to send reply: {e}", file=sys.stderr)
  93. continue
  94. if __name__ == "__main__":
  95. run_backd(init_systemd())
  96. # vim: ts=4 sw=4 expandtab