Я пытаюсь написать простой HTTPS-сервер на Python и столкнулся со следующей странной проблемой.
Давайте начнем с простого HTTP-сервера:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import ssl
import time
import logging
from http import server
class MyHandler(server.SimpleHTTPRequestHandler):
def __init__(self, args, directory, kwargs):
if issubclass(server.SimpleHTTPRequestHandler, object):
super(MyHandler, self).__init__(args, directory, kwargs)
else:
server.SimpleHTTPRequestHandler.__init__(self, args, directory, kwargs)
def do_GET(self):
logging.log(logging.INFO, 'GET Header: {}'.format(self.path))
return self.send_response('')
# overload base class's send_response() to set appropriate headers and server version
def send_response(self, page, code=200, msg='OK'):
self.wfile.write('HTTP/1.1 {} {}\r\n'.format(code, msg).encode('utf-8'))
self.send_header('Server', 'Apache')
self.send_header('Content-Length', len(page))
self.send_header('Content-type', 'text/html')
self.send_header('Connection', 'Close')
self.end_headers()
if page != '':
self.wfile.write(page.encode('utf-8'))
def set_logger(file):
handler = logging.StreamHandler(file)
out_fmt = '[%(asctime)s.%(msecs)03dZ] [%(levelname)s] %(message)s'
dt_fmt = '%Y-%m-%d %H:%M:%S'
logging.Formatter.converter = time.gmtime
formatter = logging.Formatter(out_fmt, dt_fmt)
handler.setFormatter(formatter)
root = logging.getLogger()
root.setLevel(10)
root.addHandler(handler)
def main():
set_logger(sys.stdout)
logging.log(logging.INFO, 'Server started')
httpd = server.HTTPServer(('0.0.0.0', 4443), MyHandler)
# httpd.socket = ssl.wrap_socket(httpd.socket,
# certfile='ssl/cert.pem',
# keyfile='ssl/key.pem',
# server_side=True)
try:
httpd.serve_forever()
except KeyboardInterrupt:
logging.log(logging.INFO, 'Shutdown requested... exiting.')
except Exception:
traceback.print_exc(file=sys.stdout)
httpd.server_close()
sys.exit(0)
if __name__ == '__main__':
main()
Это работает просто в порядке (при просмотре http://localhost: 4443 отображается пустая страница) и при нажатии клавиши Ctrl- C из терминала она печатает сообщение и завершает работу.
Теперь давайте попробуем чтобы сделать его HTTPS-сервером, откомментировав строки, отмеченные символом «#». (И убедитесь, что самозаверяющий сертификат создан в каталоге ssl
с OpenSSL.) Это также хорошо работает и может быть прекращено с помощью Ctrl- C - но только на начальном этапе. Однако, как только поступает первый запрос GET, нажатие Ctrl- C из терминала больше не работает. На самом деле нажатие на него ничего не делает сразу. Однако после того, как другой GET-запрос поступил после нажатия Ctrl- C, Python печатает обычное сообщение трассировки, когда программа была прервана необработанным прерыванием клавиатуры (т.е. не нашим сообщением), но скрипт продолжает работать.
Что я делаю не так?