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

Я написал серверный демон (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 Ответ

1 голос
/ 30 марта 2012

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

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

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

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

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

...