Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 12764] ファイルの概要

このコミットは、Go言語のドキュメンテーションツールであるcmd/godocにおけるカスタムパスのリダイレクト処理を正規化(canonicalize)するための変更です。具体的には、末尾のスラッシュの有無にかかわらず、同じリソースへのパスが統一された形式にリダイレクトされるように改善されています。これにより、ユーザーが/ref/doc/reference.htmlのような異なるパスでアクセスした場合でも、最終的に/ref/のような正規化されたパスにリダイレクトされるようになります。

コミット

commit 849ad2d0cac9b3ee97b3d331ca6e556a6073d94d
Author: Andrew Gerrand <adg@golang.org>
Date:   Tue Mar 27 12:44:17 2012 +1100

    cmd/godoc: canonicalize custom path redirects
    
    For example, /ref and /doc/reference.html now both redirect to /ref/.
    
    Fixes #3401.
    
    R=golang-dev, rsc
    CC=golang-dev
    https://golang.org/cl/5916044

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/849ad2d0cac9b3ee97b3d331ca6e556a6073d94d

元コミット内容

cmd/godoc: canonicalize custom path redirects

For example, /ref and /doc/reference.html now both redirect to /ref/.

Fixes #3401.

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5916044

変更の背景

この変更の背景には、godocが提供するドキュメントパスのリダイレクト処理における一貫性の問題がありました。以前のgodocでは、特定のパス(例: /ref)がリダイレクトされる際に、末尾のスラッシュの有無によって異なる挙動を示す可能性がありました。例えば、/ref/ref/が同じリソースを指す場合でも、リダイレクト先が統一されていないと、ユーザー体験の低下や、SEO(検索エンジン最適化)上の問題を引き起こす可能性があります。

このコミットは、godocがカスタムパスのリダイレクトを行う際に、末尾のスラッシュの有無を考慮し、常に正規化された(canonicalな)パスにリダイレクトするように修正することを目的としています。これにより、/ref/doc/reference.htmlのような異なる入力パスが、最終的に/ref/のような単一の正規化されたパスにリダイレクトされるようになり、より予測可能で一貫性のある挙動が実現されます。

コミットメッセージに記載されているFixes #3401は、Goプロジェクトの内部的な課題追跡システムにおける特定のバグまたは改善要求に対応するものであると考えられます。

前提知識の解説

godoc

godocは、Go言語のソースコードからドキュメンテーションを生成し、HTTPサーバーとして提供するツールです。Goのコードに記述されたコメントや宣言から自動的にドキュメントを抽出し、開発者がブラウザを通じて簡単に参照できるようにします。Go言語の標準ライブラリのドキュメントもgodocによって生成され、pkg.go.dev(旧golang.org/pkg)で公開されています。

Canonicalization (正規化)

Canonicalization(正規化)とは、複数の異なる形式で表現されうるデータやリソースを、単一の標準的な形式に変換するプロセスを指します。ウェブの文脈では、URLの正規化がよく行われます。例えば、http://example.com/pagehttp://example.com/page/http://www.example.com/pageがすべて同じコンテンツを指す場合、これらをhttp://example.com/page/のような単一の「正規URL」に統一することで、検索エンジンの評価分散を防ぎ、ユーザー体験を向上させることができます。

パスリダイレクト

パスリダイレクトは、ウェブサーバーが特定のURLへのリクエストを受け取った際に、そのリクエストを別のURLに自動的に転送する仕組みです。これは、ページの移動、URL構造の変更、または複数のURLを単一のリソースに統合する際などに使用されます。HTTPステータスコード3xx(例: 301 Moved Permanently, 302 Found)がリダイレクトのために使用されます。

技術的詳細

このコミットは、src/cmd/godoc/godoc.goファイル内のmetadataFor関数に変更を加えています。metadataFor関数は、与えられた相対パス(relpath)に対応するメタデータ(*Metadata)を取得する役割を担っています。

変更前は、metadataFor関数はdocMetadataから直接relpathに対応するメタデータを検索していました。しかし、この方法では、例えば/ref/ref/のように末尾のスラッシュの有無が異なるパスが、同じリソースを指しているにもかかわらず、別々のエントリとして扱われる可能性がありました。

