blob: 80752c137707eec9fc34eb83e850b8a5bb606f34 [file] [log] [blame]
Brad Bishopc342db32019-05-15 21:57:59 -04001#
Patrick Williams92b42cb2022-09-03 06:53:57 -05002# Copyright OpenEmbedded Contributors
3#
Brad Bishopc342db32019-05-15 21:57:59 -04004# SPDX-License-Identifier: MIT
5#
6
Patrick Williamsc0f7c042017-02-23 20:41:17 -06007import http.server
Patrick Williams864cc432023-02-09 14:54:44 -06008import logging
Patrick Williamsc124f4f2015-09-15 14:41:29 -05009import multiprocessing
10import os
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080011import signal
Patrick Williamsc0f7c042017-02-23 20:41:17 -060012from socketserver import ThreadingMixIn
Patrick Williamsc124f4f2015-09-15 14:41:29 -050013
Patrick Williamsc0f7c042017-02-23 20:41:17 -060014class HTTPServer(ThreadingMixIn, http.server.HTTPServer):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050015
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080016 def server_start(self, root_dir, logger):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050017 os.chdir(root_dir)
Patrick Williams864cc432023-02-09 14:54:44 -060018 self.logger = logger
Patrick Williamsc124f4f2015-09-15 14:41:29 -050019 self.serve_forever()
20
Patrick Williamsc0f7c042017-02-23 20:41:17 -060021class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050022
23 def log_message(self, format_str, *args):
Patrick Williams864cc432023-02-09 14:54:44 -060024 self.server.logger.info(format_str, *args)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050025
Patrick Williams864cc432023-02-09 14:54:44 -060026class HTTPService:
Patrick Williamsc124f4f2015-09-15 14:41:29 -050027
Andrew Geissler82c905d2020-04-13 13:39:40 -050028 def __init__(self, root_dir, host='', port=0, logger=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029 self.root_dir = root_dir
30 self.host = host
Andrew Geissler82c905d2020-04-13 13:39:40 -050031 self.port = port
Patrick Williams864cc432023-02-09 14:54:44 -060032 if logger:
33 self.logger = logger.getChild("HTTPService")
34 else:
35 self.logger = logging.getLogger("HTTPService")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036
37 def start(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080038 if not os.path.exists(self.root_dir):
39 self.logger.info("Not starting HTTPService for directory %s which doesn't exist" % (self.root_dir))
40 return
41
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042 self.server = HTTPServer((self.host, self.port), HTTPRequestHandler)
43 if self.port == 0:
44 self.port = self.server.server_port
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080045 self.process = multiprocessing.Process(target=self.server.server_start, args=[self.root_dir, self.logger])
46
Patrick Williams864cc432023-02-09 14:54:44 -060047 def handle_error(self, request, client_address):
48 import traceback
49 exception = traceback.format_exc()
50 self.logger.warn("Exception when handling %s: %s" % (request, exception))
51 self.server.handle_error = handle_error
52
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080053 # The signal handler from testimage.bbclass can cause deadlocks here
54 # if the HTTPServer is terminated before it can restore the standard
55 #signal behaviour
56 orig = signal.getsignal(signal.SIGTERM)
57 signal.signal(signal.SIGTERM, signal.SIG_DFL)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058 self.process.start()
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080059 signal.signal(signal.SIGTERM, orig)
60
61 if self.logger:
Patrick Williams864cc432023-02-09 14:54:44 -060062 self.logger.info("Started HTTPService for %s on %s:%s" % (self.root_dir, self.host, self.port))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080063
Patrick Williamsc124f4f2015-09-15 14:41:29 -050064
65 def stop(self):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -080066 if hasattr(self, "server"):
67 self.server.server_close()
68 if hasattr(self, "process"):
69 self.process.terminate()
70 self.process.join()
71 if self.logger:
72 self.logger.info("Stopped HTTPService on %s:%s" % (self.host, self.port))
73
Patrick Williams864cc432023-02-09 14:54:44 -060074if __name__ == "__main__":
75 import sys, logging
76
77 logger = logging.getLogger(__name__)
78 logging.basicConfig(level=logging.DEBUG)
79 httpd = HTTPService(sys.argv[1], port=8888, logger=logger)
80 httpd.start()