Apache Camel и FTP: история испорченных файлов

На одном из проектов мы использовали Entaxy для получения и обработки zip архивов через sftp. Затем появилась необходимость обрабатывать arj архивы, полученные через ftp. Для Apache Camel компоненты sftp, ftp, ftps имеют много общего и расположены в одной фиче "camel-ftp".

Параметры соединения у них схожи и мы скопировали параметры, заменив в настройках эндпоинта только sftp схему компонента на ftp. Сначала с тестовыми файлами не было проблем при скачивании и разархивацией. Но после переноса маршрутов на тестовую среду с большим количеством архивов у нас появились ошибки при извлечении содержимого некоторых архивов. При отладке обратили внимание, что длина byteArray у проблемных файлов больше длины исходных файлов. Сделали тестовый маршрут:

<route>
  <from uri="ftp:..."/>
  <to uri="file:..."/>
</route>

И те же самые файлы имели неверный размер после копирования в локальную файловую систему. Подключились к ftp через другой клиент: размеры проблемных файлов и отображаются правильно, и при копировании в локальную файловую систему файлы сохраняются правильно. Тогда вспомнили про разные режимы ftp, переключили на стороннем клиенте режим с binary на ascii и вуаля - при скачивании те же самые файлы выросли до тех же размеров, что и при копировании через Apache Camel. Открываем описание ftp компонента, находим параметр binary (common): Specifies the file transfer mode, BINARY or ASCII. Default is ASCII (false). Понятно.  Переключаемся на binary и все файлы успешно распаковались. Да - файлы у нас бинарные, да - сами виноваты. Но стало интересно, сервис с zip архивами через sftp работает больше полугода и там всё нормально. Не удержались и заглянули "под капот" - реализации протоколов разные. Ftp и ftps работает через Apache Commons Net FTPClient, который меняет режим в зависимости от опции binary:

client.setFileType(configuration.isBinary() ? FTP.BINARY_FILE_TYPE : FTP.ASCII_FILE_TYPE);

А sftp реализован через JCraft JSCH, который использует SFTP v3 и эта версия всегда работает в режиме binary. И одноимённый параметр компонента никто в Jsch передать не может. Так что не забывайте, что ftp умеет автоматически менять символы окончания строк в режиме ascii. Что этот режим установлен по умолчанию. И что sftp по умолчанию (и вообще всегда) работает в режиме binary!

Удачных вам интеграций!

01.08.2022