1#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
7import http.server
8import logging
9import multiprocessing
10import os
11import signal
12from socketserver import ThreadingMixIn
13
14class HTTPServer(ThreadingMixIn, http.server.HTTPServer):
15
16    def server_start(self, root_dir, logger):
17        os.chdir(root_dir)
18        self.logger = logger
19        self.serve_forever()
20
21class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
22
23    def log_message(self, format_str, *args):
24        self.server.logger.info(format_str, *args)
25
26class HTTPService:
27
28    def __init__(self, root_dir, host='', port=0, logger=None):
29        self.root_dir = root_dir
30        self.host = host
31        self.port = port
32        if logger:
33            self.logger = logger.getChild("HTTPService")
34        else:
35            self.logger = logging.getLogger("HTTPService")
36
37    def start(self):
38        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
42        self.server = HTTPServer((self.host, self.port), HTTPRequestHandler)
43        if self.port == 0:
44            self.port = self.server.server_port
45        self.process = multiprocessing.Process(target=self.server.server_start, args=[self.root_dir, self.logger])
46
47        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
53        # 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)
58        self.process.start()
59        signal.signal(signal.SIGTERM, orig)
60
61        if self.logger:
62            self.logger.info("Started HTTPService for %s on %s:%s" % (self.root_dir, self.host, self.port))
63
64
65    def stop(self):
66        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
74if __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()
81