Пользовательская реализация Python http.server не работает должным образом, когда включен HTTPS.Python

Программы на Python
Ответить
Anonymous
 Пользовательская реализация Python http.server не работает должным образом, когда включен HTTPS.

Сообщение Anonymous »

Мне известно, что модуль Python http.server был задуман в основном для целей тестирования, поскольку в его реализации есть некоторые хорошо известные проблемы безопасности.
Тем не менее, для очень скромного личного проекта я реализовал свой собственный класс, производный от http.server.BaseHTTPRequestHandler, в котором я переопределил метод do_GET. Все работало правильно, пока я не обновил версию Python до 3.12: кажется, эта версия также внесла некоторые изменения в модуль ssl, поэтому мне пришлось немного реорганизовать код.
В этом отношении это сжатое содержимое файла main.py:

Код: Выделить всё

# ...here are import statements and other functions...

class RequestHandler(BaseHTTPRequestHandler):

# ...here the other methods are defined...

def do_GET(self):
resobj = self._manage_get_request()
self.send_response(resobj.status_code)
self._send_headers(resobj.headers)
self._send_body(resobj.body)

def main():
print('Running http server...')
address = (_HTTP_SERV_ADDR, _HTTP_SERV_PORT)
httpd = HTTPServer(address, RequestHandler)
if not _DEBUG_ENABLED:
print('Enabling TLS protocol...')
context = _ssl.SSLContext(_ssl.PROTOCOL_TLS_SERVER)
context.load_cert_chain(certfile=_CERTIFICATE_FILE_PATH,
keyfile=_KEY_FILE_PATH)
httpd.socket = context.wrap_socket(httpd.socket, server_side=True)
print(f'Server is listening ({httpd.server_address[0]}:{httpd.server_port})...')
try:
httpd.serve_forever()
except KeyboardInterrupt:
pass
print('Shutting down http server...')
httpd.server_close()
Если отладка включена и часть кода, связанная с HTTPS, пропускается, сервер работает правильно. Вместо этого, когда отладка отключена, сервер, кажется, тоже работает нормально, но через несколько часов он перестает отвечать: истекает время ожидания всех запросов на соединение.
Не мог бы кто-нибудь из вас предоставить мне что-нибудь подскажет, что проверить, чтобы лучше понять, что происходит и почему?
Дополнительная информация по реализации
Хотя send_response уже определен в BaseHTTPRequestHandler, остальные методы, вызываемые в do_GET, определены в моей реализации. В частности:
  • Код: Выделить всё

    _manage_get_request
    — это своего рода оператор if для правильного управления запросом с учетом параметров, предоставленных через запрос; он возвращает пользовательский объект Response с кодом, заголовками и телом
  • Код: Выделить всё

    _send_headers
    по сути является оболочкой метода send_header родительского класса
  • Код: Выделить всё

    _send_body
    просто записывает тело ответа в буфер сокета.
Обновление от 6 января 2025 г. >
После того как я задал этот вопрос, я попробовал несколько изменений в коде, но на самом деле ни одно из них не решило проблему.
Итак, я решил реализовать скромный декоратор для отслеживания стека вызовов функций. С помощью этого небольшого инструмента я заметил, что код висит внутри метода get_request класса TCPServer, где принимается новое TCP-соединение:

Код: Выделить всё

[...]
----- Calling BaseServer.service_actions on 2025-01-05 15:59:15.092364 -----
BaseServer.service_actions execution ended after 0:00:00.000015
----- Calling BaseServer._handle_request_noblock on 2025-01-05 15:59:15.282698 -----
----- Calling TCPServer.get_request on 2025-01-05 15:59:15.282869 -----
Честно говоря, я не знаю причину такого поведения (вижу только, что это происходит, когда сервер получает больше запроса почти в одно и то же время, всего лишь вопрос десятых долей во-вторых), но пока я переопределяю рассматриваемый метод, добавляя простой механизм тайм-аута:

Код: Выделить всё

class TimeoutException(BaseException):
pass

def alarm_handler(signum, frame):
print('Timeout reached!')
raise TimeoutException

def get_request(self):
# Overwrite method of TCPServer class...
_signal.signal(_signal.SIGALRM, alarm_handler)
_signal.alarm(30)
try:
result = self.socket.accept()
_signal.alarm(0)
return result
except TimeoutException as e:
_signal.alarm(0)
raise OSError from e  # OSError is already managed by caller...
Я знаю, что это неэффективное решение проблемы, но оно позволяет серверу каким-то образом продолжать работать, поэтому его можно рассматривать как временный обходной путь.
Тем не менее, может ли кто-нибудь из вас объяснить, каковы возможные причины этой проблемы и как ее решить? Рассматриваемое приложение работает внутри образа Docker, полученного из ubuntu:latest.

Подробнее здесь: https://stackoverflow.com/questions/793 ... n-https-is
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Python»