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

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

このコミットは、Go言語のドキュメンテーションツールである godoc におけるリモート検索機能のバグ修正に関するものです。具体的には、リモート検索時に使用されるURLが正しく構築されていなかった問題を解決し、-html フラグと組み合わせた際にもHTML形式での検索結果が正しく取得できるように改善しています。

コミット

  • コミットハッシュ: e8188c160762f654369cdba535324a97df6aed22
  • 作者: Robert Griesemer gri@golang.org
  • コミット日時: 2011年11月11日 金曜日 16:59:47 -0800
  • 変更ファイル:
    • src/cmd/godoc/godoc.go
    • src/cmd/godoc/main.go
  • 変更概要: src/cmd/godoc/godoc.go に14行追加、src/cmd/godoc/main.go から3行削除、合計15行の追加と3行の削除。

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

https://github.com/golang/go/commit/e8188c160762f654369cdba535324a97df6aed22

元コミット内容

godoc: fix remote search (use correct URL)

Also works now together with -html, as in:
godoc -html -q Sin
for an html result.

Fixes #2435.

R=iant
CC=golang-dev
https://golang.org/cl/5375074

変更の背景

このコミットは、godoc コマンドのリモート検索機能が正しく動作しないというバグ(Issue #2435)を修正するために行われました。元の実装では、リモートサーバーに検索リクエストを送信する際のURLの構築に問題があり、特に検索クエリに特殊文字が含まれる場合や、HTML形式での結果を要求する -html フラグが使用された場合に、期待通りの結果が得られませんでした。

具体的には、以下の問題が考えられます。

  1. URLエンコーディングの不備: 検索クエリ文字列がURLの一部として送信される際、スペースや記号などの特殊文字が適切にエンコードされていないと、サーバー側で正しく解釈されず、検索が失敗したり、意図しない結果が返されたりします。
  2. HTML出力の考慮不足: godoc -html -q <query> のように -html フラグを使用してHTML形式の出力を要求した場合、リモート検索のURLがその要求を適切に反映していなかった可能性があります。例えば、テキスト形式の検索結果を要求するURLとHTML形式の検索結果を要求するURLが異なっていたにもかかわらず、常にテキスト形式のURLが使用されていた、といった状況が考えられます。

このコミットは、これらの問題を解決し、godoc のリモート検索機能がより堅牢で、ユーザーの期待通りに動作するようにすることを目的としています。

前提知識の解説

godoc

godoc は、Go言語の公式ドキュメンテーションツールです。Goのソースコードからコメントや宣言を解析し、パッケージ、関数、型などのドキュメンテーションを生成・表示します。ローカルのGoインストールに含まれるパッケージのドキュメントを表示するだけでなく、golang.org などのリモートサーバー上のドキュメントを検索する機能も持っています。

  • ローカルドキュメントの表示: godoc fmt のように実行すると、標準ライブラリの fmt パッケージのドキュメントを表示します。
  • HTTPサーバーモード: godoc -http=:8000 のように実行すると、ローカルでドキュメンテーションサーバーを起動し、ウェブブラウザからアクセスしてドキュメントを閲覧できます。これは golang.org/pkg のようなインターフェースを提供します。
  • リモート検索: godoc -q <query> のように実行すると、リモートの golang.org などのサーバーに対して検索クエリを送信し、関連するドキュメントを検索します。

URLエンコーディング

URL(Uniform Resource Locator)は、インターネット上のリソースを一意に識別するための文字列です。URLには、特定の文字セット(英数字、一部の記号)しか使用できません。スペースや日本語などの非ASCII文字、あるいはURLの構文で特別な意味を持つ文字(例: ?, &, /, #)をURLに含める場合、それらの文字は「パーセントエンコーディング」(Percent-encoding)と呼ばれる形式で変換される必要があります。

例えば、スペースは %20 に、?%3F にエンコードされます。Go言語では、net/url パッケージの QueryEscape 関数がこの処理を提供します。

HTTP GETリクエストとクエリパラメータ

ウェブブラウザやHTTPクライアントがサーバーから情報を取得する際によく使われるのがHTTP GETリクエストです。GETリクエストでは、クライアントがサーバーに送るデータ(検索クエリなど)をURLの末尾に「クエリパラメータ」として含めることができます。クエリパラメータは ? の後に キー=値 の形式で記述され、複数のパラメータは & で区切られます。

例: https://example.com/search?q=Go+language&page=1 ここで qpage がクエリパラメータです。

技術的詳細

このコミットの技術的な核心は、godoc のリモート検索機能が、検索クエリと出力形式(テキストまたはHTML)に応じて適切なURLを生成するように修正された点にあります。

以前の remoteSearch 関数では、検索URLが以下のようにハードコードされていました。

search := "/search?f=text&q=" + url.QueryEscape(query)

このコードには以下の問題がありました。

  1. f=text の固定: 常に f=text というクエリパラメータが使用されており、HTML形式の検索結果を要求する -html フラグが指定されても、それがURLに反映されませんでした。godoc -html -q Sin のようなコマンドを実行しても、サーバーはテキスト形式の検索結果を返そうとするため、クライアント側でHTMLとして解釈しようとすると問題が発生します。
  2. URL構築ロジックの分散: 検索URLの構築ロジックが remoteSearch 関数内に直接記述されており、将来的に検索パラメータやURL構造が変更された場合に、修正が困難になる可能性がありました。

このコミットでは、これらの問題を解決するために、新しいヘルパー関数 remoteSearchURL が導入されました。

remoteSearchURL 関数の導入

remoteSearchURL 関数は、検索クエリ文字列 (query) と、HTML形式の結果を要求するかどうかを示すブール値 (html) を引数として受け取ります。この関数は、これらの引数に基づいて適切な検索URLを生成し、返します。

func remoteSearchURL(query string, html bool) string {
	s := "/search?m=text&q=" // デフォルトはテキスト形式
	if html {
		s = "/search?q=" // HTML形式の場合は異なるパス
	}
	return s + url.QueryEscape(query) // クエリを適切にエンコード
}

この変更により、以下の点が改善されました。

  • 出力形式の動的な切り替え: html 引数に基づいて、m=text パラメータの有無を切り替えることで、サーバーに対してテキスト形式またはHTML形式の検索結果を適切に要求できるようになりました。
  • URLエンコーディングの徹底: url.QueryEscape(query) を使用することで、検索クエリに含まれる特殊文字が常に正しくURLエンコードされるようになりました。これにより、検索クエリがサーバーに正確に伝達され、検索の信頼性が向上します。
  • 関心の分離: URL構築ロジックが remoteSearchURL 関数にカプセル化されたことで、remoteSearch 関数はURLの取得に専念できるようになり、コードの可読性と保守性が向上しました。

main.go からの net/url インポートの削除

src/cmd/godoc/main.go から net/url パッケージのインポートが削除されました。これは、以前 main.go 内の remoteSearch 関数で直接 url.QueryEscape を使用していたためですが、新しい remoteSearchURL 関数が godoc.go に移動し、そこで net/url をインポートするようになったため、main.go では不要になったためです。これは、依存関係の整理とコードのクリーンアップの一環です。

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

src/cmd/godoc/godoc.go

--- a/src/cmd/godoc/godoc.go
+++ b/src/cmd/godoc/godoc.go
@@ -16,6 +16,7 @@ import (
 	"io"
 	"log"
 	"net/http"
+	"net/url" // net/url パッケージのインポートを追加
 	"os"
 	"path"
 	"path/filepath"
@@ -845,6 +846,19 @@ func getPageInfoMode(r *http.Request) (mode PageInfoMode) {
 	return
 }
 
+// remoteSearchURL returns the search URL for a given query as needed by
+// remoteSearch. If html is set, an html result is requested; otherwise
+// the result is in textual form.
+// Adjust this function as necessary if modeNames or FormValue parameters
+// change.
+func remoteSearchURL(query string, html bool) string {
+	s := "/search?m=text&q=" // テキスト形式のデフォルトパス
+	if html {
+		s = "/search?q=" // HTML形式のパス
+	}
+	return s + url.QueryEscape(query) // クエリをエンコードして結合
+}
+
 type PageInfo struct {
 	Dirname  string          // directory containing the package
 	PList    []string        // list of package names found

src/cmd/godoc/main.go

--- a/src/cmd/godoc/main.go
+++ b/src/cmd/godoc/main.go
@@ -38,7 +38,6 @@ import (
 	"log"
 	"net/http"
 	_ "net/http/pprof" // to serve /debug/pprof/*
-	"net/url" // この行が削除された
 	"os"
 	"path"
 	"path/filepath"
@@ -165,8 +164,6 @@ func loggingHandler(h http.Handler) http.Handler {
 }
 
 func remoteSearch(query string) (res *http.Response, err error) {
-	search := "/search?f=text&q=" + url.QueryEscape(query) // この行が削除された
-
 	// list of addresses to try
 	var addrs []string
 	if *serverAddr != "" {
@@ -180,6 +177,7 @@ func remoteSearch(query string) (res *http.Response, err error) {\n 	}\n \n 	// remote search
+	search := remoteSearchURL(query, *html) // 新しい remoteSearchURL 関数を呼び出すように変更
 	for _, addr := range addrs {\n 		url := "http://" + addr + search\n 		res, err = http.Get(url)\n```

## コアとなるコードの解説

### `src/cmd/godoc/godoc.go` の変更

1.  **`net/url` のインポート**: `remoteSearchURL` 関数内で `url.QueryEscape` を使用するため、`net/url` パッケージがインポートされました。
2.  **`remoteSearchURL` 関数の追加**:
    *   この関数は、リモート検索のためのURLを構築する責任を持ちます。
    *   `query` (検索文字列) と `html` (HTML形式の結果を要求するかどうか) の2つの引数を受け取ります。
    *   `html` が `true` の場合、URLのパスは `/search?q=` となり、HTML形式の検索結果を要求します。
    *   `html` が `false` の場合(またはデフォルト)、URLのパスは `/search?m=text&q=` となり、テキスト形式の検索結果を要求します。
    *   最後に、`url.QueryEscape(query)` を使って `query` 文字列を適切にURLエンコードし、構築されたパスに結合して返します。これにより、検索クエリに含まれる特殊文字が正しく処理されます。

### `src/cmd/godoc/main.go` の変更

1.  **`net/url` のインポート削除**: `remoteSearch` 関数内で直接 `url.QueryEscape` を呼び出す必要がなくなったため、`main.go` から `net/url` のインポートが削除されました。これは、依存関係を `godoc.go` に集約し、コードのモジュール性を高めるための変更です。
2.  **`remoteSearch` 関数の変更**:
    *   以前の `search := "/search?f=text&q=" + url.QueryEscape(query)` というハードコードされたURL構築ロジックが削除されました。
    *   代わりに、新しく追加された `remoteSearchURL(query, *html)` 関数が呼び出され、適切な検索URLが取得されるようになりました。ここで `*html` は、コマンドライン引数で指定された `-html` フラグの値(ブール値)を参照しています。これにより、ユーザーが `-html` フラグを指定したかどうかに応じて、正しい形式のURLがリモートサーバーに送信されるようになります。

これらの変更により、`godoc` のリモート検索機能は、より正確なURLを生成し、HTML形式の検索結果も正しく扱えるようになりました。

## 関連リンク

*   **Go Issue #2435**: [https://code.google.com/p/go/issues/detail?id=2435](https://code.google.com/p/go/issues/detail?id=2435) (元のGoogle CodeのIssueトラッカーへのリンクですが、現在はGitHubに移行しています。GitHub上の対応するIssueは [https://github.com/golang/go/issues/2435](https://github.com/golang/go/issues/2435) です。)
*   **Go CL 5375074**: [https://golang.org/cl/5375074](https://golang.org/cl/5375074) (GoのコードレビューシステムであるGerritへのリンク)

## 参考にした情報源リンク

*   Go言語公式ドキュメンテーション: [https://golang.org/doc/](https://golang.org/doc/)
*   `net/url` パッケージのドキュメンテーション: [https://pkg.go.dev/net/url](https://pkg.go.dev/net/url)
*   `godoc` コマンドのドキュメンテーション (Goのインストールに含まれる): `go doc cmd/godoc` または `godoc -h`
*   HTTP GET メソッドとクエリパラメータに関する一般的な情報 (MDN Web Docsなど)
*   URLエンコーディングに関する一般的な情報 (RFC 3986など)
*   GitHub上のGoリポジトリ: [https://github.com/golang/go](https://github.com/golang/go)
*   Go Issue #2435 (GitHub): [https://github.com/golang/go/issues/2435](https://github.com/golang/go/issues/2435)