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

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

このコミットは、doc/go1.3.html ファイルにのみ変更を加えています。具体的には、net/http パッケージの TransportRequest.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 パッケージの TransportRequest.Body を閉じる動作の一貫性に関する重要な変更点を追記するものです。以前は成功時や特定のエラー時にのみ閉じられていた Request.Body が、エラー発生時でも常に閉じられるようになったことが明記されています。

変更の背景

この変更の背景には、net/http パッケージの Transport がHTTPリクエストのボディ (Request.Body) を処理する際の一貫性の欠如がありました。以前のバージョンでは、リクエストが成功した場合や、特定のエラーが発生した場合には Request.Body が閉じられていましたが、エラーの種類や発生タイミングによっては閉じられないケースが存在していました。

Request.Bodyio.ReadCloser インターフェースを実装しており、これは通常、リソース(この場合はHTTPリクエストのペイロード)を読み込んだ後に明示的に閉じる必要があることを示しています。リソースが閉じられないと、ファイルディスクリプタのリーク、メモリリーク、またはネットワーク接続の枯渇といった問題が発生する可能性があります。特に、HTTPクライアントが多数のリクエストを送信するようなシナリオでは、これらの問題が顕在化しやすくなります。

このコミットは、Go 1.3のリリースに向けて、net/http パッケージの堅牢性と信頼性を向上させるためのドキュメント上の修正です。実際のコード変更は、このドキュメントの追加よりも前のコミットで行われており、このコミットはその変更をユーザーに明確に伝えるためのものです。これにより、開発者は Request.Body のクローズに関して、より予測可能な挙動を期待できるようになります。

前提知識の解説

Go言語の net/http パッケージ

net/http パッケージは、Go言語でHTTPクライアントおよびサーバーを実装するための標準ライブラリです。このパッケージは、HTTPプロトコルの低レベルな詳細を抽象化し、開発者が簡単にWebアプリケーションやHTTPクライアントを構築できるようにします。

http.RequestRequest.Body

http.Request 構造体は、HTTPリクエストを表します。これには、メソッド(GET, POSTなど)、URL、ヘッダー、そしてリクエストボディが含まれます。 Request.Bodyio.ReadCloser 型であり、これは io.Readerio.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 パッケージの TransportRequest.Body を処理する際の内部的な挙動に関するものです。

以前のGoバージョンでは、TransportRequest.Body を閉じるタイミングについて一貫性がありませんでした。具体的には、以下のような状況が考えられます。

  1. 成功時のクローズ: リクエストが正常に送信され、レスポンスが受信された場合、TransportRequest.Body を閉じていました。これは期待される動作です。
  2. 一部のエラー時のクローズ: ネットワークエラーやプロトコルエラーなど、特定の種類のエラーが発生した場合にも TransportRequest.Body を閉じるロジックを持っていました。
  3. エラー時のクローズの欠如: しかし、すべてではないエラーパスにおいて Request.Body が閉じられないケースが存在していました。例えば、リクエストの送信中にタイムアウトが発生した場合や、予期せぬ接続切断が発生した場合など、特定のタイミングやエラーの種類によっては Close() メソッドが呼び出されないことがありました。この「タイミングに依存する」という記述は、競合状態や特定の実行パスでのみ問題が顕在化することを示唆しています。

このような一貫性のない挙動は、開発者にとって予測が難しく、アプリケーションにリソースリークを引き起こす可能性がありました。特に、Request.Body が大きなデータストリームである場合や、カスタムの io.ReadCloser 実装を使用している場合には、この問題はより深刻になります。

Go 1.3での変更(このドキュメントが言及している実際のコード変更)により、TransportRequest.Body を「常に」閉じるようになりました。これは、リクエストの処理が成功したかどうかにかかわらず、またどのような種類のエラーが発生したとしても、TransportRequest.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.: これがこの変更の核心です。TransportRequest.Body を「一貫して」、つまり「エラー時でも」閉じるようになったことを述べています。これは、以前のバージョンではエラー時に閉じられないケースがあったことへの改善を意味します。
  • Previously it was closed on success and closed on some errors, sometimes depending on timing.: 以前の挙動を説明しています。成功時には閉じられていたが、一部のエラー時のみ閉じられ、その挙動が「タイミングに依存する」ことがあった、と指摘しています。この「タイミングに依存する」という記述は、競合状態や特定の実行パスでのみ問題が顕在化していた可能性を示唆しており、デバッグが困難であったことを示唆しています。

このドキュメントの追加により、Go 1.3を使用する開発者は、net/http.TransportRequest.Body のクローズをより確実に処理するようになったことを認識し、リソースリークのリスクを低減できるようになります。

関連リンク

参考にした情報源リンク