読者です 読者をやめる 読者になる 読者になる

M12i.

学術書・マンガ・アニメ・映画の消費活動とプログラミングについて

SVNKitのSVNURLオブジェクトまわりがちょっと不思議

Java

ちょっとしたツールを作成したくてSVNKitについて調べていたら、SVNURLオブジェクトで不思議なものを見つけた。

そもそもの発端は SVNURL . parseURIDecoded (String) メソッドが“Deprecated”と指定されているのに、Javadocにはその代替APIについて何も記載がなかったこと。というかこのポストでも指摘されているようにJavadocには廃止予定であること自体何らの記載もない。

SVNURL.parseURIDecoded has been deprecated in 1.7.5-v1, but the javadoc doesn't offer any explanation or alternative. What do we do if we are currently using this method?
SVN.parseURIDecodedメソッドは1.7.5-v1時点で廃止予定となっている。けれどもJavadocには何らその説明がないし代替の提示もされていない。今現在このメソッドを使っている場合、一体どうしたらいいの?)

このメソッドUTF-8エンコードされていないURL文字列を受け取ってパースし、そのURLをあらわすSVNURLオブジェクトを生成する。しかし廃止予定だという(ちなみに現在の最新バージョンは1.8系)。

それで前掲の記事別の記事を参考にした結果、次のようにするのがよさそうだと判断した。

final String rawStringUrl = "...";
final String autoEncodedUrl = SVNEncodingUtil.autoURIEncode(rawStringUrl);
final SVNURL svnUrl = SVNURL.parseURIEncoded(autoEncodedUrl);


しかし、一体どうちがうのだろうかと思い、検証してみた結果が以下の通り:

半角スペースあり

API 文字列/URL
(処理前) http://example.com/foo var/baz.txt#hash
parseURIDecoded http://example.com/foo%E3%80%80var/baz.txt%23hash
parseURIEncoded http://example.com/foo%E3%80%80var/baz.txt%23hash
autoURIEncode
+ parseURIEncoded
http://example.com/foo%E3%80%80var/baz.txt%23hash

おおむね予想通りではあるけど、SVNURL.parseURIEncoded(String)メソッドの挙動が気になるところではある。何しろエンコード済みのはずの文字列をパースしているのに、勝手に再度エンコードを行っている。

マルチバイト文字あり

API 文字列/URL
(処理前) http://example.com/foo/var/ばず.txt#hash
parseURIDecoded http://example.com/foo/var/%E3%81%B0%E3%81%9A.txt%23hash
parseURIEncoded http://example.com/foo/var/%E3%81%B0%E3%81%9A.txt%23hash
autoURIEncode
+ parseURIEncoded
http://example.com/foo/var/%E3%81%B0%E3%81%9A.txt%23hash

この結果も前回同様。

エンコード+未エンコード

API 文字列/URL
(処理前) http://example.com/foo%20var/ばず.txt#hash
parseURIDecoded http://example.com/foo%2520var/%E3%81%B0%E3%81%9A.txt%23hash
parseURIEncoded http://example.com/foo%20var/%E3%81%B0%E3%81%9A.txt%23hash
autoURIEncode
+ parseURIEncoded
http://example.com/foo%20var/%E3%81%B0%E3%81%9A.txt%23hash

やっとparseURIDecoded(String)メソッドの問題点が明らかになる。未エンコード文字が存在すると、とにかくURL全体が再度エンコードされるため、半角スペースがエンコードされた結果である“%20”が、再度エンコードされて“%2520”になってしまった。

とにかくいろいろ入れてみる

API 文字列/URL
(処理前) http://example.com/foo/var/,;:$&+=?!/baz.txt#hash
parseURIDecoded http://example.com/foo/var/,%3B:$&+=%3F!/baz.txt%23hash
parseURIEncoded http://example.com/foo/var/,%3B:$&+=%23hash
autoURIEncode
+ parseURIEncoded
http://example.com/foo/var/,%3B:$&+=%3F!/baz.txt%23hash

URIの仕様を確認しながら扱いの微妙そうな文字をいろいろ突っ込んでみた。すると今度はparseURIEncoded(String)単体で用いた場合に変な結果となった。“?”のあとに続く文字列のパースに失敗している。

まとめ(?)

とまあ、そんなわけで、結局いちばん安全なのはSVNEncodingUtil . autoURIEncode(String)と
SVNURL . parseURIEncoded(String)を同時に使う方法らしい。

これは明らかに手間だし、振り返ってみるとSVNURL.parseURIDecoded(String)がいちばん予測可能な挙動(1文字でもURIとして不正な文字が含まれているならそのURL全体がエンコードされる)を示しており、このAPIがわざわざ“Deprecated”と指定される理由がやはりよくわからない。