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

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

このコミットは、Go言語の net/http パッケージにおける (*Request).Write メソッドの振る舞いに関するドキュメントの追加です。具体的には、リクエストボディ (Body フィールド) がリクエスト送信後に閉じられることを明記しています。

コミット

commit 77fe6befb7852d58250c4ebe12d80d665f900829
Author: Shenghou Ma <minux.ma@gmail.com>
Date:   Tue Dec 10 23:35:50 2013 -0500

    net/http: document that body is closed after (*Request).Write.
    Fixes #6911.
    
    R=golang-dev, bradfitz
    CC=golang-dev
    https://golang.org/cl/38690043

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

https://github.com/golang/go/commit/77fe6befb7852d58250c4ebe12d80d665f900829

元コミット内容

net/http: document that body is closed after (*Request).Write.
Fixes #6911.

R=golang-dev, bradfitz
CC=golang-dev
https://golang.org/cl/38690043

変更の背景

このコミットの背景には、Go言語の net/http パッケージにおける http.RequestBody フィールドのライフサイクルに関する明確なドキュメントの不足がありました。特に、(*Request).Write メソッドがリクエストボディをどのように扱うかについて、開発者間で混乱が生じる可能性がありました。

http.RequestBody フィールドは io.ReadCloser インターフェースを満たす型であり、これはリクエストのペイロード(例えば、POSTリクエストのデータ)を表現します。Goの net/http パッケージでは、クライアントが http.Request を送信する際に、内部的に (*Request).Write メソッドが呼び出されます。このメソッドは、リクエストボディの内容をネットワークに書き込みます。

問題は、この Body がいつ、どのように閉じられるのかが明示されていなかった点にあります。もし Bodyio.Closer インターフェースを実装している場合、リソースリークを防ぐために適切に閉じられる必要があります。このコミットは、(*Request).Write がリクエスト送信後に Body を自動的に閉じるという既存の振る舞いを明示的にドキュメント化することで、この曖昧さを解消し、開発者がリソース管理についてより正確な理解を持てるようにすることを目的としています。

Fixes #6911 とあることから、このコミットはGoのIssueトラッカーで報告された、このドキュメントの不足に関する問題(Issue 6911)を解決するものです。

前提知識の解説

このコミットを理解するためには、以下のGo言語の基本的な概念と net/http パッケージの知識が必要です。

  1. io.Reader インターフェース: データを読み出すためのインターフェースで、Read(p []byte) (n int, err error) メソッドを持ちます。ファイル、ネットワーク接続、メモリ上のバッファなど、様々なデータソースからデータを読み出すために使用されます。

  2. io.Writer インターフェース: データを書き込むためのインターフェースで、Write(p []byte) (n int, err error) メソッドを持ちます。ファイル、ネットワーク接続、メモリ上のバッファなど、様々なデータシンクにデータを書き込むために使用されます。

  3. io.Closer インターフェース: リソースを閉じるためのインターフェースで、Close() error メソッドを持ちます。ファイルディスクリプタ、ネットワークソケットなどのシステムリソースを解放するために使用されます。リソースリークを防ぐために、使用後は必ず Close() を呼び出すことが推奨されます。Goでは defer ステートメントと組み合わせて使われることが多いです。

  4. io.ReadCloser インターフェース: io.Readerio.Closer の両方のインターフェースを組み合わせたものです。データを読み出すことができ、かつリソースを閉じることができるオブジェクトを表します。net/http パッケージの Request.BodyResponse.Body はこのインターフェースを実装しています。

  5. net/http パッケージ: Go言語の標準ライブラリで、HTTPクライアントとサーバーの実装を提供します。ウェブアプリケーションの構築やHTTPリクエストの送信に不可欠なパッケージです。

    • http.Request: HTTPリクエストを表す構造体です。メソッド(GET, POSTなど)、URL、ヘッダー、そしてリクエストボディ (Body フィールド) などの情報を含みます。
    • http.Response: HTTPレスポンスを表す構造体です。ステータスコード、ヘッダー、そしてレスポンスボディ (Body フィールド) などの情報を含みます。
  6. リクエストボディとレスポンスボディ: HTTP通信において、クライアントがサーバーにデータを送信する際(例: POSTリクエスト)にそのデータがリクエストボディに含まれます。サーバーがクライアントに応答する際、そのデータがレスポンスボディに含まれます。これらは通常、ストリームとして扱われ、io.Reader または io.ReadCloser として表現されます。

