Ответ PSGI: Какие типы файловых дескрипторов могут работать с PSGI и Plack? - PullRequest
3 голосов
/ 16 мая 2011

Спецификация PSGI определяет HTTP-ответ как состоящий из трех частей, третья из которых может быть либо ссылкой на массив, либо дескриптором файла.Файловый дескриптор может быть:

IO :: Handle-подобный объект или встроенный файловый дескриптор.

И в спецификации сказано:

Серверы МОГУТ проверить, еслитело - это настоящий файловый дескриптор, использующий fileno и Scalar :: Util :: reftype, и если это настоящий файловый дескриптор, имеющий файловый дескриптор, он МОЖЕТ оптимизировать обработку файлов, используя такие методы, как sendfile (2).

Теперь ясобрал пример командной строки, используя plackup (версия Plack 0.9978), и кажется, что проверка, является ли тело реальным дескриптором файла, приводит к фатальной ошибке:

Can't locate object method "FILENO" via package "IO::Scalar" at /usr/lib/perl5/5.10/i686-cygwin/IO/Handle.pm line 390

Вот пример командной строки:

plackup -MData::Dumper -MIO::Scalar -e \
'sub { $env=shift; return [200, [], IO::Scalar->new(\Dumper $env) ] }'

Конечно, я просто не мог использовать файловый дескриптор:

plackup --port 9999 -MData::Dumper -e \
'sub { $env=shift; return [200, [], [Dumper $env] ] }'

Но мне интересно, что работает, а что нет,Так не следует ли Плаку проявлять большую осторожность при вызове FILENO на дескрипторе, чтобы он не попадал в исключение?

И добавить еще одно:

plackup --port 9999 -MData::Dumper -e \
'sub{$env=shift; $s=Dumper $env; open $fh,q(<),\$s or die; return [200,[],$fh ]}'

Похоже надескриптор файла не распознается как таковой.Сообщение об ошибке:

body should be an array ref or filehandle at /usr/lib/perl5/site_perl/5.10/Plack/Middleware/StackTrace.pm line 35

Обновление:

Как указано в его ответе, будет работать следующее (по крайней мере, 5.10.1 в Cygwin):

plackup -p 9999 -MData::Dumper -MIO::String -e \
'sub { return [200, [], IO::String->new(\Dumper shift) ] }'

Но ясно, что где-то есть проблема, которую можно увидеть из неудачных примеров, и о ней сообщат, как только я решу, что это на самом деле.

Ответы [ 3 ]

9 голосов
/ 16 мая 2011

Это не ошибки - на самом деле это проще назвать ошибкой в ​​Plack и исправить , чтобы они воспринимались как верный ответ.Но это могло бы ухудшить ситуацию, поскольку теперь Plack обрабатывает вещи, которые (явно) не определены как правильный ответ в спецификации PSGI.(PSGI! = Plack, также HTTP! = Apache)

Суть спецификации PSGI заключается в том, что это общий интерфейс между веб-серверами и приложениями.Если серверу / приложению необходимо добавить дополнительные 2-3 строки кода для соответствия спецификации, это хороший компромисс.Гораздо лучше иметь 2-3 строки кода в каждом N приложений и M серверов, чем иметь N * 2-3 строки дополнительного кода для обработки угловых случаев на серверах и наоборот в приложениях.

Спецификацияопределяет, что тело ответа должно быть либо «встроенным дескриптором файла», либо «IO :: Handle-подобным объектом, реализующим getline».Работать с чем-то похожим на это легко в Plack, но мы не должны делать это вслепую - помните, Plack - не единственная реализация PSGI.Промежуточное программное обеспечение Lint, предупреждающее вас о такой несовместимости, является правильной вещью.

Сказано:

a) IO :: Scalar - это объект, который реализует метод getline (),так что это должно быть принято.К сожалению, Lint умирает от этого из-за ошибки модуля, как указывалось другими.Это можно легко обойти с помощью исправления обезьяны, а также легко исправить Plack :: Util :: is_real_fh для перехвата ошибок в вызове -> fileno, но, опять же, мне нужно подумать об этом, если это правильная вещь , чтобы сделать.

б) PerlIO-файловый дескриптор в памяти является хитрой вещью.В спецификации сказано только «встроенный файловый дескриптор», а файловый дескриптор в памяти также может рассматриваться как встроенный.На самом деле, если вы отключите промежуточное программное обеспечение Lint (например, с опцией -E production для plackup), дескриптор файла будет просто работать.Но опять же, промежуточное программное обеспечение Lint дает вам сообщение, потому что оно не гарантированно будет работать где-то еще.

Наконец, но не в последнюю очередь, это, вероятно, следует рассмотреть в FAQ.Не стесняйтесь открыть дело в репозитории psgi-specs .

8 голосов
/ 16 мая 2011

Это похоже на ошибку в Plack.Он пытается выяснить, имеет ли он настоящий дескриптор файла, через fileno, и если нет, он будет принимать объекты только методом getline.Это упускается как для связанных файловых дескрипторов без определения FILENO (допустимых, если невежливых), так и для файловых дескрипторов памяти, которые не имеют допустимого файлового имени и не являются благословенными объектами.Вы можете увидеть это в логике в Plack::Middleware::Lint->validate_res и Plack::Util->is_real_fh.

Я бы сообщил об этом Плаку как об ошибке .

Тем временем вы можете работатьвокруг проблемы в IO :: Scalar путем определения IO :: Scalar :: FILENO для возврата undef.

sub IO::Scalar::FILENO { return }

Это было бы улучшением IO :: Scalar, но оно не обновлялось в шестилет, чтобы я не задерживал дыхание.

Чтобы разрешить в памяти файловые дескрипторы, вы можете обмануть Плака, благословив файловый дескриптор.Когда-нибудь между открытием и передачей, сделайте это:

bless $fh, "IO::Handle";

Это безвредно, так как любой дескриптор файла все равно будет реагировать на методы IO :: Handle.Но также, пожалуйста, сообщите об этом как об ошибке.

0 голосов
/ 16 мая 2011

Похоже на ошибку в IO :: Scalar. Сообщите об этом, и вместо этого используйте IO :: String или встроенную поддержку памяти, добавленную в 5.8.

...