HTTP URLパスの//を「正規化」するのは誤りである

HTTP URLパスの正規化、特に連続するスラッシュ(//)を単一のスラッシュに統一する処理について、これが必ずしも正しくないケースが存在するという議論です。一見するとURLの正規化は好ましい最適化に見えますが、実際にはシステムによってパスの扱いが異なるため、正規化が予期しない動...

HTTP URLパスの正規化、特に連続するスラッシュ(//)を単一のスラッシュに統一する処理について、これが必ずしも正しくないケースが存在するという議論です。一見するとURLの正規化は好ましい最適化に見えますが、実際にはシステムによってパスの扱いが異なるため、正規化が予期しない動作を引き起こす可能性があります。

問題となるのはクラウドストレージサービス(例:Amazon S3)のようなシステムです。S3ではディレクトリの概念がなく、パスは単なるキー名として扱われます。

したがって、`foo/bar.txt`と`foo//bar.txt`は全く異なるキー名として存在し、同じファイルを指しません。複数のスクリプトがパス結合を行う際に、一方は「foo」+「/bar」と結合し、他方は「foo/」+「/bar」と結合する場合、正規化によってこれらが同じパスに統一されてしまい、重大なバグが生じます。

さらに、URLの解析・正規化・エスケープ処理は複雑であり、実装によっても異なります。特にURLをファイルシステムにマッピングする必要がある場合、URLのルールとファイルシステムのルールの違いが問題を複雑化させます。

異なるファイルシステムでもパスの扱いが異なるため、同じ正規化ルールが全ての場合に適用できるわけではありません。URLパスの正規化は慎重に行う必要があり、異なるシステム間でのパス互換性が必要な場合は特に注意が重要です。

HNの反応

コミュニティはURL正規化の落とし穴について具体的な事例を交えて議論しており、S3などクラウドストレージの仕様やファイルシステムとの相違点による問題点を指摘しています。

注目コメント

「しかし、もしかしてあなたはS3を使っているのかもしれません。S3は`foo/bar.txt`と`foo//bar.txt`を完全に異なるものとして扱います。S3ではディレクトリが存在せず、それらはリテラルに、データが保存されているキーの正確な名前です。そのためスクリプトAが「foo」+「/bar」を連結し、スクリプトBが「foo/」+「/bar」を連結すると、突然奇妙な問題が生じます。」— @dale_glass

元記事を読むHN討議を見る