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 не работает, когда вы получаете ответ с того же сайта, то это то, что, вероятно, происходит.
Возможное решение:
- В CPython 3.7 HttpServer имеет параметры, поддерживающие предварительное подключение. Посмотрите на HttpThreadingServer в документации.
Поместите передачу запроса в отдельный поток и установите время ожидания этого потока, когда операция чтения занимает слишком много времени.
Оба из них являются потенциально болезненными решениями, но по крайней мере это должно помочь вам начать.
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)
Но оба, скорее всего, будут мешать коду обработчика запросов и требуют тщательного тестирования.