Python: чтение из rfile в SimpleHTTPRequestHandler

При перегрузке SimpleHTTPRequestHandler моя функция блокирует функцию self.rfile.read(). Как узнать, есть ли какие-либо данные в rfile перед чтением? Альтернативно, есть ли неблокирующий вызов чтения, который возвращается при отсутствии данных?

2 ответа

Для записи решение состоит в том, чтобы только попытаться прочитать столько байтов, сколько указано в заголовке Content-Length. то есть что-то вроде:

contentLength = int(request.headers['Content-Length'])
payload = str(request.rfile.read(contentLength))

Я только что решил такой случай.

Я почти уверен, что означает "что надо", это бесконечный поток битов, записываемый в ваш сокет клиентом, к которому вы подключены. Это часто называют "предварительным соединением", и это происходит потому, что http/tcp/HttpServer не делает существенного различия между "кусками" и одиночными байтами, которые медленно передаются в соединение. Если вы видите, что заголовок ответа содержит Transfer-Encoding: chunked Вы являетесь кандидатом на это. Google Chrome работает таким образом и является хорошим тестом. Если Fire Fox и IE работают, но Chrome не работает, когда вы получаете ответ с того же сайта, то это то, что, вероятно, происходит.

Возможное решение:

  1. В CPython 3.7 HttpServer имеет параметры, поддерживающие предварительное подключение. Посмотрите на HttpThreadingServer в документации.
  2. Поместите передачу запроса в отдельный поток и установите время ожидания этого потока, когда операция чтения занимает слишком много времени.

    Оба из них являются потенциально болезненными решениями, но по крайней мере это должно помочь вам начать.

rfile а также wfile являются обертками на базовое соединение. Вы можете select на что. Если вы даете timeout из 0 он просто проверит и немедленно вернется.

[ready_to_read, _, _] = select.select([self.connection], [], [], timeout)
if ready_to_read:
    self.rfile.read()

Вы также можете установить тайм-аут на соединение:

self.connection.settimeout(timeout)

Или переведите его в неблокирующий режим

self.connection.setblocking(0)

Но оба, скорее всего, будут мешать коду обработчика запросов и требуют тщательного тестирования.

Другие вопросы по тегам