Сообщение об ошибке
curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0
Также выводится как
- curl: (56) OpenSSL SSL_read: OpenSSL/3.5.7: error:0A000126:SSL routines::unexpected eof while reading, errno 0
Последние версии curl вставляют после «SSL_read: » версию TLS-библиотеки (например, «OpenSSL/3.5.7: »). OpenSSL 1.1.1 не сообщал об этой ситуации таким образом: в 1.1.1 то же усечение обычно выглядит как «curl: (18) transfer closed with N bytes remaining to read».
curl (OpenSSL 3 backend) — CURLE_RECV_ERROR, SSL_R_UNEXPECTED_EOF_WHILE_READING
Что это означает
TLS-соединение было установлено и данные передавались, но затем другая сторона закрыла TCP-соединение, не отправив перед этим оповещение TLS close_notify, хотя curl ещё ждал данных. OpenSSL 3 считает такое внезапное завершение ошибкой, а не обычным концом потока, потому что атака усечения выглядит именно так: close_notify не приходит. curl сообщает об этом как о сбое при получении данных (код завершения 56).
Почему это происходит
Процесс сервера завершился аварийно или по тайм-ауту посреди ответа
частоРабочий процесс приложения, убитый по тайм-ауту или из-за нехватки памяти, перезапуск рабочего процесса PHP-FPM или Gunicorn либо вышестоящий сервер (upstream), прекративший обработку запроса, закрывают сокет, пока тело ответа ещё передаётся.
Соединение разорвало промежуточное устройство
частоМежсетевые экраны, NAT-шлюзы, корпоративные прокси и балансировщики нагрузки с ограничениями на время простоя или максимальную длительность соединения могут оборвать долгое скачивание или медленный ответ на уровне TCP без штатного завершения TLS со стороны сервера.
Сервер завершает ответы без close_notify
иногдаНекоторые встроенные веб-серверы, старые версии IIS и самописные TLS-серверы закрывают сокет без штатного завершения TLS. Если конец HTTP-ответа обозначается закрытием соединения, клиенты на OpenSSL 3 выдают эту ошибку на каждый такой ответ.
Передачу прервало ограничение на размер тела сообщения
иногдаОграничения на загрузку данных на сервер (client_max_body_size, правила WAF) или квоты на скачивание иногда сбрасывают соединение вместо того, чтобы вернуть положенный ответ 413 или 403.
Как исправить
- 1.
Выясните, какой узел на пути закрывает соединение
Запишите, сколько байт и сколько секунд проходит до ошибки, затем повторите запрос напрямую к бэкенду. Обрыв на круглом числе секунд указывает на тайм-аут в прокси или балансировщике нагрузки.
bash # How much arrived, and for how long, before the connection died? curl -sv --trace-time https://api.example.com/export.csv -o out.csv 2>&1 | tail -20 # Same request directly to the backend, bypassing the proxy / load balancer curl -sv --resolve api.example.com:443:10.0.0.12 https://api.example.com/export.csv -o out.csv - 2.
Увеличьте срабатывающий тайм-аут
Поднимите лимит в компоненте, который обрывает соединение, выше самого долгого нормального времени ответа или ускорьте медленный эндпоинт (отдавайте большие выгрузки потоком или постранично).
text # nginx in front of a slow upstream (both default to 60s) proxy_read_timeout 300s; proxy_send_timeout 300s; # Load balancers: set the idle timeout above the longest legitimate response time - 3.
Повторяйте идемпотентные передачи данных
При скачивании по ненадёжным каналам разрешите curl повторять попытки и докачивать данные. Это лечит симптом на стороне клиента, пока причину ищут на стороне сервера.
bash # For idempotent downloads: retry, and resume where the transfer stopped curl --retry 5 --retry-all-errors -C - -o big.iso https://downloads.example.com/big.iso - 4.
Серверный код: закрывайте TLS-соединения правильно
Отправляйте close_notify перед закрытием сокета (SSL_shutdown в OpenSSL, unwrap() в Python, Close() у tls.Conn в Go) и обозначайте границы HTTP-тела заголовком Content-Length или кодированием chunked, чтобы штатное завершение было однозначным.
python # Server code: shut TLS down cleanly so the peer receives close_notify conn.unwrap() # Python ssl.SSLSocket: sends close_notify before closing conn.close()
Связанные ошибки
error:0A000126:SSL routines::unexpected eof while readingOpenSSL 3[SSL: UNEXPECTED_EOF_WHILE_READING] EOF occurred in violation of protocolPython ssl module (OpenSSL)GnuTLS recv error (-110): The TLS connection was non-properly terminated.git over HTTPS with libcurl-gnutls (Debian, Ubuntu)curl: (35) TLS connect error: error:0A00010B:SSL routines::wrong version numbercurl (OpenSSL backend)