HTTP クライアントのなかにはいくつかタイムアウトのオプションを設定できるものがある(curl(1) の --connect-timeout
や --max-time
など)
Ruby の Net::HTTP も open_timeout
と read_timeout
というオプションを指定できるが、 HTTP サーバのどの処理に時間がかかったときこれらのタイムアウトが効くのか気になったので、ソケット処理の各段階に wait を入れられるような簡易 HTTP サーバを書いて試してみた。
https://github.com/kyanny/playground/tree/gh-pages/slow-http-server
- curl(1) の場合
- bind の前までは HTTP サーバに接続できないのでタイムアウトオプションは無意味
--connect-timeout
は bind 後 listen 前で待たされるときに効き、 listen 後に待たされても関知しない--max-time
は bind 後のどの段階で待たされるときにも効く(サーバがレスポンスを返し終わっていてもソケットをし終わるまではタイムアウトが効く)
- Net::HTTP の場合
- bind の前までは HTTP サーバに接続できないのでタイムアウトオプションは無意味
open_timeout
は bind 後 listen 前で待たされるときに効き、 listen 後に待たされても関知しない- curl(1) の
--connect-timeout
と同じ挙動 - タイムアウトすると
Net::OpenTimeout
例外を送出する
- curl(1) の
read_timeout
は listen 後のどの段階で待たされるときにも効く- これも curl(1) の
--max-time
と同じ挙動にみえる - 例外は全て同じではなく、 listen 後 accept 前で待たされたときは
Errno::ECONNRESET
を、 accept 後 write の途中で待たされたときはNet::ReadTimeout
を、 write 完了後 close 前で待たされたときはErrno::ECONNRESET
を送出する
- これも curl(1) の
余談。 Ruby の Net::HTTP で簡易 HTTP サーバにリクエストを送ると、 Content-Length
ヘッダを正しく返さないときに Errno::ECONNREFUSED
例外を送出する、という不思議な挙動に出くわした。 HTTP の仕様的にそういうものなのかと思ったら、 "HTTP/1.0 200 OK\r\n\r\nHello world" | nc -l 8080
で立てた簡易 HTTP サーバに対してリクエストを送るとふつうにレスポンスを受け取れる。ソケットのオプションか何かに違いがあるのでは、という気がするが、調べていないのでわからない。
https://github.com/kyanny/playground/blob/gh-pages/slow-http-server/s.sh
https://github.com/kyanny/playground/blob/gh-pages/slow-http-server/nc.sh