どういう記事?
prismaのdb urlを設定する時にpasswordとusernameをpercent encodingする必要があるが、percent encodingも色々あるみたいなので、調べたログ。あと、windows(powershell)で手軽に手元でpercent encodingする方法を知りたかったのでそれも書いた。
作成日:2025年2月22日
概要
prismaを使用する時に設定するdatabse urlは以下のurlだが、usernameとpasswordのspecial characterはpercent encodingする必要がある。
DATABASE_URL=postgresql://janedoe:mypassword@localhost:5432/mydb
prismaのドキュメントからリンクされているのはMDNのpercent encodingの記事
これによると、変換についてはRFC 3986のsection 2.1に定義されているとのこと。
powershellでpercent encodingをする場合、以下の3つの関数があるっぽい。調べた感じ、一番上のEscapeDataStringを使うのが良さげではある。
1. [uri]::EscapeDataString("text")
2. [System.Net.WebUtility]::UrlEncode("text")
3. [System.Web.HttpUtility]::UrlEncode("text")
1. [uri]::EscapeDataString("text")
[uri]::EscapeDataString
はドキュメントによるとデフォルトでRFC 2396に則ったencodingが行われるが、International Resource Identifiers(IRIs)とInternationalized Domain Name(IDN) parsingがenableならRFC 3986とRFC 3987に則ってencodingが行われるとのこと。
chatGPT曰く最近の環境(powershell 7.1)以降ではIRIとIDNはデフォルトでオンらしいが、それらしい情報は見つけられなかったので、不明。
2. [System.Net.WebUtility]::UrlEncode("text")
ドキュメントによると、
Use EscapeDataString for RFC compliant transformation.
とのこと。これは[System.Net.WebUtility]::UrlEncode()
には慣習的な(web標準ではない)『spaceを+に変える』みたいな処理も入っているから、という事らしい。因みに、このRemarkはドキュメントを英語に切り替えないと出ない。
例えば、te xt
という間にスペースが入った文字列をpercent encodingする時、変換後の文字列に以下のような差が生じる
PS C:> [System.Net.WebUtility]::UrlEncode("te xt")
te+xt
PS C:> [uri]::EscapeDataString("te xt")
te%20xt
prisma側では+をspaceに戻す処理は無いので、もしusernameやpasswordにspaceが入っていて、WebUtilityのUrlEncodeを使ってしまうと、DBに接続できない(そもそもspaceを使うなという感じだが、技術的に使えない訳ではないっぽい)
3. [System.Web.HttpUtility]::UrlEncode("test string")
HttpUtilityはそもそも古いくて、実行前にAdd-Type -AssemblyName System.Web
しないと今の環境では使えない。それに、実行結果は[System.Net.WebUtility]::UrlEncode()
と同じなので、spaceが入ると+になる。率先して使う理由は無さそうではある。
そもそもなぜpercent encodingが必要なのか?
prismaがurlの形式でDBの情報を受け取る時にパスワードに特殊文字が含まれていると正しく接続できないため、ユーザー名やパスワードはurl encodingする必要がある。
どう処理されている?
prismaのコアはprisma engineという別リポジトリが存在し、その中にQuaintというRust製の種々のDBのための抽象化レイヤーみたいなものがある。元は別repoだったみたいだが、今はQuaintはprisma-engineの一部になっている。
prisma engineはこのquaintを用いてDBに接続する。
そのQuaintの中にmysqlに接続するconnecterがあり、その中でpasswordのdecodeを行っている。具体的には以下のコード
pub fn password(&self) -> Option<Cow<str>> {
match self
.url
.password()
.and_then(|pw| percent_decode(pw.as_bytes()).decode_utf8().ok())
{
Some(password) => Some(password),
None => self.url.password().map(|s| s.into()),
}
}
で、このpercent_decode
に関しては同じファイルの上の方で
use percent_encoding::percent_decode;
として宣言されている。
このQuaintのcargo.tomlを見るとpercent-encoding.workspace = true
と書いてあったので、上の階層から探すと、prisma-engineのrootのcargo.tomlにpercent-encoding = "2"
と書いてあった。普通にRUSTのpercent-encodingを使っているっぽい。
で、そのRustのpercent_encodingにおける、percent_decode
のドキュメントには、whatwgのpercent_decodeのリンクが貼ってあるので、どうやらこのライブラリはWHATWG(Web Hypertext Application Technology Working Group)の標準に従ってるっぽい。
また、
Any sequence of % followed by two hexadecimal digits is decoded. The return type:
とも書いてあるので、純粋に「%と16進数の数字」の組み合わせがあればそれをdecodeして値を返すだけっぽい。
結論
powershellでprisma用のpercent encodingを作る時は[uri]::EscapeDataString("text")
を使おう。
あとなんか間違えてる事あれば教えてください。
独り言
これ調べてたら土曜日の午後が終わった。こういうのに時間かけすぎで他の事が進まないんだよな。うーーーーーーーむ。