「Expect: 100-continue」の深淵:巨大リクエストの明暗を分けるプロトコルの駆け引き
HTTP/1.1という枯れた技術、しかしその仕様の隅々には、物理的な距離(レイテンシ)という呪縛と戦い抜いた先人の知恵が詰まっている。今回スポットを当てるのは、巨大なリクエストボディを送りつける際の「事前確認」――`Expect: 100-continue`ヘッダーだ。
単なる「おまじない」だと思っているなら要注意だ。インフラエンジニアにとって、これは輻輳制御とスループット最適化の境界線を握る重要なトリガーであり、誤った理解はパケットロス以上に痛い「無駄なRTT」を生むことになる。
—
1. パケットの深層:なぜ「100-continue」が必要か
巨大なファイルアップロードや、複雑なJSONペイロードをPOSTする場合、標準的なHTTPクライアントは即座にリクエストボディをTCPストリームに流し込む。もし、サーバー側が認証エラーやバリデーション失敗で即座に401や400を返したとしても、すでに数メガバイトのデータが回線を駆け巡った後であれば、その帯域は無駄になり、TCPの輻輳ウィンドウ(cwnd)も無意味に膨らむ。
`Expect: 100-continue`は、この悲劇を防ぐための「握手」だ。
1. Client: `Expect: 100-continue` を含んだリクエストヘッダーのみを送信。
2. Server: 受け取りを判定。問題なければ `HTTP/1.1 100 Continue` を返送。
3. Client: ここで初めてボディデータを送信開始。
この挙動は、特にモバイル回線のような高RTT環境下において、無駄なデータ転送を抑制し、クライアント側のTCPバッファを保護する役割を果たす。
—
2. インフラ・アーキテクトが直視すべき「潜伏するリスク」
しかし、この仕組みは両刃の剣でもある。サーバー実装が`100-continue`を適切に処理できない、あるいはロードバランサーがこのヘッダーを透過できずに握りつぶすと、クライアントは「サーバーからの応答がない」と判断し、タイムアウトまで待機する事態に陥る。
パフォーマンスを最大化するカーネル/バッファチューニング
このヘッダーを扱う際、Linuxホスト側で意識すべきはTCPの挙動だ。
TCPウィンドウのスケーリングを調整し、巨大リクエストのバッファ溢れを防ぐ
16MBのバッファを確保し、ロングファットパイプを活かす
sysctl -w net.ipv4.tcp_rmem=”4096 87380 16777216″
sysctl -w net.ipv4.tcp_wmem=”4096 65536 16777216″
サーバー側での100-continueの「待ち時間」を制御する
Nginxの場合、クライアントからのボディ送信を待ち続けるタイムアウト設定
client_body_timeout 10s;
特に、TLSハンドシェイクと組み合わさった場合、`Expect`ヘッダーの送信タイミングがTCP Slow Startのフェーズと重なると、往復回数が増え、ユーザー体験(UX)を劇的に悪化させる。TLS 1.3の0-RTTやHTTP/2/3への移行を検討する際、この「HTTP/1.1の作法」がいかに足枷となるかを理解しておく必要がある。
—
3. セキュリティ:未知の攻撃ベクトルを封じる
このヘッダーを悪用したDoS攻撃も存在する。攻撃者が`Expect: 100-continue`を送信したまま、ボディデータを送信せずに放置する「Slowloris」の亜種だ。サーバー側がリソースを確保し続けたまま接続をクローズしないと、ワーカープロセスが枯渇する。
Nginxでの防御的構成例
セキュリティ専門家として推奨したいのは、`client_body_timeout`の適切な設定と、不審なリクエストに対するレート制限だ。
Nginxの設定例
server {
# 100-continueを待機する時間を絞り込み、リソース枯渇を防ぐ
client_body_timeout 5s;
# リクエストボディの最大サイズを制限し、メモリオーバーフローを防ぐ
client_max_body_size 10m;
location /upload {
# 巨大なアップロードに対する事前チェックを厳格に行う
# 許可されないヘッダーはここで弾くのがベストプラクティス
if ($http_expect ~ “100-continue”) {
# ロジックに応じた制御
}
}
}
—
結びに代えて:プロトコルの裏側にある「哲学」
`Expect: 100-continue`は、現代の高速なネットワーク環境においては「オーバーヘッド」と見なされることも多い。HTTP/2以降、ヘッダーの多重化やストリーム制御が標準化されたことで、このヘッダーの必要性は薄れている。
しかし、レガシーなバックエンドシステムや、帯域が極端に狭いIoT環境において、この「事前合意」のプロトコルは依然として強力な武器となる。パケットレベルで「今、データを送ってもいいか?」と問う姿勢は、効率的なアーキテクチャ設計の原点だ。
技術を単なる仕様として覚えるのではなく、「どのレイヤーで、どんな制約を回避するために存在しているのか」を突き詰めること。それこそが、トラブルシューティングの現場で「最後の一手」を打てるエンジニアの条件であると、私は確信している。
次のネットワーク解析でパケットキャプチャを開くとき、ぜひこの`100-continue`がどのようなタイミングで、どのようなTCPウィンドウで交換されているかを確認してほしい。そこに、あなたのインフラの真の姿が映し出されているはずだ。
コメント