[インデックス 14698] ファイルの概要
このコミットは、cmd/godoc
ツールにおいて、末尾にスラッシュが付いたファイルパスへのリクエストを、スラッシュなしの正規のファイルパスへリダイレクトする機能を追加するものです。これにより、godoc
が提供するドキュメントやソースコードの表示において、URLの正規化と一貫性が向上します。具体的には、Fixes #4543
と記載されており、関連するバグ報告に対応しています。
コミット
- コミットハッシュ:
2874cc4eedf1e152f8327c1d93fb5d6a6a973a15
- 作者: Andrew Gerrand adg@golang.org
- 日付: Fri Dec 21 07:03:00 2012 +1100
- コミットメッセージ:
cmd/godoc: redirect for file with trailing / Fixes #4543. R=golang-dev, rsc CC=golang-dev https://golang.org/cl/6971050
- 変更ファイル:
src/cmd/godoc/godoc.go
(1ファイル) - 変更行数: 15行の追加
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/2874cc4eedf1e152f8327c1d93fb5d6a6a973a15
元コミット内容
cmd/godoc: redirect for file with trailing /
Fixes #4543.
R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/6971050
変更の背景
この変更の背景には、godoc
が提供するWebインターフェースにおけるURLの正規化の問題があります。通常、Webサーバーでは、ディレクトリを示すURLには末尾にスラッシュを付けることが一般的ですが、ファイルを示すURLには末尾にスラッシュを付けません。しかし、ユーザーが誤ってファイルパスの末尾にスラッシュを付けてアクセスした場合、godoc
はそのリクエストを正しく処理できないか、または期待しない動作をする可能性がありました。
Fixes #4543
とあるように、このコミットは特定のバグ報告(Issue 4543)に対応しています。このバグは、godoc
がファイルを提供するときに、末尾のスラッシュを適切に扱わないことによって発生していたと考えられます。例えば、/path/to/file.go/
のようにアクセスされた場合に、/path/to/file.go
へとリダイレクトすることで、一貫したURL表現と正しいコンテンツの提供を保証することが目的です。
Go言語の標準ライブラリである net/http
パッケージの http.ServeMux
は、末尾のスラッシュの有無によってリダイレクトを行うデフォルトの挙動を持っています。これは、ディレクトリとファイルの区別を明確にし、一貫したルーティングを保証するためです。しかし、このコミットが修正しようとしているのは、おそらく http.ServeMux
のデフォルトの挙動だけではカバーしきれない、特定のファイルパスに対する末尾スラッシュの処理に関する godoc
固有の問題であったと推測されます。
前提知識の解説
godoc
: Go言語の公式ドキュメンテーションツールです。Goのソースコードからドキュメントを生成し、Webサーバーとして提供する機能も持っています。開発者はgodoc
をローカルで実行することで、Goの標準ライブラリや自身のプロジェクトのドキュメントをブラウザで閲覧できます。- HTTPリダイレクト (301 Moved Permanently): Webサーバーがクライアントに対して、リクエストされたリソースが恒久的に別のURLに移動したことを伝えるHTTPステータスコードです。ブラウザはこれを受け取ると、新しいURLに自動的にリクエストを再送信します。SEOの観点からも、URLの正規化に広く利用されます。
- URLパスと末尾のスラッシュ: URLのパス部分は、Webサーバー上のリソースの場所を示します。
example.com/dir/
: 通常、dir
という名前のディレクトリを示します。example.com/file.html
: 通常、file.html
という名前のファイルを示します。 Webサーバーによっては、example.com/dir
へのアクセスをexample.com/dir/
へリダイレクトしたり、その逆を行ったりすることがあります。このコミットでは、ファイルパスに誤って付与された末尾のスラッシュを削除するリダイレクトを扱っています。
pathpkg.Clean
: Go言語のpath
パッケージ(通常はpathpkg
としてインポートされる)のClean
関数は、パスを簡潔な形式に変換します。例えば、a/b/../c
はa/c
に、a//b
はa/b
に、/a/b/
は/a/b
になります。この関数は、パスの正規化に非常に役立ちます。strings.HasSuffix
: Go言語のstrings
パッケージの関数で、ある文字列が特定の接尾辞で終わるかどうかを判定します。
技術的詳細
このコミットは、godoc
のWebサーバー機能において、ファイルパスの末尾に不要なスラッシュが付いている場合に、それを削除して正規のパスにリダイレクトする新しい関数 redirectFile
を導入しています。
既存の serveFile
関数は、ファイルの種類を判別し、テキストファイルであれば serveTextFile
を呼び出すロジックを持っています。この変更では、serveTextFile
を呼び出す前に redirectFile
を呼び出すように修正されています。
redirectFile
関数の内部では、以下の処理が行われます。
r.URL.Path
(リクエストされたURLパス) をpathpkg.Clean
で正規化し、c
に格納します。pathpkg.Clean
は、末尾のスラッシュを削除する効果もあります。for strings.HasSuffix("/", c)
ループを使って、c
の末尾にスラッシュが残っている限り、そのスラッシュを削除します。pathpkg.Clean
は通常、末尾のスラッシュを削除しますが、念のためこのループで確実に削除しています。- 正規化されたパス
c
が元のリクエストパスr.URL.Path
と異なる場合、つまり末尾のスラッシュが削除された場合、http.Redirect
を使用してhttp.StatusMovedPermanently
(301) ステータスコードで正規のパスc
へリダイレクトします。 - リダイレクトが行われた場合は
true
を、そうでない場合はfalse
を返します。
serveFile
関数では、isTextFile(abspath)
が true
の場合に、まず redirectFile(w, r)
を呼び出します。もし redirectFile
が true
を返した場合(つまりリダイレクトが行われた場合)、それ以上処理を進めずに return
することで、二重の処理を防ぎます。これにより、ユーザーは常に正規化されたURLでコンテンツにアクセスできるようになります。
この修正は、godoc
の堅牢性とユーザーエクスペリエンスを向上させ、URLの正規化に関する一般的なWebの慣習に沿ったものとなります。
コアとなるコードの変更箇所
--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -658,6 +658,18 @@ func redirect(w http.ResponseWriter, r *http.Request) (redirected bool) {
return
}
+func redirectFile(w http.ResponseWriter, r *http.Request) (redirected bool) {
+ c := pathpkg.Clean(r.URL.Path)
+ for strings.HasSuffix("/", c) {
+ c = c[:len(c)-1]
+ }
+ if r.URL.Path != c {
+ http.Redirect(w, r, c, http.StatusMovedPermanently)
+ redirected = true
+ }
+ return
+}
+
func serveTextFile(w http.ResponseWriter, r *http.Request, abspath, relpath, title string) {
src, err := ReadFile(fs, abspath)
if err != nil {
@@ -749,6 +761,9 @@ func serveFile(w http.ResponseWriter, r *http.Request) {
}
if isTextFile(abspath) {
+ if redirectFile(w, r) {
+ return
+ }
serveTextFile(w, r, abspath, relpath, "Text file")
return
}
コアとなるコードの解説
redirectFile
関数の追加
func redirectFile(w http.ResponseWriter, r *http.Request) (redirected bool) {
c := pathpkg.Clean(r.URL.Path)
for strings.HasSuffix("/", c) {
c = c[:len(c)-1]
}
if r.URL.Path != c {
http.Redirect(w, r, c, http.StatusMovedPermanently)
redirected = true
}
return
}
この新しい関数 redirectFile
は、リクエストされたURLパス r.URL.Path
を受け取り、そのパスがファイルを示すものでありながら末尾に不要なスラッシュが付いている場合に、正規のパスへリダイレクトする役割を担います。
-
c := pathpkg.Clean(r.URL.Path)
:pathpkg.Clean
は、パスを正規化します。例えば、/a/b/../c/
のようなパスは/a/c
に、/a//b
は/a/b
になります。また、末尾のスラッシュも削除される傾向があります。この行で、まずパスを一般的なクリーンな形式に変換します。 -
for strings.HasSuffix("/", c) { c = c[:len(c)-1] }
:pathpkg.Clean
が末尾のスラッシュを完全に削除しないケース(例えば、ルートパス/
の場合など)や、より確実にするために、このループが追加されています。strings.HasSuffix("/", c)
は、文字列c
が/
で終わるかどうかをチェックします。もし終わっていれば、c = c[:len(c)-1]
によって末尾の/
を削除します。これにより、パスの末尾からすべてのスラッシュが取り除かれます。 -
if r.URL.Path != c { ... }
: 元のリクエストパスr.URL.Path
と、スラッシュが削除され正規化されたパスc
を比較します。もし両者が異なる場合、それはリダイレクトが必要であることを意味します。 -
http.Redirect(w, r, c, http.StatusMovedPermanently)
:http.Redirect
関数は、HTTPリダイレクトを実行します。w
:http.ResponseWriter
で、HTTPレスポンスを書き込むためのインターフェースです。r
:*http.Request
で、受信したHTTPリクエストの情報を含みます。c
: リダイレクト先の新しいURLパスです。http.StatusMovedPermanently
: HTTPステータスコード301を表します。これは、リソースが恒久的に新しいURLに移動したことをクライアントに伝えます。ブラウザや検索エンジンは、この情報に基づいてキャッシュを更新し、今後のリクエストを新しいURLに送るようになります。
-
redirected = true
: リダイレクトが行われたことを示すために、戻り値redirected
をtrue
に設定します。
serveFile
関数での呼び出し
func serveFile(w http.ResponseWriter, r *http.Request) {
// ... (既存のコード) ...
if isTextFile(abspath) {
+ if redirectFile(w, r) {
+ return
+ }
serveTextFile(w, r, abspath, relpath, "Text file")
return
}
// ... (既存のコード) ...
}
serveFile
関数は、ファイルを提供するための主要なハンドラです。この変更では、テキストファイル(isTextFile(abspath)
が true
の場合)を処理する前に、新しく追加された redirectFile
関数を呼び出すように修正されています。
if redirectFile(w, r) { return }
:redirectFile
を呼び出し、その戻り値を確認します。もしredirectFile
がtrue
を返した場合(つまり、リダイレクトが実行された場合)、それ以上このリクエストに対する処理は不要なので、serveFile
関数を即座にreturn
します。これにより、リダイレクト後にserveTextFile
が誤って呼び出されることを防ぎ、効率的かつ正しい動作を保証します。
この変更により、godoc
はファイルパスの末尾スラッシュ問題を適切に処理し、ユーザーに正規化されたURLを提供できるようになりました。
関連リンク
- Go CL (Code Review) リンク: https://golang.org/cl/6971050
- 関連するGitHub Issue:
Fixes #4543
(ただし、直接的なIssueページはWeb検索では見つかりませんでした。GoのIssueトラッカーは時期によってURL構造が異なる場合があります。)
参考にした情報源リンク
http.ServeMux
のデフォルトの挙動に関するStack Overflowの議論: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFe1dW7VA8wtd_MknCLhvyOPV_auP0Bij-uW8DChWLwmIKCHzg_YGcbg94Pd-AGV47Li_XNb9F60m10EmBXWY2IlrXQnIbzXyqWuf2O0e2gABXHe1N2iKzMjT-KdDAMwkiayy5hkAo8LxUfF0WVlFGr4a47Z_shoiq_6k9xoqu4_SWlG_5I6-sxH0j368qqw2Mquoba9F6BGo-48f_IJe_xpkgsite
のショートカットリダイレクトに関するIssue #40166: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFs0XvvIPk3rDpUu9zKcm1L8Sl0QXGnWHMAKQramUAVzDZcUl6MfDFkard9aGYrd_vAMnqP_MY5WVNnGXwbBOVXb1veJPFij6MUGKZ9obMuRMjw37R1rmsPD9fodhbgg1zqbt0gnet/http
の無限リダイレクトに関するIssue #67657: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQFGGrjg2YMoR3BH7D22CcYdy-oYH9HGRVoH4Fym9wsBKtrL9vMfrm7wouPblayrlyyQWzF35nPsN4sBcolYCp--lnVUHD64NzCQZ7GhmTEl5RHdizmyF0300wQC6yLCW3li2dZDhttp.ServeMux
の予期せぬリダイレクトに関するIssue #11757: https://vertexaisearch.cloud.google.com/grounding-api-redirect/AUZIYQGTSGmsL4YdpfqELkpzgPGNypeC39qQIP1Q7bmOuokVerZKpJYmeCGlx-TBUR2Lwbso9952RpHc8reRGBUJE2OF5NQp7RMQSkcTAbK8G-uXcJeUwxT3JyEHhoNHrD3CrBJVtz-t