ThreadingTCPServer против ThreadingMix в HTTPServer - PullRequest
0 голосов
/ 05 октября 2019

Я запрограммировал два сервера, которые по сути делают то же самое разными способами. Оба являются веб-серверами с неблокирующей оболочкой ssl вокруг объекта сокета. Потоки позволяют обрабатывать несколько запросов одновременно.

Один использует ThreadingTCPServer, а другой вызывает ThreadingMixIn в модуле HTTPServer. Какой из них следует использовать и почему, если какой-либо из них лучше другого?

ThreadingMixIn на HTTPServer:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, ssl
from socketserver import ThreadingMixIn
from http.server import SimpleHTTPRequestHandler, HTTPServer

MYSERV_WORKDIR = "/media/kingdian/server_pub"
#MYSERV_CLIENTCRT = "/home/ran/keys/client.pem"
MYSERV_FULLCHAIN = "/home/ran/.acme.sh/example.com_ecc/fullchain.cer"
MYSERV_PRIVKEY = "/home/ran/.acme.sh/example.com_ecc/example.com.key"

global sslcontext
sslcontext = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
sslcontext.options |= ssl.OP_NO_TLSv1
sslcontext.options |= ssl.OP_NO_TLSv1_1
#sslcontext.options |= ssl.OP_NO_TLSv1_2
#sslcontext.protocol = ssl.PROTOCOL_TLS
#sslcontext.verify_mode = ssl.CERT_REQUIRED
sslcontext.set_ciphers("ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305")
sslcontext.set_ecdh_curve("secp384r1")
#sslcontext.load_verify_locations(MYSERV_CLIENTCRT)
sslcontext.load_cert_chain(MYSERV_FULLCHAIN, MYSERV_PRIVKEY)

class HSTSHandler(SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_header("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
        self.send_header("Content-Security-Policy", "default-src 'self'")
        self.send_header("X-Content-Type-Options", "nosniff")
        self.send_header("X-Frame-Options", "SAMEORIGIN")
        self.send_header("X-XSS-Protection", "1; mode=block")
        self.send_header("Referrer-Policy", "no-referrer")
        SimpleHTTPRequestHandler.end_headers(self)

class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
    daemon_threads = True

def main():
    try:
        os.chdir(MYSERV_WORKDIR)#auto-change working directory
        SimpleHTTPRequestHandler.sys_version = "002"#display custom Python system version
        SimpleHTTPRequestHandler.server_version = "001"#display custom server software version
        my_server = ThreadedHTTPServer(('', 443), HSTSHandler)
        my_server.socket = sslcontext.wrap_socket(my_server.socket, do_handshake_on_connect=False, server_side=True)
        print('Starting server, use <Ctrl-C> to stop')
        my_server.serve_forever()

    except KeyboardInterrupt:
        print(' received, shutting down server')
        my_server.shutdown()

if __name__ == '__main__':
    main()

ThreadingTCPServer:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os, ssl, socketserver
from http.server import SimpleHTTPRequestHandler

MYSERV_WORKDIR = "/media/kingdian/server_pub"
#MYSERV_CLIENTCRT = "/home/ran/keys/client.pem"
MYSERV_FULLCHAIN = "/home/ran/.acme.sh/example.com_ecc/fullchain.cer"
MYSERV_PRIVKEY = "/home/ran/.acme.sh/example.com_ecc/example.com.key"

global sslcontext
sslcontext = ssl.create_default_context(purpose=ssl.Purpose.CLIENT_AUTH)
sslcontext.options |= ssl.OP_NO_TLSv1
sslcontext.options |= ssl.OP_NO_TLSv1_1
#sslcontext.options |= ssl.OP_NO_TLSv1_2
#sslcontext.protocol = ssl.PROTOCOL_TLS
#sslcontext.verify_mode = ssl.CERT_REQUIRED
sslcontext.set_ciphers("ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305")
sslcontext.set_ecdh_curve("secp384r1")
#sslcontext.load_verify_locations(MYSERV_CLIENTCRT)
sslcontext.load_cert_chain(MYSERV_FULLCHAIN, MYSERV_PRIVKEY)

class HSTSHandler(SimpleHTTPRequestHandler):
    def end_headers(self):
        self.send_header("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload")
        self.send_header("Content-Security-Policy", "default-src 'self'")
        self.send_header("X-Content-Type-Options", "nosniff")
        self.send_header("X-Frame-Options", "SAMEORIGIN")
        self.send_header("X-XSS-Protection", "1; mode=block")
        self.send_header("Referrer-Policy", "no-referrer")
        SimpleHTTPRequestHandler.end_headers(self)

def main():
    try:
        os.chdir(MYSERV_WORKDIR)#auto-change working directory
        SimpleHTTPRequestHandler.sys_version = "002"#display custom Python system version
        SimpleHTTPRequestHandler.server_version = "001"#display custom server software version
        my_server = socketserver.ThreadingTCPServer(('', 443), HSTSHandler)
        my_server.socket = sslcontext.wrap_socket(my_server.socket, do_handshake_on_connect=False, server_side=True)
        print('Starting server, use <Ctrl-C> to stop')
        my_server.serve_forever()

    except KeyboardInterrupt:
        print(' received, shutting down server')
        my_server.shutdown()

if __name__ == '__main__':
    main()

1 Ответ

0 голосов
/ 05 октября 2019

Это почти два разных способа достижения одного и того же конечного результата. Если вы посмотрите на реализацию ThreadingTCPServer, то просто:

class ThreadingTCPServer(ThreadingMixIn, TCPServer): pass

В другом примере HTTPServer - это очень маленькая оболочка вокруг TCPServer (добавляет переопределение в server_bind длясохраните имя хоста сервера и автоматически установите allow_reuse_address), а затем ваш код непосредственно добавит ThreadingMixIn.

Так что, в конечном счете, вы в любом случае выполняете один и тот же базовый код. Иерархия классов в библиотеке python со временем немного изменилась, поэтому разные примеры кода заканчивали тем, что делали вещи в разных комбинациях.

Лично для ваших примеров я нахожу версию, которая использует ThreadingTCPServer чище, простопотому что один дополнительный класс обрабатывается в другом месте, и поэтому код немного меньше. OTOH, другая версия обеспечивает немного большую гибкость, так как вы уже определили точку, в которой вы можете управлять атрибутами смешивающего потока, плюс вы получите дополнительные HTTPServer биты обертки, если это станет важным для вас.

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