Freepascal, версия магистрали Indy SVN, ничего не получено клиентом PHP при передаче XML, пока не будет удалено преобразование кодировки

Я написал демон сервера (Linux, Ubuntu), который взаимодействует с PHP как уровень внешнего интерфейса.

Недавно я обновил FPC и библиотеку Indy до FPC 2.6.0, а Indy до версии магистрали (до того, как я использовал ветку Tiburon).

Все скомпилировано, и все выглядело нормально, но при записи в IOHandler ничего не получено (клиентом PHP), клиент сообщит, что получено 0 байт.

После погружения в проблему я увидел, что при использовании методов записи из IOHandler кодировка проверяется и преобразуется перед отправкой ответа в метод ToBytes() в IdGlobal.pas.

Теперь, если я закомментирую строки преобразования в подпрограммах ToBytes();

if ASrcEncoding <> ADestEncoding then begin
  LBytes := TIdTextEncoding.Convert(ASrcEncoding, ADestEncoding, LBytes);

На этот раз клиент PHP получает ответ.

Мой вопрос, как я могу настроить свой TCP-сервер Indy или IOHandlers, чтобы остановить кодирование данных?

1 ответ

Решение

Инди звонки TIdTextEncoding.Convert() когда он думает, что две кодировки различны, байты могут быть преобразованы из одной кодировки в другую. Тем не менее, Инди еще не обнаруживает, когда два TIdTextEncoding объекты представляют одну и ту же кодировку, поэтому преобразование можно пропустить. Это в основном из-за ограничения в Embarcadero в SysUtils.TEncoding класс в Delphi 2009-XE, который не предоставляет эту информацию (в Delphi XE2, TEncoding получил новый EncodingName а также CodePage свойства, но Indy еще не обновлялся для их использования). Инди TIdTextEncoding класс является псевдонимом для TEncoding в Delphi 2009+ и моделируется после TEncoding в Delphi 5-2007 и FreePascal, чтобы поддерживать единый API на всей кодовой странице Indy.

Инди в настоящее время просто сравнивает TIdTextEncoding указатели объектов друг на друга, что хорошо при использовании стандартных кодировок из TIdTextEncoding свойства класса, так как они реализованы как одноэлементные объекты в памяти. Однако, если вы смешаете в TIdTextEncoding объекты, которые получены TIdTextEncoding.GetEncoding() метод, такой как от Инди CharsetToEncoding() функция, тогда указатели объекта не будут совпадать, даже если их кодировки соответствуют. В идеальных условиях это было бы невозможным преобразованием из набора символов в Unicode обратно в тот же набор символов.

Тем не менее, под FreePascal, TIdTextEncoding использует библиотеку ICONV, а поддержка ICONV в Indy неполная. Преобразования осуществлены, но полная обработка ошибок еще не реализована, в основном из-за проблем с доступом к errno переменная на разных платформах, которую ICONV использует для расширенного отчета об ошибках. Не все ошибки ICONV являются фатальными, но Indy пока не может их обнаружить.

Хуже, TEncoding установлен, чтобы НЕ выбрасывать исключения, когда ошибки преобразования происходят, только когда ошибки буфера происходят (позор Embarcadero для этого). Если происходит ошибка преобразования данных, TEncoding просто возвращает пустые данные. Мы должны были поддерживать это поведение в TIdTextEncoding в не-D2009+ средах, таких как FreePascal. Я полагаю, что Indy мог бы быть обновлен для внутренней проверки этого состояния и, при необходимости, для создания собственного исключения.

Чтобы ответить на ваш вопрос, вы ничего не можете сделать, чтобы Indy пропустил звонок TIdTextEncoding.Convert(), Вы должны были бы закомментировать это и перекомпилировать Indy в настоящее время. Это известная проблема в текущем выпуске Indy, и была предпринята некоторая работа по ее решению, но пока нет ETA, когда она будет готова для публичного использования. В Инди 11 мы, вероятно, откажемся от поддержки TEncoding и внедрить наш собственный движок charset изначально в Indy, по крайней мере для часто используемых charsets. Таким образом, мы больше не привязаны к каким-либо конкретным API для конкретной платформы. Но мы еще даже не начали работу над Indy 11 или даже решили, каким будет ее набор функций.

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