2017-07-31 4 views

答えて

6

コアの問題は、Crystalがストリーミング要求本体をサポートしていることです。つまり、要求をストリームするとIOはEOFで、2番目のハンドラはデータを読み取ることができません。

これを解決する簡単な方法は、body_string = context.request.body.try(&.gets_to_end)を使用してコンテンツ全体を取得し、次に返された文字列にcontext.request.body = body_stringを使用してリクエスト本文を設定することです。これにより、ボディ全体がメモリにバッファされ、メモリに格納されたバッファにボディが設定されます。このアプローチの欠点は、攻撃者が無制限のサイズのリクエストボディを送信し、サーバー上のすべてのメモリを食べてDOS攻撃を引き起こすことです。別の欠点は、バイナリデータを扱う場合、文字列を#to_sliceを使ってスライスに変換して処理する必要があることです。

DOS攻撃の問題を解決する1つの方法 - あなたは心の中で最大のボディサイズを持っている場合は、 - 体が大きすぎる場合には、要求を失敗することです:

if body = context.request.body 
    body_io = IO::Memory.new 
    bytes_read = IO.copy(body, body_io, limit: 1_048_576) # 1GiB limit 
    body_io.rewind 
    if bytes_read == 1_048_576 
    # Fail request 
    end 

    # use body_io 

    body_io.rewind # Reset body_io to start 
    context.request.body = body_io 
end 

あなたは無限の大きさを受け入れるために必要がある場合本体にバッファリングしない場合は、既存の本体IOをラップし、IO#read(Bytes)の中で必要な変換を実行するカスタムIO実装を作成する必要があります。このメソッドは非常に複雑で、以前のメソッドはほぼすべての状況をカバーしていますので、このオプションのコードサンプルは提供しません。

+1

未定義のメソッド '#reset'は'#rewind'を意味しますか? 'IO.copy'の直後に別の' body_io.rewind'を追加して動作させる必要がありました。ありがとう! P.S:将来のユーザーのためにあなたの答えを更新してください;) –

+0

@VladFaustそのタイプミスをキャッチしてくれてありがとう! – RX14

関連する問題