HTTP クライアントが inet_aton を使ってホスト名を IP アドレスに変換しようとすると、 OS が自動的に DNS サーバに問い合わせを行います。 そのとき、www.host1.com・www.host2.com・www.host3.com のいずれに対しても、同じ xxx.xxx.xxx.xxx という IP アドレスを返すように DNS サーバを設定しておけばいいのです。
つまりユーザからは 3つの別のホストに接続しているつもりでも、 結果的には同じホストに接続していることになるのです。 こうすると何がうれしいかというと、WWW サーバを xxx.xxx.xxx.xxx にだけ立ち上げておけば、 一つのホストで WWW サーバ 3 つ分の役割を果たすことができます。
これをバーチャルホストと言い、DNS の仕組みを利用して 1つのホストで複数の WWW サーバ分の働きをするものです。 このことをソフトウェアマルチホーミングとも言うようです。
では、IPアドレス xxx.xxx.xxx.xxx のマシンで動いている WWW サーバが
GET /index.html HTTP/1.0というリクエストを受けた場合、どう解釈すべきでしょうか。このままでは
そこで、WWW クライアントは「自分は接続先のサーバ名を〜であると認識している」 という意味の「Hostヘッダ」を送ります。例えば
GET /index.html HTTP/1.0 Host: www.host2.com:80というリクエストを送ることで、WWW サーバは 「このクライアントは http://www.host2.com/index.html の内容が欲しいんだな」 ということがわかります。
逆に言うと、Host ヘッダを送信しない WWW クライアント (IE2 がそうです) は、 http://www.host3.com/index.html をリクエストしたつもりでも、 http://www.host1.com/index.html に相当するページが送られてきたりします。
なお、HTTP/1.1 を使う場合は Host ヘッダを必ず付けなくてはいけません。
http://www.foo.com/bar.cgi?data1=hoge&data2=fugaといったふうに、? の後に渡したい文字列を書き連ねます。 HTTP クライアントは、www.foo.com に接続し、GET メソッドを使って
GET /bar.cgi?data1=hoge1&data2=fuga HTTP/1.0と、そのまま引数を渡します。
しかしこの方法は環境変数経由で文字列が渡されるので、あまりにも長い文字列は 渡すことができません (どれくらいの長さの文字列なら OK か、というのは処理系依存です)。 また、URL として引数が表示されてしまうので、ユーザにデータを見せたくない 場合には不適当です。
そういう場合は POST メソッドを使います。書式は以下の通りです。
POST /bar.cgi HTTP/1.0 Content-Length: 渡したい文字列の長さ (空行) hoge=fuga&hoge2=fuga2&....もし、データが「hoge=fuga&hoge2=fuga2」ならば、長さは 21 なので、
Content-Length: 21となります。
HTTP では、そのまま送信していい文字は `0-9' `a-z' `A-Z' `_' `-' `.' `*' だけで、その他の文字列は URL エンコードを行わなくてはなりませんが、 これは HTTP クライアントの仕事です。URL エンコードというのは 「%」の後に、その文字の16進数表記を続けたものです。
`~'を16進数のASCIIコードで表すと「7E」となるので、 「~68user」をURLエンコードすると「%7E68user」になるわけです。
また、「 」(空白)は「+」に変換しないといけません (「+」を「%20」に再変換する必要はありません)。
例えば、http://foo.com/~user/hoge.cgi?fuga=ABC!"$ DEF+は
GET /%7euser/hoge.cgi?fuga%3DABC%21%22%5C%24+DEF%20 HTTP/1.0としなければいけないのです。POST メソッドで送るデータも URL エンコードの対象になります。
URL エンコードを perl で行うには
$str =~ s/([^\.\*\-_a-zA-Z0-9 ])/sprintf("%%%02lX",unpack("C",$1))/eg; $str =~ s/ /+/g;とします。
参考: 掲示板での 当ページ管理人の発言
最後に「/」が付いていない URL を、実際に telnet で試してみましょう。
% telnet X68000.q-e-d.net 80 Trying 210.155.201.169... Connected to X68000.q-e-d.net. Escape character is '^]'. GET /~68user HTTP/1.0(リターン) Host: X68000.q-e-d.net:80 (続けてリターン) HTTP/1.1 301 Moved Permanently Date: Sat, 20 Jun 1998 22:31:59 GMT Server: Apache/2.0.52 Location: http://X68000.q-e-d.net/~68user/ Connection: close Content-Type: text/html (以下略)注目してほしいのはヘッダの先頭行の「HTTP/1.1 301 Moved Permanently」と 「Location: http://X68000.q-e-d.net/~68user/」です。
WWW サーバが「GET http://X68000.q-e-d.net/~68user HTTP1.0」を受け取ると、 「~68user」はディレクトリなのに最後の「/」が省略されていると判断し、 ステータスコード 301 を返してきます。そして、正しい URL (最後に「/」が付いた URL) を Location ヘッダで知らせてきます。
その時点でコネクションは切断されるので、クライアントは再度サーバに接続しなおして、 Location ヘッダで示された URL にアクセスしなければなりません。 つまり http://X68000.q-e-d.net/~68user は間違いで、 http://X68000.q-e-d.net/~68user/ が正しい URL なのです。
ご意見・ご指摘は Twitter: @68user までお願いします。