0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

prismaでmysqlに繋ぐ時、DATABASER_URLに渡す文字のエンコードの話

Posted at

どういう記事?

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を行っている。具体的には以下のコード

prisma-engines/quaint/src/connector/mysql/url.rs
    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.tomlpercent-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")を使おう。
あとなんか間違えてる事あれば教えてください。

独り言

これ調べてたら土曜日の午後が終わった。こういうのに時間かけすぎで他の事が進まないんだよな。うーーーーーーーむ。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?