web-dev-qa-db-ja.com

JavaのBufferedReader.readLine()の最大行長?

BufferedReaderのreadLine()メソッドを使用して、テキスト行をソケットから読み取ります。

読み取る行の長さを制限する明確な方法はありません。

データのソースが(悪意を持ってまたは誤って)改行文字なしで大量のデータを書き込む可能性があることを心配しています。これにより、BufferedReaderが無制限の量のメモリを割り当てます。

それを回避する方法はありますか?または、readLine()の制限付きバージョンを自分で実装する必要がありますか?

22
daphshez

これを行う最も簡単な方法は、独自の境界付きラインリーダーを実装することです。

または、もっと簡単に、 this BoundedBufferedReader class のコードを再利用します。

実際、標準のメソッドと同じように機能するreadLine()をコーディングすることは簡単ではありません。 3種類のラインターミネータを正しく処理するには、かなり注意深いコーディングが必要です。上記のリンクのさまざまなアプローチを、BufferedReaderの Sunバージョン および Apache Harmonyバージョン と比較すると興味深いです。

注:制限付きバージョンまたはApacheバージョンのいずれかが100%正しいとは、完全には確信していません。境界バージョンは、基になるストリームがマークとリセットをサポートしていることを前提としていますが、これは常に正しいとは限りません。バッファの最後の文字としてCRが見つかると、Apacheバージョンは1文字先読みしているように見えます。これは、ユーザーが入力した入力を読み取るときにMacOSで壊れます。 Sunバージョンは、次のread...操作でCRがスキップされる可能性のあるLFを引き起こすフラグを設定することでこれを処理します。つまり、偽の先読みはありません。

13
Stephen C

別のオプションは、Apache Commonsの BoundedInputStream です。

InputStream bounded = new BoundedInputStream(is, MAX_BYTE_COUNT);
BufferedReader reader = new BufferedReader(new InputStreamReader(bounded));
String line = reader.readLine();
12
Kevin Litwack

おそらく最も簡単な解決策は、少し異なるアプローチを取ることです。 1つの特定の読み取りを制限することによってDoSを防止しようとする代わりに、読み取られる生データの全体量を制限します。この方法では、割り当てられたメモリが受信データに比例している限り、すべての読み取りとループに特別なコードを使用することを心配する必要はありません。

Reader、またはおそらくより適切には、デコードされていないStreamまたは同等のものを測定できます。

文字列の制限は20億文字です。制限を小さくしたい場合は、自分でデータを読み取る必要があります。バッファストリームから、制限または改行文字に達するまで、一度に1つの文字を読み取ることができます。

3
Peter Lawrey

これを回避する方法はいくつかあります。

  • 全体のデータ量が非常に少ない場合は、ソケットからバッファーにデータをロードし(バイト配列、バイトバッファー、必要に応じて異なります)、次に、ByteArrayInputStreamなどを介してBufferedReaderをメモリ内のデータにラップします。
  • 発生した場合は、OutOfMemoryErrorをキャッチします。このエラーをキャッチすることは一般的に信頼できませんが、配列割り当ての失敗をキャッチする特定のケースでは、基本的に安全です(ただし、ヒープから大量に割り当てる1つのスレッドが他のスレッドに与える可能性があるノックオン効果の問題は解決しません)たとえば、アプリケーションで実行中);
  • 非常に多くのバイトのみを読み取るラッパーInputStreamを実装し、これをソケットとBufferedReaderの間に挿入します。
  • bufferedReaderを破棄し、正規表現フレームワークを介して行を分割します(ストリームから文字を取得するCharSequenceを実装してから、行の長さを制限する正規表現を定義します)。原則として、CharSequenceはランダムアクセスであると想定されますが、単純な「行分割」正規表現の場合、実際には、連続する文字が常に要求されるため、実装で「チート」できることがわかります。
1
Neil Coffey