技術的詳細

このコミットは、net/http パッケージの Response 構造体の Write メソッドのドキュメントに、Body is closed after it is sent. という一文を追加するものです。

(*Response).Write メソッドは、http.Response 構造体の内容を io.Writer に書き出すために使用されます。これは主に、HTTPサーバーがクライアントに応答を送信する際に内部的に利用されるか、あるいはプロキシなどのミドルウェアでレスポンスを転送する際に使用されます。

ここで重要なのは、http.ResponseBody フィールドもまた io.ReadCloser であるという点です。この Write メソッドが呼び出されると、ResponseBody の内容が指定された io.Writer にコピーされます。このコピーが完了した後、もし Response.Bodyio.Closer インターフェースを実装していれば、その Close() メソッドが自動的に呼び出され、関連するリソースが解放されます。

この自動的な Close() の呼び出しは、特にHTTPクライアントがレスポンスを受け取った際に resp.Body.Close()defer する必要があるのと同様に、リソースリークを防ぐ上で非常に重要です。しかし、このコミットは Response.Write のドキュメントに追加されたものであり、Request.Write のドキュメントに追加されたものではありません。コミットメッセージのタイトルが net/http: document that body is closed after (*Request).Write. となっているため、一見すると矛盾しているように見えますが、これは response.go ファイル内の Response.Write メソッドのドキュメントに、Request.Write の文脈で Body が閉じられることについて言及していると解釈できます。

より正確に言えば、net/http パッケージの設計思想として、io.ReadCloser を持つ Body フィールドは、その内容が完全に読み取られたか、またはリクエスト/レスポンスの処理が完了した後に、関連するリソースが自動的に閉じられるべきであるという原則があります。このコミットは、その原則が (*Request).Write の文脈でも適用されることを明示的にドキュメント化することで、開発者が Request.Body を扱う際に Close() を手動で呼び出す必要がないことを明確にしています。これは、http.Client を使用してリクエストを送信する際に http.RequestBodyio.ReadCloser を渡した場合に、その Body が自動的に閉じられることを意味します。

このドキュメントの追加は、既存の動作を変更するものではなく、その動作を明確にすることで、開発者が不必要な Close() 呼び出しを行ったり、逆に Close() を呼び忘れてリソースリークを引き起こしたりするのを防ぐことを目的としています。

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

変更は src/pkg/net/http/response.go ファイルの1行の追加です。

--- a/src/pkg/net/http/response.go
+++ b/src/pkg/net/http/response.go
@@ -187,6 +187,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
 //  ContentLength
 //  Header, values for non-canonical keys will have unpredictable behavior
 //
+// Body is closed after it is sent.
 func (r *Response) Write(w io.Writer) error {
 
  	// Status line

コアとなるコードの解説

追加された行は以下の通りです。

// Body is closed after it is sent.

このコメントは、func (r *Response) Write(w io.Writer) error メソッドのドキュメントブロックに追加されました。このメソッドは http.Response の内容を io.Writer に書き出す役割を担います。

このコメントが追加されたことで、Response.Write メソッドが ResponseBody フィールドを処理した後、その Body が自動的に閉じられるという重要な情報が明示されました。これは、http.RequestWrite メソッド(クライアントがリクエストを送信する際に使用される)が Request.Body を閉じるのと同様の振る舞いを、Response.WriteResponse.Body に対して行うことを示唆しています。

このドキュメントの追加は、Goの net/http パッケージにおける io.ReadCloser の管理に関する一貫した原則を強調するものです。つまり、Body フィールドが io.Closer を実装している場合、その内容が完全に消費された後(この場合は Write メソッドによってネットワークに送信された後)、システムリソースを適切に解放するために自動的に閉じられるということです。これにより、開発者は Request.BodyResponse.Body を手動で閉じる必要がないことを理解し、リソースリークのリスクを軽減できます。

関連リンク

参考にした情報源リンク