1c342db35SBrad Bishop# 292b42cb3SPatrick Williams# Copyright OpenEmbedded Contributors 392b42cb3SPatrick Williams# 4c342db35SBrad Bishop# SPDX-License-Identifier: MIT 5c342db35SBrad Bishop# 6c342db35SBrad Bishop 7eb8dc403SDave Cobbleyimport http.server 8*864cc43bSPatrick Williamsimport logging 9eb8dc403SDave Cobbleyimport multiprocessing 10eb8dc403SDave Cobbleyimport os 111a4b7ee2SBrad Bishopimport signal 12eb8dc403SDave Cobbleyfrom socketserver import ThreadingMixIn 13eb8dc403SDave Cobbley 14eb8dc403SDave Cobbleyclass HTTPServer(ThreadingMixIn, http.server.HTTPServer): 15eb8dc403SDave Cobbley 161a4b7ee2SBrad Bishop def server_start(self, root_dir, logger): 17eb8dc403SDave Cobbley os.chdir(root_dir) 18*864cc43bSPatrick Williams self.logger = logger 19eb8dc403SDave Cobbley self.serve_forever() 20eb8dc403SDave Cobbley 21eb8dc403SDave Cobbleyclass HTTPRequestHandler(http.server.SimpleHTTPRequestHandler): 22eb8dc403SDave Cobbley 23eb8dc403SDave Cobbley def log_message(self, format_str, *args): 24*864cc43bSPatrick Williams self.server.logger.info(format_str, *args) 25eb8dc403SDave Cobbley 26*864cc43bSPatrick Williamsclass HTTPService: 27eb8dc403SDave Cobbley 2882c905dcSAndrew Geissler def __init__(self, root_dir, host='', port=0, logger=None): 29eb8dc403SDave Cobbley self.root_dir = root_dir 30eb8dc403SDave Cobbley self.host = host 3182c905dcSAndrew Geissler self.port = port 32*864cc43bSPatrick Williams if logger: 33*864cc43bSPatrick Williams self.logger = logger.getChild("HTTPService") 34*864cc43bSPatrick Williams else: 35*864cc43bSPatrick Williams self.logger = logging.getLogger("HTTPService") 36eb8dc403SDave Cobbley 37eb8dc403SDave Cobbley def start(self): 381a4b7ee2SBrad Bishop if not os.path.exists(self.root_dir): 391a4b7ee2SBrad Bishop self.logger.info("Not starting HTTPService for directory %s which doesn't exist" % (self.root_dir)) 401a4b7ee2SBrad Bishop return 411a4b7ee2SBrad Bishop 42eb8dc403SDave Cobbley self.server = HTTPServer((self.host, self.port), HTTPRequestHandler) 43eb8dc403SDave Cobbley if self.port == 0: 44eb8dc403SDave Cobbley self.port = self.server.server_port 451a4b7ee2SBrad Bishop self.process = multiprocessing.Process(target=self.server.server_start, args=[self.root_dir, self.logger]) 461a4b7ee2SBrad Bishop 47*864cc43bSPatrick Williams def handle_error(self, request, client_address): 48*864cc43bSPatrick Williams import traceback 49*864cc43bSPatrick Williams exception = traceback.format_exc() 50*864cc43bSPatrick Williams self.logger.warn("Exception when handling %s: %s" % (request, exception)) 51*864cc43bSPatrick Williams self.server.handle_error = handle_error 52*864cc43bSPatrick Williams 531a4b7ee2SBrad Bishop # The signal handler from testimage.bbclass can cause deadlocks here 541a4b7ee2SBrad Bishop # if the HTTPServer is terminated before it can restore the standard 551a4b7ee2SBrad Bishop #signal behaviour 561a4b7ee2SBrad Bishop orig = signal.getsignal(signal.SIGTERM) 571a4b7ee2SBrad Bishop signal.signal(signal.SIGTERM, signal.SIG_DFL) 58eb8dc403SDave Cobbley self.process.start() 591a4b7ee2SBrad Bishop signal.signal(signal.SIGTERM, orig) 601a4b7ee2SBrad Bishop 611a4b7ee2SBrad Bishop if self.logger: 62*864cc43bSPatrick Williams self.logger.info("Started HTTPService for %s on %s:%s" % (self.root_dir, self.host, self.port)) 631a4b7ee2SBrad Bishop 64eb8dc403SDave Cobbley 65eb8dc403SDave Cobbley def stop(self): 661a4b7ee2SBrad Bishop if hasattr(self, "server"): 67eb8dc403SDave Cobbley self.server.server_close() 681a4b7ee2SBrad Bishop if hasattr(self, "process"): 69eb8dc403SDave Cobbley self.process.terminate() 70eb8dc403SDave Cobbley self.process.join() 711a4b7ee2SBrad Bishop if self.logger: 721a4b7ee2SBrad Bishop self.logger.info("Stopped HTTPService on %s:%s" % (self.host, self.port)) 731a4b7ee2SBrad Bishop 74*864cc43bSPatrick Williamsif __name__ == "__main__": 75*864cc43bSPatrick Williams import sys, logging 76*864cc43bSPatrick Williams 77*864cc43bSPatrick Williams logger = logging.getLogger(__name__) 78*864cc43bSPatrick Williams logging.basicConfig(level=logging.DEBUG) 79*864cc43bSPatrick Williams httpd = HTTPService(sys.argv[1], port=8888, logger=logger) 80*864cc43bSPatrick Williams httpd.start() 81