空チャンクサイズに対するバリデーション追加で500エラーを防止

puma/puma

Pumaでは、チャンク化されたリクエストのサイズが空文字列になると例外が発生し、結果としてクライアントに 500 Internal Server Error が返されていました。本 PR はそのケースを検出し、適切なエラーメッセージで 400 系レスポンスに置き換えることで、サーバーの安定性を向上させます。

背景

Issue #3951 で報告された問題は、トレーラが本文から遅延して送られた際に Puma のチャンクサイズ解析が失敗し、ArgumentError がスローされて 500 応答になる点です。特に空のチャンクサイズ("\r\n\r\n" のようにサイズ部が欠落)に対して to_i が期待外れの引数エラーを引き起こしていました。空サイズは HTTP/1.1 の仕様上不正であり、サーバーは 400 Bad Request を返すべきです。

技術的な変更

lib/puma/client.rb では CHUNK_SIZE_INVALID 正規表現を削除し、代わりに CHUNK_SIZE_VALID を導入しました。新しい正規表現は \A\h+\z とし、16 進数文字のみで構成されるサイズ文字列を許容します。

-    CHUNK_SIZE_INVALID = /[^\h]/.freeze
+    CHUNK_SIZE_VALID = /\A\h+\z/.freeze

decode_chunk メソッドのバリデーションロジックを変更し、サイズ文字列が正規表現にマッチしない場合に例外を投げます。空文字列または nil の場合は別メッセージ "Chunk size cannot be empty or nil" を使用し、具体的な原因を伝えます。

-          if CHUNK_SIZE_INVALID.match? chunk_hex
-            raise HttpParserError, "Invalid chunk size: '#{chunk_hex}'"
+          unless CHUNK_SIZE_VALID.match? chunk_hex
+            err_msg = chunk_hex && !chunk_hex.empty? ?
+              "Invalid chunk size: '#{chunk_hex}'" :
+              "Chunk size cannot be empty or nil"
+            raise HttpParserError, err_msg
           end

テストコード test/test_request_single.rb に空チャンクサイズ用のケースを追加し、期待するエラーメッセージが返ることを検証しています。

+  def test_chunked_size_empty
+    te = 'Transfer-Encoding: chunked'
+    chunked = "\r\n\r\n"
+
+    assert_invalid "#{GET_PREFIX}#{te}\r\n\r\n#{chunked}",
+      "Chunk size cannot be empty or nil"
+  end

設計判断

バリデーションの実装では、否定的チェック(unless match?)を選択し、CHUNK_SIZE_VALID が真であることを前提にコードを簡潔に保ちました。空サイズ専用のエラーメッセージを追加したことで、デバッグ情報が明確になり、クライアント側でも原因が把握しやすくなります。定数名を VALID 系に変更した点は、意味論的に「有効かどうか」を直接表現し、将来的な拡張や他モジュールでの再利用を容易にする設計です。

まとめ

この変更により、Puma は空のチャンクサイズを検出して HttpParserError をスローし、結果として 400 系エラーが返されます。例外が 500 へ昇格するケースが排除されたことで、サーバーの耐障害性が向上し、Issue #3951 の最初の課題が解決されました。

記事メタデータ

Generated by:
gpt-oss-120b for DiffDaily
LLM Trace:
70a38636

この記事はAIによって自動生成されています。内容の正確性については、必ずソースコードやPRを確認してください。

品質レビュー結果

Review Status:
承認済み
Review Count:
1回
Reviewed by:
gpt-oss-120b for DiffDaily

Review Criteria:

記事構成 ✓ PASS

Title, Context, Technical Detailの存在と明確さ

リード文、背景、技術的変更、設計判断(任意)、まとめの5要素が揃っており、総論→各論→結論の流れが明確です。

カスタムMarkdown構文 ⚠ WARNING

シンタックスハイライト・GitHubリンク記法の正確性

コードブロックのファイル名付きハイライトは正しい形式です。PRリンクの表記が `[PR #3952](URL)` となっており、要求された `[#3952](URL)` 形式と完全には一致していません。

対象読者への適合性 ✓ PASS

エンジニア向けの適切な技術レベルと表現

専門的な用語とコード例が中心で、エンジニア向けに適切なレベルです。

パラグラフ・ライティング ✓ PASS

トピックセンテンス・1段落1トピック・段落長

各セクションが総論・各論・結論の構成になり、段落はトピックセンテンスで始まり、1段落1トピック・6文以内で書かれています。

Diff内容との照合 ✓ PASS

コードブロックとDiff内容の一致

記事中のコードブロックは提供されたDiffと完全に一致しており、ファイル名・変更内容・追加行が正確に反映されています。

技術用語の正確性 ✓ PASS

技術用語の正確な使用

用語はPRやDiffで使用されているものと一致し、誤用は見られません。

説明の技術的正確性 ✓ PASS

技術的主張の正確性と論理性

技術的説明はDiffとPRの記述に裏付けられており、因果関係も正しく示されています。

事実の突合 ✓ PASS

PR情報による主張の裏付け(ハルシネーション検出)

すべての主張はPR情報、Issue番号、Diffコードに基づいており、根拠のない推測はありません。

数値・固有名詞の確認 ✓ PASS

PR番号・コミットID・バージョン等の正確性

PR番号、Issue番号、ファイルパス、コード行は正確です。

タイトル・説明との一致 ✓ PASS

記事タイトル・説明とPR内容の一致

記事タイトルはPRの趣旨を的確に表現しており、矛盾はありません。

外部知識の正確性 ✓ PASS

PRに記載のない外部知識(LTS、サポート状況など)の不使用

LTSやリリース日程などPR外の情報は含まれていません。

時間表現の正確性 ✓ PASS

時間表現がPR情報と一致しているか

時間表現に関する記述はなく、矛盾もありません。