bokken.io
作成日
2022-07-31
更新日
2022-07-31
author
@bokken_
tag
GitHub, permalink

はじめに

筆者は VS Code で GitHub の permalink をコピーできる拡張機能をよく使っている。

この拡張機能は一部のエンコードが必要な URL についてはサポートされていない。

例えば、下記のような pathname を持つファイルは正しい URL をコピーできない。

/@foo/[bar]/a !"#$%&'()*+,-.:;<=>?@[\]^`{|}~.txt

今回はこの URL がどのように生成されているのか調べてみることにした。

TL;DR

早く知りたい人向けに結論を書く。

この調査結果に至るまでの過程について次の節で述べる。

調査

まず、GitHub の permalink の基本的な形式は下記のようになっている。

https://github.com/${owner}/${repository}/${commit_hash}/blob/${path_name}?query=test#L11

調査をする過程でgithub-url-test というリポジトリを作って確認をしていた。そして、GitHub の URL は少し奇妙な規則でURL エンコードされていることに気づいた。よくある encodeURI や encodeURIComponent を単独で利用した場合にエンコードされる URL とは異なる URL になる。

例えば、 ファイル名にある # は パーセントエンコードされるが、!&' といった記号はパーセントエンコードされないといった具合だ。

前述したファイルのパスは下記のようにエンコードされる。

/@foo/%5Bbar%5D/a%20!%22%23$%25&'()*+,-.:;%3C=%3E%3F@%5B%5C%5D%5E%60%7B%7C%7D~.txt

各記号とそれがどのようにエンコードされるのかをまとめたのが下記の表だ。

記号 GitHub permalink 上の表現 encodeURI encodeURIComponent
SP %20 %20 %20
! ! ! !
" %22 %22 %22
# %23 # %23
$ $ $ %24
% %25 %25 %25
& & & %26
' ' ' '
( ( ( (
) ) ) )
* * * *
+ + + %2B
, , , %2C
- - - -
. . . .
/ / / /
: : : %3A
; ; ; %3B
< %3C %3C %3C
= = = %3D
> %3E %3E %3E
? %3F ? %3F
@ @ @ %40
[ %5B %5B %5B
\ %5C %5C %5C
] %5D %5D %5D
^ %5E %5E %5E
` %60 %60 %60
{ %7B %7B %7B
| %7C %7C %7C
} %7D %7D %7D
~ ~ ~ ~

但し、URL 末尾に行番号を表すときに付与されるフラグメントの # や、クエリパラメータを表す ? はエンコードされない。 合わせて / がファイル名としては使えなかったので、 / のままとしている。

上記の表を見てみると、おおむね encodeURI でエンコードされる内容と同じである。 異なっているのは、#? のみである。

これは、#? がフラグメントやクエリパラメータとして特別な意味を持っているため、ファイル名で使えないためだと考えられる。

エンコード処理

これらのことから、エンコード前の GitHub の URL を permalink の形式にする処理としては下記のようになるだろう。

const encoded = encodeURI(url).replace('#', '%23').replace('?', '%3F')

ただし、クエリパラメータや、URL フラグメントがある場合は分離した上で url として渡す必要がある。

なお、GitHub 上のページ遷移で表示されるリンクと permalink の生成とでエンコードされる URL は違うようである。例えば @ は、permalink 上ではエンコードされないが、GitHub 上のリンクの遷移では %40 にエンコードされる。

おわりに

分かってしまうと簡単な規則でパーマリンクが実現されていることが分かった。

普段からお世話になっている GitHub の permalink をコピーできる拡張機能 にも fix する PR を送ろうと思う。

もしも誤りや、他の permalink 生成の規則とも同一であることが分かった場合は、@bokken_ までお知らせしてもらえると嬉しい。

Tweet このエントリーをはてなブックマークに追加
Subscribe via RSS
TOP