3

PSGI仕様では、HTTP応答を3つの部分で構成されていると定義しており、そのうちの3番目は配列参照またはファイルハンドルのいずれかです。ファイルハンドルは次のとおりです。

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では、例外が発生しないように、ハンドルを呼び出すときにPlackはもっと注意を払うべきではありませんか?

そしてもう1つ追加するには:

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

アップデート:

ysthが彼の回答で述べたように、以下は機能します(少なくともCygwinの5.10.1では):

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

しかし、明らかに、失敗した例からわかるようにどこかに問題があり、それが実際に何であるかを決心したら報告されます。

4

3 に答える 3

9

これらはバグではありません-実際には、これをPlackのバグと呼び、有効な応答として処理するように修正する方が簡単です。しかし、PSGI仕様で適切な応答として(明確に)定義されていないものをPlackが処理するため、状況はさらに悪化します。(PSGI!= Plack、同様にHTTP!= Apache)

PSGI仕様のポイントは、Webサーバーとアプリケーション間の共通のインターフェースであるということです。サーバー/アプリケーションが仕様に準拠するために2〜3行のコードを追加する必要がある場合、それは適切な妥協案です。サーバーのコーナーケースを処理するためにN*2-3行の追加コードを用意するよりも、N個のアプリケーションとMサーバーごとに2〜3行のコードを用意する方が、はるかに優れています。

仕様では、応答本文は「組み込みのファイルハンドル」または「getlineを実装するIO::Handleのようなオブジェクト」のいずれかである必要があると定義されています。これと同様に機能するものをPlackで処理するのは簡単ですが、盲目的に行うべきではありません。PSGIの実装はPlackだけではないことを忘れないでください。その非互換性について警告するLintミドルウェアは正しいことです。

それは言った:

a)IO :: Scalarはgetl​​ine()メソッドを実装するオブジェクトであるため、受け入れる必要があります。他の人が指摘しているように、モジュールのバグのためにLintが死んでしまうのは残念です。モンキーパッチで簡単に回避できます。また、Plack :: Util :: is_real_fhにパッチを適用して、-> fileno呼び出しのエラーをトラップするのも簡単ですが、これが正しいかどうかを考える必要があります。行う。

b)PerlIOのメモリ内ファイルハンドルは注意が必要です。仕様には「組み込みのファイルハンドル」とのみ記載されており、メモリ内のファイルハンドルも組み込みのものとして主張できます。実際、Lintミドルウェアを無効にすると(-E productionたとえば、plackupのオプションを使用して)、ファイルハンドルは正常に機能します。しかし、繰り返しになりますが、Lintミドルウェアは、他の場所での動作が保証されていないため、メッセージを表示します。

最後になりましたが、これはおそらくFAQで対処する必要があります。psgi-specsリポジトリでケースを開いてください。

于 2011-05-16T03:23:25.910 に答える
8

これはPlackのバグのようです。filenoを介して、実際のファイルハンドルがあるかどうかを判断しようとします。ない場合は、getlineメソッドを持つオブジェクトのみを受け入れます。FILENOこれは、定義されていない(失礼な場合は有効な)タイのファイルハンドルと、有効なfilenoを持たず、オブジェクトを祝福していないメモリ内のファイルハンドルの両方を見逃します。Plack::Middleware::Lint->validate_resとのロジックで確認できますPlack::Util->is_real_fh

バグとしてPlackに報告します。

一方、IO :: Scalar :: FILENOを定義してundefを返すことにより、IO::Scalarの問題を回避できます。

sub IO::Scalar::FILENO { return }

これはIO::Scalarの改善になりますが、6年間更新されていないため、息を止めません。

メモリ内のファイルハンドルを許可するには、ファイルハンドルを祝福してPlackをだますことができます。それを開いてから渡すまでの間に、これを行います。

bless $fh, "IO::Handle";

とにかく、どのファイルハンドルもIO :: Handleメソッドに応答するので、これは無害です。ただし、バグとして報告してください。

于 2011-05-16T02:48:17.560 に答える
0

IO::Scalarのバグのようです。それを報告し、5.8で追加されたIO::Stringまたは組み込みのメモリファイルサポートを使用してください。

于 2011-05-16T00:27:16.550 に答える