Interceptig KeyboardInterrupt при использовании wrap_socket - PullRequest
0 голосов
/ 29 января 2020

Я пытаюсь написать простой 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 печатает обычное сообщение трассировки, когда программа была прервана необработанным прерыванием клавиатуры (т.е. не нашим сообщением), но скрипт продолжает работать.

Что я делаю не так?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...