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

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

このコミットは、Go言語の公式ドキュメントツールであるgodocの一部であるcodewalk.goファイルに対する修正です。codewalk.goは、Goのコードウォーク(インタラクティブなチュートリアルやコード解説)を処理するためのハンドラを実装しています。

コミット

  • コミットハッシュ: bb6e685b7b7cc2a9ba7f81b98fa29bfdbf5cff7b
  • 作者: Francisco Souza franciscossouza@gmail.com
  • 日付: Tue Mar 13 09:08:04 2012 +1100
  • コミットメッセージ:
    godoc: fix codewalk handler
    
    For URLs ending with /, the handler did not work, trying to append
    ".xml" to the path.
    
    For instance, the "Share Memory by Communicating" returned the
    following error:
    
            open /Users/francisco.souza/lib/go/doc/codewalk/sharemem/.xml: no such file or directory
    
    R=adg, minux.ma
    CC=golang-dev
    https://golang.org/cl/5797065
    

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

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

元コミット内容

commit bb6e685b7b7cc2a9ba7f81b98fa29bfdbf5cff7b
Author: Francisco Souza <franciscossouza@gmail.com>
Date:   Tue Mar 13 09:08:04 2012 +1100

    godoc: fix codewalk handler
    
    For URLs ending with /, the handler did not work, trying to append
    ".xml" to the path.
    
    For instance, the "Share Memory by Communicating" returned the
    following error:
    
            open /Users/francisco.souza/lib/go/doc/codewalk/sharemem/.xml: no such file or directory
    
    R=adg, minux.ma
    CC=golang-dev
    https://golang.org/cl/5797065
---
 src/cmd/godoc/codewalk.go | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/cmd/godoc/codewalk.go b/src/cmd/godoc/codewalk.go
index 2804ebbe5d..3e38162a48 100644
--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -53,7 +53,9 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
 	}\n \n 	// Otherwise append .xml and hope to find\n-\t// a codewalk description.\n+\t// a codewalk description, but before trim\n+\t// the trailing /.\n+\tabspath = strings.TrimRight(abspath, \"/\")\n \tcw, err := loadCodewalk(abspath + \".xml\")\n \tif err != nil {\n \t\tlog.Print(err)\n```

## 変更の背景

このコミットは、`godoc`ツールにおけるコードウォークハンドラのバグを修正するものです。具体的には、URLがスラッシュ (`/`) で終わる場合に、コードウォークのXML記述ファイルを正しくロードできない問題がありました。

`godoc`のコードウォーク機能は、特定のパス(例: `/doc/codewalk/sharemem/`) にアクセスした際に、そのパスに対応するXMLファイル(例: `sharemem.xml`)を読み込んで表示します。しかし、元の実装では、URLパスの末尾にスラッシュがある場合、そのスラッシュを削除せずに直接`.xml`を付加しようとしていました。

その結果、例えば `/doc/codewalk/sharemem/` というURLに対しては、`sharemem/.xml` のような不正なファイルパスが生成され、`open .../.xml: no such file or directory` というエラーが発生し、コードウォークが表示されないという問題が生じていました。このコミットは、この不正なファイルパス生成を防ぐために、末尾のスラッシュを削除する処理を追加しています。

## 前提知識の解説

### godoc

`godoc`は、Go言語のソースコードからドキュメントを生成し、HTTPサーバーとして提供するツールです。Goのコードは、コメントの書き方によって自動的にドキュメントとして認識され、`godoc`によって整形されて表示されます。これにより、開発者はコードとドキュメントを密接に連携させることができます。`godoc`は、Goの標準ライブラリのドキュメント閲覧にも利用されています。

### Go Code Walk (コードウォーク)

Goのコードウォークは、インタラクティブなチュートリアルやコード解説の形式です。特定のトピックについて、コード例を交えながらステップバイステップで説明し、読者が実際にコードを実行したり、その出力を確認したりできるような仕組みを提供します。これらは通常、XML形式のファイルで記述され、`godoc`サーバーによってレンダリングされます。例えば、「Share Memory by Communicating」は有名なコードウォークの一つです。

### HTTPリクエストパスの処理

Webサーバーは、クライアントからのHTTPリクエストを受け取ると、そのリクエストのURLパスを解析し、適切なハンドラにルーティングします。この際、URLパスの末尾にスラッシュがあるかないかは、Webアプリケーションのルーティングやリソースの特定において重要な意味を持つことがあります。例えば、`/foo`と`/foo/`は、Webサーバーによっては異なるリソースとして扱われることがあります。ファイルシステムにおいては、`/path/to/dir/file.xml`は有効ですが、`/path/to/dir/.xml`は通常、不正なファイル名とみなされます。

### Go言語の `strings.TrimRight` 関数

`strings.TrimRight`は、Go言語の標準ライブラリ`strings`パッケージに含まれる関数です。この関数は、文字列の末尾から指定された文字セットに含まれる文字をすべて削除した新しい文字列を返します。

