Dev Study
← Rust で小さなブラウザを作る コース

5. URL の部品 — scheme / host / port / path / query を左から切る

の分解は、文字列を左から順に 4 回切るだけです。"://" の前が 、次の "/" か "?" までが ( と )、authority を ":" で host と port に分け、残りを "?" で と に分けます。

仕様は URL Standard です。URL は scheme / host / port / path / query / からなり、http や のような「」には既定のポートがあります(http は 80、https は 443)。だから "http://example.com" には port が書かれていなくても 80 につなげばよい、と決まっています。fragment(# より後ろ)はブラウザの中だけで使うもので、サーバーには送りません。

参照実装の parse は、入力を 4 段で切って Url { scheme, host, port, path, query } を返します。URL にパスが無ければ path は "/" にします。これは次の章で のに " / " と書くためです。() が path と ?query をつないだもの、host_header() が の値で、どちらも HTTP の章で使います。host_header() は既定ポートの 80 なら :port を省きます。 9110 §7.2 は Host を URI の authority と同じにせよと定めているので、URL に :80 と明記されていた場合は厳密には付けるのが正しく、この実装は多くのクライアントと同じ省略をしている、と覚えておいてください。

下のコードを実行すると、6 つの入力がどう分かれるかが出ます。3 つ目の "HTTP://Example.COM:8080" で scheme と host が小文字になるのは、どちらも大文字小文字を区別しないと仕様が定めているからです。パスは区別するのでそのままです。

本物のブラウザでは: の URL 処理は url/ ディレクトリにあり、部品に切るだけの (url_parse。遠い祖先は Mozilla のコード)、正規化する canonicalizer(url_canon)、その上の GURL という 3 層です。README は「parser は決して失敗せず、最善の推測をする」と書いていて、小文字化や既定ポートの判断は canonicalizer の仕事です。セキュリティの判断には GURL と別に url::Origin があります。 は自前の KURL(platform/weborigin/kurl.h)を持ちます。Firefox は netwerk/base/nsStandardURL.cpp です。この回の parse() は、分割と正規化を 1 つの関数でやっている小さな版だと思ってください。

開発のどこに活かすか: URL を文字列のまま引き回して、必要なときに正規表現で切る実装は、クエリや fragment の扱いで必ずずれます。入口で一度だけ型(Url)に変えて以後は型で渡す、という形は API クライアントやログ解析でそのまま使えます。既定ポートの補完や Host ヘッダーの組み立てを 1 か所に閉じ込められるのも同じ理由です。

点線の付いた語はタップすると説明が出ます。用語集を開く →

① 左から 4 回切る

http://localhost:8000/docs/index.html?q=rust#top の分解
"://" で切るscheme = http
残り: localhost:8000/docs/index.html?q=rust#top
# 以降は捨てる(サーバーに送らない)
最初の "/" か "?" で切るauthority = localhost:8000
残り: /docs/index.html?q=rust
authority を ":" で
host = localhost
port = 8000(無ければ 80)
残りを "?" で
path = /docs/index.html
query = q=rust

切る順番を仕様と同じ「左から」にしておくと、"http://example.com?x=1" のようにパスが無い入力でも迷いません。

▶ サンプルコードを実行してみよう(自由に書き換えてOK)

Rust

手元で動かす(配布物)

図やコードに出てくる用語(タップで説明)

サンプルコードで身につける(3本) →

学んだ概念を、素朴な例から実務寄りの例まで3つの具体例で確認します。

公式ドキュメントで詳しく ↗