TCPのRSTが飛ぶタイミングと認証が必要なHTTP POST [TCP]
久々のTCPネタ。
TCPのRSTについてこの記事でも簡単に触れた。
このRSTがどのようなタイミングで送信されるかというと、OSのソケットバッファに
受信データがまだ残っているにもかかわらず、アプリがcloseを実行したときに送信される(Linuxのお話)。
つまり、まだ受け取るべきデータが残っているにもかかわらず、有無を言わさずアプリが
closeを実行してきたので、これは異常な状態だ、ということでRSTを送信し、
その受け取るべきデータを送ってきた送信者側に、「もうデータは送らないでくれ」と伝えたいのである。
さて、これを踏まえて考えると、実は下記のようなケースで問題が発生する。
- マシンA(HTTPクライアント)はHTTP POSTのヘッダ(仮に1024バイトとする)とHTTP POSTのボディ(仮に8192バイトとする)をマシンB(HTTPサーバ)に送信した。
- マシンBのOSは、9216バイト(1024+8192)すべてネットワークから受信し、受信ソケットバッファに蓄えた。
- マシンBのHTTPサーバアプリは、適当なバイト(仮に2048バイトとする)をreadした。
- マシンBのHTTPサーバアプリは、readした2048byteのデータをHTTPにのっとってparseし、HTTP POSTヘッダを解釈した。
- マシンBのHTTPサーバアプリは、受け付けたHTTP POSTリクエストは認証が必要だと判断し、まずは"401 Unauthorized"レスポンスのレスポンスラインのみをwriteした。
- マシンBのHTTPサーバアプリは、続いて401エラーのレスポンスヘッダ群をwriteした。
- マシンBのHTTPサーバアプリは、401エラーを返す処理を終えたのでソケットをcloseした。
- マシンBのOSは、401エラーのレスポンスラインをマシンAにむけてネットワークに送信した。
- マシンBのOSは、Nagleアルゴリズムにより401エラーのレスポンスヘッダ群のネットワーク送信は待機している。
- マシンBのOSは、closeを検出し、401エラーのレスポンスヘッダ群を返すことなくRSTをマシンAにむけてネットワークに送信した。
- マシンAは、401エラーのレスポンスヘッダ群を受信することなくRSTを受信してしまい、認証のための情報(nonceなど)が受け取れないので認証が実行できない。
この現象を回避するためには、
マシンBがHTTP POSTボディまで全て受信してから、認証フェーズに入ればよい、
もしくは、
レスポンスラインとレスポンスヘッダ群を同時にwriteすればよい、
ということではあるが、HTTPレイヤで下記のような手順を踏むことで解決することもできる。
マシンAがHTTP POSTのボディはすぐに送信せずに、HTTP POSTリクエストのヘッダに、
"Expect: 100-continue"を含めて送信する。
もし、マシンBが認証が必要だと判断した場合は、401エラーを上記のフローと同様に返してくるが、
POSTボディを送信していないので、RSTが飛んでこない。
また、認証が必要ない場合は、マシンBから"100 Continue"レスポンスが返ってくるので、
これを受けてマシンAはPOSTボディを送信すれば良い。
UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI
- 作者: W.リチャード スティーヴンス
- 出版社/メーカー: ピアソンエデュケーション
- 発売日: 2000/04
- メディア: 単行本
Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)
- 作者: 山本 陽平
- 出版社/メーカー: 技術評論社
- 発売日: 2010/04/08
- メディア: 単行本(ソフトカバー)
コメント 0