**関数シグネチャ**:
```go
func TrimRight(s, cutset string) string
  • s: 処理対象の文字列
  • cutset: 削除する文字のセット(文字列として指定)。cutset内の任意の文字がsの末尾に連続して出現する場合、それらの文字はすべて削除されます。

このコミットでは、strings.TrimRight(abspath, "/")のように使用されており、abspath文字列の末尾からスラッシュ (/) をすべて削除する役割を果たします。

技術的詳細

このバグは、godocのコードウォークハンドラが、HTTPリクエストのパスをファイルシステム上のパスに変換する際に、末尾のスラッシュの処理を誤っていたことに起因します。

コードウォークのXMLファイルは、通常、{codewalk_name}.xmlという形式で保存されています。例えば、sharememというコードウォークであれば、sharemem.xmlというファイル名になります。

godocのハンドラは、リクエストされたURLパス(例: /doc/codewalk/sharemem/)から、対応するファイルシステムのパス(例: /Users/francisco.souza/lib/go/doc/codewalk/sharemem)を構築し、その後に.xml拡張子を付加してファイルを開こうとします。

問題は、リクエストパスが / で終わる場合、abspath変数(ファイルシステムの絶対パスを表す)も / で終わってしまう点にありました。このabspathに直接.xmlを付加すると、例えば /Users/francisco.souza/lib/go/doc/codewalk/sharemem/.xml のようなパスが生成されます。ファイルシステムでは、.xmlというファイル名がディレクトリの直下にあると解釈され、これは通常、有効なファイル名ではありません(特に、sharememというディレクトリの中に.xmlというファイルがあることを期待している場合)。

このコミットの修正は、strings.TrimRight(abspath, "/") を導入することで、この問題を解決しています。loadCodewalk関数を呼び出す前に、abspathの末尾からスラッシュを確実に削除することで、常に sharemem.xml のような正しいファイルパスが生成されるようになります。これにより、openシステムコールが正しいファイル名で実行され、コードウォークのXMLファイルが正常にロードされるようになります。

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

--- a/src/cmd/godoc/codewalk.go
+++ b/src/cmd/godoc/codewalk.go
@@ -53,7 +53,9 @@ func codewalk(w http.ResponseWriter, r *http.Request) {
 	}\n \n 	// Otherwise append .xml and hope to find\n-\t// a codewalk description.\n+\t// a codewalk description, but before trim
+\t// the trailing /.\n+\tabspath = strings.TrimRight(abspath, \"/\")\n \tcw, err := loadCodewalk(abspath + \".xml\")\n \tif err != nil {\n \t\tlog.Print(err)\n```

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

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

元のコードでは、コメント`// Otherwise append .xml and hope to find // a codewalk description.`の後に、直接`abspath + ".xml"`としてファイルパスを構築し、`loadCodewalk`関数に渡していました。

修正後のコードでは、以下の2行が追加されています。

1.  `// a codewalk description, but before trim // the trailing /.`
    これは新しいコメントで、次に続くコードが何をするのかを説明しています。「コードウォークの記述を見つけるために.xmlを付加するが、その前に末尾のスラッシュをトリムする」という意図が明確に示されています。

2.  `abspath = strings.TrimRight(abspath, "/")`
    この行がこのコミットの核心です。`abspath`変数(これはHTTPリクエストパスから導出されたファイルシステムの絶対パス)の末尾から、すべてのスラッシュ (`/`) を削除します。例えば、`"/Users/francisco.souza/lib/go/doc/codewalk/sharemem/"`という`abspath`は、この行の実行後には`"/Users/francisco.souza/lib/go/doc/codewalk/sharemem"`となります。

この変更により、その後の`loadCodewalk(abspath + ".xml")`の呼び出しでは、常にスラッシュが取り除かれたクリーンなパスに`.xml`が追加されるため、`sharemem.xml`のような正しいファイル名が生成され、ファイルが見つからないエラーが解消されます。

## 関連リンク

- Go言語公式ドキュメント: [https://go.dev/doc/](https://go.dev/doc/)
- `godoc`コマンドについて: [https://go.dev/cmd/godoc/](https://go.dev/cmd/godoc/)
- Go Code Walkの例: [https://go.dev/doc/codewalk/sharemem/](https://go.dev/doc/codewalk/sharemem/) (このコミットで修正された問題の例として挙げられたコードウォーク)
- `strings`パッケージのドキュメント: [https://pkg.go.dev/strings](https://pkg.go.dev/strings)

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

- 上記のGitHubコミットページ
- Go言語の公式ドキュメントおよび`godoc`のソースコード
- `strings.TrimRight`関数のGo標準ライブラリドキュメント
- 一般的なHTTPリクエストパスの処理に関する知識
- ファイルシステムにおけるパスの命名規則に関する知識
- Go Code Review Comments (CL 5797065): [https://golang.org/cl/5797065](https://golang.org/cl/5797065) (コミットメッセージに記載されている変更リストへのリンク)