概要
curl の引数にURLを与えて実行すると指定したコンテンツを取得してコンソールに表示できますが、そこでどういう処理が行われているかを説明します。
URLのパース
URL文字列は例えば http://example.com/some/data といったものです。まずはこの文字列を解析します。このような処理をパース(parse)とかデシリアライズ(deserialize)と言いますが、例に出したURLを
- http
- example.com
- /some/data
という3つの要素に分解し、それぞれを scheme, host, path と呼びます1。
名前解決
次にURLから取り出した host の部分に対応するIPアドレスを取得するために getaddrinfo 関数を呼び出します。getaddrinfo 関数では、必要ならDNSサーバに host 文字列を送信してIPアドレスを取得します。
TCP接続
対象ホストにTCP接続します。TCP接続にはIPアドレスとポート番号が必要になります。接続先のIPアドレスはhostの名前解決をすることで取得しました。URL中でポート番号が明示的に指定されていない場合、schemeに依存したデフォルトのポート番号を使用します。httpの場合は80です。
HTTPリクエストの送信
TCP接続が確立されたら、URLのschemaパートに基づく方法でコンテンツを取得します。今回はhttpだったので、RFC7239で規定されたHTTPのお作法でコンテンツを取得します。パスとしてURLから取り出したpathを使って、HTTPリクエスト
GET /some/data HTTP/1.1
Host: example.com
をTCPソケットに書き込みます2。すると、対象ホストから応答(HTTPレスポンス)が返ってきます。
HTTPレスポンスのパース
HTTPレスポンスはMIME3で規定されたフォーマットになっているので、それを解析して本文(body)を取り出し、標準出力に書き込みます。これにより、取得したコンテンツがコンソールに表示されます。
まとめ
HTTPによるコンテンツ取得の処理を説明しました。
WebブラウザでアドレスバーにURLを入力してページを表示する際に行われている処理も、レスポンスをパースした後の処理がもうちょっと複雑になるだけで同様の処理が行われています。処理内容を把握しておくことで、コンテンツが取得できない場合の切り分けの参考になると思い説明してみました。
dig example.com +short
で名前解決したり、telnet example.com 80
でTCP接続してHTTPリクエストを送信してみるとより理解が深まるかもしれません。