HTTPって意外に難しい
長い間Webサービスの開発に携わっているのだけれど、HTTP について全然理解していなかったんだ、と思わされる出来事があった。
そのこととは、名前ベースのバーチャルホストのこと。今までは、ドメイン名を変えれば同じサーバ上に複数のサービスを稼働させられるあれのことね、という程度の認識で、仕組みまでは理解していなかった。
仕組みを理解していなかったために、問題の解決に時間がかかってしまった。いや、理解していれば問題は発生していなかったはず。
問題
問題はプロキシ的な機能(以下プロキシ)を作っているときに発生した。
プロキシを簡単に説明すると、クライアントからリクエストを受け取り、簡単な変換とチェックを行い、その先の各サービスにリクエストを送信する役割。プロキシと各サービスは同じサーバ上で開発していて、URLはサブドメインで分けられている(バーチャルホスト)。
で、問題発生。プロキシを通すと期待しているサービスにリクエストが届かない。
解決
設定とか調査するんだけれど、悪いところは見当たらない。コードでも調査して、HTTPクライアント(cURL)に渡すURLは正しいことが確認できた。コードや設定を見つめていても原因がわからなかったので、tcpdump でどんな通信をしているか覗いてみることにした。
そしたら、Host ヘッダの所に各サービスのホストではなくプロキシのホストが設定されていたのがわかった。
ただ、わかった瞬間は別におかしいとは思わなくて、しばらくしてから、バーチャルホストってどういう仕組みで動いているのかを考えたときに、原因に気付いた。
名前ベースのバーチャルホストは HTTP ヘッダの Host の値をもとにリクエストの振り分け先を決定している。
なので、プロキシから各サービスに送信するには、Host に各サービスのドメインを設定するのが正しいが、実際はクライアントから受信した Host の値を設定していしまっていた(というか、無理に設定しなければ HTTPクライアントがよきに計らってくれる)。
反省
反省点は、どんなヘッダがあるのかろくに調べもせず全部丸投げにすればいいだろうと安易に考えてしまったこと、だろうか。
Content-Length とかも気をつけないとなー。
というか、どのヘッダを送らない(ブラックリスト)方式ではなく、どのヘッダは送る(ホワイトリスト)方式にした方がよさそう。