さるへい備忘録

さるへいのやったことを綴っているブログです。基本的にテクノロジーの話題です。

URLのパースを各言語で行った時の挙動の違い

URLをパースしていて不可思議な現象に立ち会ったので紹介します。

プログラムを書いていて、URLをパースしなければいけない機会というのは結構存在すると思います。
PythonJavaScript両方で同じURLをパースしたら片方でエラーが出て、片方ではうまくいくといった現象が起こりました。

それぞれの言語ではどうなんだろう?と思って4種類程度の言語で確かめてみました。

実験方法

至ってシンプルで、

URL1 http://saruhei1989.hatenablog.com/
URL2 //saruhei1989.hatenablog.com/

の上記2リンクを用意して、それぞれを各言語でパースするだけです。
URL2はプロトコルを省略したものです。一応aタグのsrcに指定したら両方正しく遷移するものを用意しました。
ご想像の通り、僕が遭遇した不可思議パターンのURLです。

結果

言語 URL1 URL2 URLの定義
Python パースされる パースされる RFC3986
JavaScript パースされる エラーが出る RFC3986, RFC3987
PHP パースされる パースされる RFC3986
Ruby パースされる パースされる RFC3986, RFC3987

Pythonの公式ドキュメント : https://docs.python.org/ja/3/library/urllib.parse.html

JavaScriptは公式が見つからなかったので仕様の記載しているもの : https://developer.mozilla.org/ja/docs/Web/API/URL/URL

PHPの公式ドキュメント : https://www.php.net/manual/ja/function.parse-url.php

Rubyの公式ドキュメント : https://docs.ruby-lang.org/ja/latest/class/URI.html

結論はJavaScriptだけエラーがでました。
言語が違うもの、違ってもおかしくないという話ですが、 RubyJavaScriptはURLの定義どころか、実装の際に利用した仕様が全く一緒のようです。

url.spec.whatwg.org

考察

英語が難しすぎて全然理解が進まなかったのですが、 用意したURLは両方RFC3986の仕様を満たすURLではあるようです。
結論どっちが正しいとか全然わからなかったのですが、言えることは

違う言語をまたいで同じだと思われる処理をするのはやめましょう

ということですね。