[インデックス 19128] ファイルの概要
このコミットは、doc/go1.3.html
ファイルにのみ変更を加えています。具体的には、net/http
パッケージの Transport
が Request.Body
を閉じる動作に関するGo 1.3の変更点を説明する新しい項目が追加されています。
コミット
commit 071a0f4d18c5b5869bdcb6b0ca0e396cfa4506c6
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Mon Apr 14 10:19:10 2014 -0700
doc: add go1.3 note about the http Transport closing Request.Body
LGTM=rsc
R=rsc, r
CC=golang-codereviews
https://golang.org/cl/87620043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/071a0f4d18c5b5869bdcb6b0ca0e396cfa4506c6
元コミット内容
このコミットは、Go 1.3のリリースノートに、net/http
パッケージの Transport
が Request.Body
を閉じる動作の一貫性に関する重要な変更点を追記するものです。以前は成功時や特定のエラー時にのみ閉じられていた Request.Body
が、エラー発生時でも常に閉じられるようになったことが明記されています。
変更の背景
この変更の背景には、net/http
パッケージの Transport
がHTTPリクエストのボディ (Request.Body
) を処理する際の一貫性の欠如がありました。以前のバージョンでは、リクエストが成功した場合や、特定のエラーが発生した場合には Request.Body
が閉じられていましたが、エラーの種類や発生タイミングによっては閉じられないケースが存在していました。
Request.Body
は io.ReadCloser
インターフェースを実装しており、これは通常、リソース(この場合はHTTPリクエストのペイロード)を読み込んだ後に明示的に閉じる必要があることを示しています。リソースが閉じられないと、ファイルディスクリプタのリーク、メモリリーク、またはネットワーク接続の枯渇といった問題が発生する可能性があります。特に、HTTPクライアントが多数のリクエストを送信するようなシナリオでは、これらの問題が顕在化しやすくなります。
このコミットは、Go 1.3のリリースに向けて、net/http
パッケージの堅牢性と信頼性を向上させるためのドキュメント上の修正です。実際のコード変更は、このドキュメントの追加よりも前のコミットで行われており、このコミットはその変更をユーザーに明確に伝えるためのものです。これにより、開発者は Request.Body
のクローズに関して、より予測可能な挙動を期待できるようになります。
前提知識の解説
Go言語の net/http
パッケージ
net/http
パッケージは、Go言語でHTTPクライアントおよびサーバーを実装するための標準ライブラリです。このパッケージは、HTTPプロトコルの低レベルな詳細を抽象化し、開発者が簡単にWebアプリケーションやHTTPクライアントを構築できるようにします。
http.Request
と Request.Body
http.Request
構造体は、HTTPリクエストを表します。これには、メソッド(GET, POSTなど)、URL、ヘッダー、そしてリクエストボディが含まれます。
Request.Body
は io.ReadCloser
型であり、これは io.Reader
と io.Closer
の両方のインターフェースを満たすことを意味します。io.Reader
としては、リクエストのペイロード(例えばPOSTリクエストのデータ)を読み出すために使用されます。io.Closer
としては、リクエストボディの読み出しが完了した後、またはエラーが発生した場合に、関連するリソース(例えば基盤となるネットワーク接続やファイルディスクリプタ)を解放するために Close()
メソッドを呼び出す必要があります。
http.Transport
http.Transport
は、HTTPリクエストの実際の送信とHTTPレスポンスの受信を担当する構造体です。これには、TCP接続の確立、TLSハンドシェイク、HTTP/1.1またはHTTP/2プロトコルの処理、接続の再利用(Keep-Alive)などの低レベルなネットワーク操作が含まれます。http.Client
は内部的に http.Transport
を使用してリクエストを処理します。
リソースのクローズの重要性
プログラミングにおいて、ファイル、ネットワーク接続、メモリブロックなどのシステムリソースを使用する場合、それらが不要になったときに適切に解放(クローズ)することが非常に重要です。リソースを適切にクローズしないと、以下のような問題が発生する可能性があります。
- リソースリーク: 使用済みのリソースが解放されずに残り続け、システムのリソースが枯渇する。例えば、ファイルディスクリプタのリークは、新しいファイルを開けなくなる原因となります。
- メモリリーク: 不要になったメモリが解放されず、プログラムのメモリ使用量が増加し続ける。
- パフォーマンスの低下: リソースの枯渇により、新しい操作の開始が遅延したり、システム全体の応答性が低下したりする。
- デッドロック: 共有リソースが解放されないために、他の処理がそのリソースを待機し続け、プログラムが停止する。
Request.Body
の場合、基盤となるネットワーク接続やバッファが適切に閉じられないと、これらの問題が発生する可能性があります。
技術的詳細
このコミットが言及している技術的詳細は、net/http
パッケージの Transport
が Request.Body
を処理する際の内部的な挙動に関するものです。
以前のGoバージョンでは、Transport
は Request.Body
を閉じるタイミングについて一貫性がありませんでした。具体的には、以下のような状況が考えられます。
- 成功時のクローズ: リクエストが正常に送信され、レスポンスが受信された場合、
Transport
はRequest.Body
を閉じていました。これは期待される動作です。 - 一部のエラー時のクローズ: ネットワークエラーやプロトコルエラーなど、特定の種類のエラーが発生した場合にも
Transport
はRequest.Body
を閉じるロジックを持っていました。 - エラー時のクローズの欠如: しかし、すべてではないエラーパスにおいて
Request.Body
が閉じられないケースが存在していました。例えば、リクエストの送信中にタイムアウトが発生した場合や、予期せぬ接続切断が発生した場合など、特定のタイミングやエラーの種類によってはClose()
メソッドが呼び出されないことがありました。この「タイミングに依存する」という記述は、競合状態や特定の実行パスでのみ問題が顕在化することを示唆しています。
このような一貫性のない挙動は、開発者にとって予測が難しく、アプリケーションにリソースリークを引き起こす可能性がありました。特に、Request.Body
が大きなデータストリームである場合や、カスタムの io.ReadCloser
実装を使用している場合には、この問題はより深刻になります。
Go 1.3での変更(このドキュメントが言及している実際のコード変更)により、Transport
は Request.Body
を「常に」閉じるようになりました。これは、リクエストの処理が成功したかどうかにかかわらず、またどのような種類のエラーが発生したとしても、Transport
が Request.Body.Close()
を呼び出すことを保証するという意味です。これにより、開発者は Request.Body
のクローズに関して、Transport
にその責任を委ねることができ、自身で defer req.Body.Close()
のようなコードを記述する必要がなくなります(ただし、Response.Body
は依然としてユーザーが閉じる必要があります)。
この変更は、net/http
パッケージの堅牢性を高め、リソース管理のバグを減らすことに貢献します。
コアとなるコードの変更箇所
このコミットは、Goのリリースノートドキュメントである doc/go1.3.html
ファイルに以下のHTMLスニペットを追加しています。
--- a/doc/go1.3.html
+++ b/doc/go1.3.html
@@ -350,6 +350,14 @@ the <a href="/pkg/net/#Dialer"><code>Dialer</code></a> struct now
has a <code>KeepAlive</code> option to specify a keep-alive period for the connection.\n </li>\n \n+<li>\n+The <a href="/pkg/net/http/"><code>net/http</code></a> package\'s \n+<a href="/pkg/net/http/#Transport"><code>Transport</code></a>\n+now closes <a href="/pkg/net/http/#Request"><code>Request.Body</code></a>\n+consistently, even on errors. Previously it was closed on success and\n+closed on some errors, sometimes depending on timing.\n+</li>\n+\n <li> TODO: net: enable fast socket creation using SOCK_CLOEXEC and Accept4 on FreeBSD 10 (69100043)</li>
具体的には、<li>
タグで囲まれた新しいリスト項目が追加されています。
コアとなるコードの解説
追加されたHTMLスニペットは、Go 1.3のリリースノートの一部として、net/http
パッケージに関する重要な変更点を説明しています。
The <a href="/pkg/net/http/"><code>net/http</code></a> package's
:net/http
パッケージに関する記述であることを示します。<a href="/pkg/net/http/#Transport"><code>Transport</code></a>
:net/http
パッケージ内のTransport
型に関する変更であることを明示しています。now closes <a href="/pkg/net/http/#Request"><code>Request.Body</code></a> consistently, even on errors.
: これがこの変更の核心です。Transport
がRequest.Body
を「一貫して」、つまり「エラー時でも」閉じるようになったことを述べています。これは、以前のバージョンではエラー時に閉じられないケースがあったことへの改善を意味します。Previously it was closed on success and closed on some errors, sometimes depending on timing.
: 以前の挙動を説明しています。成功時には閉じられていたが、一部のエラー時のみ閉じられ、その挙動が「タイミングに依存する」ことがあった、と指摘しています。この「タイミングに依存する」という記述は、競合状態や特定の実行パスでのみ問題が顕在化していた可能性を示唆しており、デバッグが困難であったことを示唆しています。
このドキュメントの追加により、Go 1.3を使用する開発者は、net/http.Transport
が Request.Body
のクローズをより確実に処理するようになったことを認識し、リソースリークのリスクを低減できるようになります。
関連リンク
- Go 1.3 Release Notes: https://golang.org/doc/go1.3 (このコミットで追加された内容が反映されているはずです)
- Go
net/http
パッケージドキュメント: https://golang.org/pkg/net/http/ - Go
io.ReadCloser
インターフェースドキュメント: https://golang.org/pkg/io/#ReadCloser
参考にした情報源リンク
- Go 1.3 Release Notes (公式ドキュメント): https://golang.org/doc/go1.3
- Go
net/http
パッケージのソースコードおよびドキュメント (Go公式): https://golang.org/pkg/net/http/ - Go
io
パッケージのソースコードおよびドキュメント (Go公式): https://golang.org/pkg/io/ - Goのコミット履歴 (GitHub): https://github.com/golang/go/commits/master
- Go Code Review (Gerrit): https://golang.org/cl/87620043 (コミットメッセージに記載されているGerritのリンク)
- 一般的なプログラミングにおけるリソース管理とリークに関する情報 (例: Stack Overflow, 各種技術ブログ)