1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# SPDX-License-Identifier: MIT 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun 5*4882a593Smuzhiyunimport http.server 6*4882a593Smuzhiyunimport multiprocessing 7*4882a593Smuzhiyunimport os 8*4882a593Smuzhiyunimport traceback 9*4882a593Smuzhiyunimport signal 10*4882a593Smuzhiyunfrom socketserver import ThreadingMixIn 11*4882a593Smuzhiyun 12*4882a593Smuzhiyunclass HTTPServer(ThreadingMixIn, http.server.HTTPServer): 13*4882a593Smuzhiyun 14*4882a593Smuzhiyun def server_start(self, root_dir, logger): 15*4882a593Smuzhiyun os.chdir(root_dir) 16*4882a593Smuzhiyun self.serve_forever() 17*4882a593Smuzhiyun 18*4882a593Smuzhiyunclass HTTPRequestHandler(http.server.SimpleHTTPRequestHandler): 19*4882a593Smuzhiyun 20*4882a593Smuzhiyun def log_message(self, format_str, *args): 21*4882a593Smuzhiyun pass 22*4882a593Smuzhiyun 23*4882a593Smuzhiyunclass HTTPService(object): 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun def __init__(self, root_dir, host='', port=0, logger=None): 26*4882a593Smuzhiyun self.root_dir = root_dir 27*4882a593Smuzhiyun self.host = host 28*4882a593Smuzhiyun self.port = port 29*4882a593Smuzhiyun self.logger = logger 30*4882a593Smuzhiyun 31*4882a593Smuzhiyun def start(self): 32*4882a593Smuzhiyun if not os.path.exists(self.root_dir): 33*4882a593Smuzhiyun self.logger.info("Not starting HTTPService for directory %s which doesn't exist" % (self.root_dir)) 34*4882a593Smuzhiyun return 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun self.server = HTTPServer((self.host, self.port), HTTPRequestHandler) 37*4882a593Smuzhiyun if self.port == 0: 38*4882a593Smuzhiyun self.port = self.server.server_port 39*4882a593Smuzhiyun self.process = multiprocessing.Process(target=self.server.server_start, args=[self.root_dir, self.logger]) 40*4882a593Smuzhiyun 41*4882a593Smuzhiyun def handle_error(self, request, client_address): 42*4882a593Smuzhiyun import traceback 43*4882a593Smuzhiyun exception = traceback.format_exc() 44*4882a593Smuzhiyun self.logger.warn("Exception when handling %s: %s" % (request, exception)) 45*4882a593Smuzhiyun self.server.handle_error = handle_error 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun # The signal handler from testimage.bbclass can cause deadlocks here 48*4882a593Smuzhiyun # if the HTTPServer is terminated before it can restore the standard 49*4882a593Smuzhiyun #signal behaviour 50*4882a593Smuzhiyun orig = signal.getsignal(signal.SIGTERM) 51*4882a593Smuzhiyun signal.signal(signal.SIGTERM, signal.SIG_DFL) 52*4882a593Smuzhiyun self.process.start() 53*4882a593Smuzhiyun signal.signal(signal.SIGTERM, orig) 54*4882a593Smuzhiyun 55*4882a593Smuzhiyun if self.logger: 56*4882a593Smuzhiyun self.logger.info("Started HTTPService on %s:%s" % (self.host, self.port)) 57*4882a593Smuzhiyun 58*4882a593Smuzhiyun 59*4882a593Smuzhiyun def stop(self): 60*4882a593Smuzhiyun if hasattr(self, "server"): 61*4882a593Smuzhiyun self.server.server_close() 62*4882a593Smuzhiyun if hasattr(self, "process"): 63*4882a593Smuzhiyun self.process.terminate() 64*4882a593Smuzhiyun self.process.join() 65*4882a593Smuzhiyun if self.logger: 66*4882a593Smuzhiyun self.logger.info("Stopped HTTPService on %s:%s" % (self.host, self.port)) 67*4882a593Smuzhiyun 68