For Agileware Drinkup at RubyKaigi 2023 Lightning Talk
自己紹介
渋谷 充宏 @m4buya
- 株式会社ファンファーレ Engineering Manager
- Ruby / SRE / マネジメント
- https://github.com/mshibuya
- RailsAdmin/CarrierWave committer
- 自作キーボード沼に入門しました
この発表について
CarrierWaveというファイルアップロードライブラリには、エンドユーザーからファイルのURLを受け取ってそれをダウンロードし格納する仕組みがあります。そこでURI/URLを扱うのが意外と難しいなぁ…という話をします
URI
皆様よくご存じ、Uniform Resource Identifier。
Rubyでは標準ライブラリとして URI
が存在していて、いろんなURIを便利に扱える。
が、わりと仕様に厳密に即した入力を要求する。
Ruby URIライブラリが扱えないURIの例
これらのURIはRFC違反なので使えません、と言い切ってしまう手もあるが…
irb(main):001:0> URI.parse('https://example.com/file[1].txt')
/Users/mshibuya/.anyenv/envs/rbenv/versions/3.2.1/lib/ruby/3.2.0/uri/rfc3986_parser.rb:66:in `split': bad URI(is not URI?): "https://example.com/file[1].txt" (URI::InvalidURIError)
from /Users/mshibuya/.anyenv/envs/rbenv/versions/3.2.1/lib/ruby/3.2.0/uri/rfc3986_parser.rb:71:in `parse'
エンドユーザーはURIに対しふわっとした期待を持っている!
???「ブラウザのアドレスバーに入れたらちゃんと出るものがダウンロードできないのはバグでしょ」
特にIDNAが厄介で、この表記がなされたもの自体はURIそのものではなく「規定のエンコードがなされたURIをアプリケーションがよしなに表示できる」という扱い…
そこで Addressable
RubyのIDNA対応URIライブラリとしてポピュラー。
入力にもかなり寛容なので、ユーザーの期待に近い
IDNAを扱うには
#normalize します
irb(main):001:0> Addressable::URI.parse('https://ドメイン名例.jp/').normalize
=> #<Addressable::URI:0x382c URI:https://xn--eckwd4c7cu47r2wf.jp/>
落とし穴
URI全体をnormalizeしてしまうと、pathなども別物になってしまう!
irb(main):001:0> Addressable::URI.parse('https://example.com/o%CC%88.png').normalize
=> #<Addressable::URI:0x7170 URI:https://example.com/%C3%B6.png>
実装された運用
uri = Addressable::URI.parse(source)
uri.host = uri.normalized_host
uri.to_s
とりあえずこんな感じにお茶を濁してます…問題が出ないといいな
まとめ
- URI、おなじみなんですが考えることが多くて意外と難しい
- おすすめの方法があったら教えてください
- 人間はいい加減なのでできるだけURIを書かせてはいけない(戒め)