変更後のコードでは、以下のロジックが追加されています。

  1. まず、元のrelpathでメタデータが存在するかどうかを確認します。存在すれば、それを返します。
  2. もし元のrelpathでメタデータが見つからなかった場合、末尾のスラッシュの有無を反転させて再試行します。
    • もしrelpathが末尾にスラッシュを持っている場合(例: /ref/)、スラッシュを取り除いたパス(例: /ref)で再検索します。
    • もしrelpathが末尾にスラッシュを持っていない場合(例: /ref)、スラッシュを追加したパス(例: /ref/)で再検索します。

この変更により、metadataFor関数は、末尾のスラッシュの有無にかかわらず、同じ論理的なパスに対応するメタデータを適切に取得できるようになり、リダイレクト処理の一貫性が向上します。

コアとなるコードの変更箇所

--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -1315,7 +1315,18 @@ func refreshMetadataLoop() {
 //
 func metadataFor(relpath string) *Metadata {
  if m, _ := docMetadata.get(); m != nil {
-  return m.(map[string]*Metadata)[relpath]
+  meta := m.(map[string]*Metadata)
+  // If metadata for this relpath exists, return it.
+  if p := meta[relpath]; p != nil {
+   return p
+  }
+  // Try with or without trailing slash.
+  if strings.HasSuffix(relpath, "/") {
+   relpath = relpath[:len(relpath)-1]
+  } else {
+   relpath = relpath + "/"
+  }
+  return meta[relpath]
  }
  return nil
 }

コアとなるコードの解説

変更はsrc/cmd/godoc/godoc.goファイルのmetadataFor関数内で行われています。

func metadataFor(relpath string) *Metadata {
	if m, _ := docMetadata.get(); m != nil {
		meta := m.(map[string]*Metadata)
		// If metadata for this relpath exists, return it.
		if p := meta[relpath]; p != nil {
			return p
		}
		// Try with or without trailing slash.
		if strings.HasSuffix(relpath, "/") {
			relpath = relpath[:len(relpath)-1]
		} else {
			relpath = relpath + "/"
		}
		return meta[relpath]
	}
	return nil
}
  1. meta := m.(map[string]*Metadata): docMetadataから取得したメタデータマップをmeta変数にキャストしています。
  2. if p := meta[relpath]; p != nil: まず、引数として渡されたrelpath(例: /ref)がそのままマップのキーとして存在するかどうかを確認します。もし存在すれば、そのメタデータをすぐに返します。これは、最も直接的なマッチングを優先するためです。
  3. if strings.HasSuffix(relpath, "/"): もし最初の試行でメタデータが見つからなかった場合、パスの末尾にスラッシュがあるかどうかをstrings.HasSuffix関数で確認します。
    • relpath = relpath[:len(relpath)-1]: もしスラッシュがある場合(例: /ref/)、そのスラッシュを取り除きます(例: /ref)。
    • relpath = relpath + "/": もしスラッシュがない場合(例: /ref)、スラッシュを追加します(例: /ref/)。
  4. return meta[relpath]: スラッシュの有無を反転させた新しいrelpathで再度メタデータを検索し、その結果を返します。

このロジックにより、metadataFor関数は、/ref/ref/のようなパスのバリエーションを透過的に処理し、どちらの形式でリクエストが来ても適切なメタデータを返すことができるようになります。これにより、godocのリダイレクト処理がより堅牢でユーザーフレンドリーになります。

関連リンク

参考にした情報源リンク

  • GitHubコミットページ: https://github.com/golang/go/commit/849ad2d0cac9b3ee97b3d331ca6e556a6073d94d
  • Go CL 5916044: https://golang.org/cl/5916044
  • Fixes #3401について: このコミットが修正したとされる#3401は、Goプロジェクトの内部的な課題追跡システム(おそらく当時のGo issue tracker)の番号であると考えられます。現在のGitHubのissue trackerで直接この番号を検索しても、当時の関連情報がすぐに見つからない場合があります。これは、issue trackingシステムが時間とともに変更されたり、特定のissueが非公開であったりするためです。