URLの解析
Parse URL
原則として、自力で解析してはならない。
URL は複雑化し、自力で文字列解析するのはもはや困難になっている。
Web で検索して見つかるコード例の大半が間違っている。
自力で解析をすることを避ける。必ず適切なライブラリを使うこと。
自力で解析すると、以下のような問題が発生しやすい。
仕様の理解不足による不正な解析とそれによる脆弱性の作り込み
パフォーマンスの低下
decodeURI は間違っている API なので使ってはならない!
例外的に「人間が目で見るための文字列への変換」として表示のみに使う時には使えないこともない。
基本的にはどう分解されるべきなのか?
URL は形式的には以下になっている。
scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
分解するときには以下のようになる。
scheme(protocol) (http, https, ftp など)
authority
userInfo
user
password
host
書かれているホスト名
DNSに渡せるホスト名
人間が見るときのホスト名
port (port の指定がない場合は scheme のデフォルト値)
path
query (?a=xxx&b=yyy)
fragment (#xxx)
恐らく最も正確なURLの解析方法(WHATWGによる)
URL Living standard 4.4. URL parsing https://url.spec.whatwg.org/#url-parsing
考慮すべき事
国際化ドメイン名(IDN)の考慮が必要。
使用可能な文字について、規格ごとに違いがある。WHATWGの規格が最も正しいと考えられる。
いきなりパーセントエンコーディング(%xx)をデコードしてはならない。
パーセントエンコーディングは URL の表記とぶつからないためなので、要素に分解してからのみデコードが可能。
既に URL の形状になっているならば、:,/,?,#,&,= は避けるようにパーセントエンコーディングされているはずなので、これを頼りに分解してよい。
scheme はパーセントエンコーディングが許されていない。よって単純判定が可能。
^[A-Za-z][A-Za-z0-9+\-]*:
authority の中で@は複数回現れることがある。このため、もしあれば最後の@がセパレータとして正しい。
@はパーセントエンコーディングされていないことがある。(本来的にはされるべきと思うが)
scheme, host, port に空白文字が含まれていれば不正。
user, password, path, query, fragment には空白文字が現れる可能性がある。
これはパーセントエンコーディングされているべき。
host の長さは最大255文字。
分解した要素へのアクセスはパーセントエンコーディングを外した物でなければならない。
二重エンコード、二重デコードの防止
絶対URLと相対URLがあり、相対URLのままで取り扱いたいケースがある。
しかし厳密に考えれば、相対URLは scheme が不明瞭では取り扱えない。
通常はなかなか目にすることはないが、特殊な組み合わせは考えられる。
http:../foo のようにすることもできないことはない。
URL は複数のプロトコルで統一的に文書を参照するために考え出された。
[翻訳]”URL”の歴史 — Cloudflare Blog https://medium.com/@teruhisafukumoto/the-history-of-the-url-at-cloudflare-e6857c2658a2
URL から URN が発明され、URI として統合された。
URN のアイデアは、ページ内容をハッシュ値にするというもの。
実際には ISBN, DOI などで使われているだけになった。
実際には URN を解析することはほぼない。せいぜい URN って URL によく似ているねくらいの意味。URI 解析と言いながら URL しか解析できないライブラリが普通。
正しく URN を解釈したとしても得られるのは scheme と path 部のみなのであまりメリットがない。
URN を真面目に解析するならば、scheme ごとに専用のパーサーが必要となる。よって気にした方が負け。
各言語での解析方法
https://rosettacode.org/wiki/URL_parser
GNU Free Documentation License 1.2 に注意
ここにはパーセントエンコーディングが含まれていない
やっつけなコードになっているので、そのまま使うのはあまり望ましくない。
JavaScript
https://developer.mozilla.org/ja/docs/Web/API/URL
要素ごと
href (全体)
protocol (":"含む)
username
password
host (= hostname + ":" + port)
hostname
port
pathname
search (?以降のいわゆるクエリ文字列)
書き込むとエスケープする。(エスケープしたものを書き込んではならない)
読み出したものはエスケープされた文字列になる。(エスケープせずに文字列結合できる。)
searchParams (パラメータごとに分かれた辞書)
書き込むとエスケープする。(エスケープしたものを書き込んではならない)
読み出したものはアンエスケープされた文字列になる。
hash (#以降)
.NET Framework (C#)
System.Uri
https://docs.microsoft.com/ja-jp/dotnet/api/system.uri?view=netcore-3.1
OriginalString
AbsoluteUri
Scheme
UserInfo
Host
IdnHost
DnsSafeHost
Port
PathAndQuery
AbsolutePath
LocalPath
Segments
Query
Fragment
System.Web.HttpUtility.ParseQueryString
クエリ文字列の解析
https://docs.microsoft.com/ja-jp/dotnet/api/system.web.httputility.parsequerystring?view=netcore-3.1]
参考
URLを解析する (.NET Framework) https://dobon.net/vb/dotnet/internet/analyzeurl.html
PowerShell
文字列を url に型変換すると解析される。
code:ps1
PS > url"http://apserver:22427/ssp/admin?k1=v1&k2=v2#blah"
AbsolutePath : /ssp/admin
AbsoluteUri : http://apserver:22427/ssp/admin?k1=v1&k2=v2#blah
LocalPath : /ssp/admin
Authority : apserver:22427
HostNameType : Dns
IsDefaultPort : False
IsFile : False
IsLoopback : False
PathAndQuery : /ssp/admin?k1=v1&k2=v2
Segments : {/, ssp/, admin}
IsUnc : False
Host : apserver
Port : 22427
Query : ?k1=v1&k2=v2
Fragment : #blah
Scheme : http
OriginalString : http://apserver:22427/ssp/admin?k1=v1&k2=v2#blah
DnsSafeHost : apserver
IdnHost : apserver
IsAbsoluteUri : True
UserEscaped : False
UserInfo :
参考
https://social.technet.microsoft.com/Forums/ie/en-US/38d06bcb-8842-47af-9d86-166dd4ee97e3/how-do-i-split-a-url?forum=winserverpowershell
PHP
https://www.php.net/manual/ja/function.parse-url.php
https://www.php.net/manual/ja/function.parse-str.php
クエリ文字列の解析
配列型のクエリ文字列を解析できるのが特徴
scheme
user
pass
host
port
path
query
fragment
関連仕様
RFC 8141 Uniform Resource Names (URNs)
RFC 3986 Uniform Resource Identifier (URI): Generic Syntax
RFC 3987 Internationalized Resource Identifiers (IRIs)
IDN Info by JPRS https://jprs.co.jp/idn/
#URL