Избегание ChunkedEncodingError для пустой части с запросами 2.3.0

Я использую Запросы для загрузки файла (несколько гигабайт) с сервера. Чтобы обеспечить обновления хода выполнения (и чтобы весь файл не мог быть сохранен в памяти), я установил stream=True и написал загрузку в файл:

with open('output', 'w') as f:
    response = requests.get(url, stream=True)

    if not response.ok:
        print 'There was an error'
        exit()

    for block in response.iter_content(1024 * 100):
        f.write(block)
        completed_bytes += len(block)
        write_progress(completed_bytes, total_bytes)

Однако в какой-то случайной точке загрузки Requests выбрасывает ChunkedEncodingError. Я попал в источник и обнаружил, что соответствует исключению IncompleteRead. Я вставил оператор журнала вокруг этих строк и обнаружил, что e.partial = "\r". Я знаю, что сервер придает загрузке низкий приоритет, и я подозреваю, что это исключение возникает, когда сервер слишком долго ждет отправки следующего фрагмента.

Как и ожидалось, исключение останавливает загрузку. К сожалению, сервер не реализует диапазоны контента HTTP/1.1, поэтому я не могу просто возобновить его. Я играл с увеличением внутреннего тайм-аута urllib3, но исключение все еще сохраняется.

В любом случае, чтобы сделать основной urllib3 (или Requests) более терпимым к этим пустым (или более поздним) фрагментам, чтобы файл мог полностью загрузить?

Ответ 1

import httplib

def patch_http_response_read(func):
    def inner(*args):
        try:
            return func(*args)
        except httplib.IncompleteRead, e:
            return e.partial
    return inner

httplib.HTTPResponse.read = patch_http_response_read(httplib.HTTPResponse.read)

Я не могу воспроизвести вашу проблему прямо сейчас, но я думаю, что это может быть патч. Это позволяет вам работать с дефектными серверами http.

Большинство плохих серверов передают все данные, но из-за ошибок реализации они неправильно закрывают сессию и httplib повышают ошибку и хоронят ваши драгоценные байты.