[インデックス 10243] ファイルの概要
このコミットは、Go言語の標準ライブラリである net/http
パッケージ内の Request
構造体のドキュメントを明確化することを目的としています。特に、Request
構造体の各フィールド(ContentLength
、TransferEncoding
、Close
、Form
、MultipartForm
、Trailer
、RemoteAddr
、TLS
)に関する説明が、より詳細かつ正確になるように修正されています。これにより、http.Request
がサーバーによって受信されたリクエストとクライアントによって送信されるリクエストの両方を表すことが明確にされ、各フィールドがサーバー側とクライアント側でどのように扱われるかについての情報が追加されています。
コミット
commit 3b901f4515a20c76ea3b120d3c9b1877263a72da
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Thu Nov 3 20:05:13 2011 -0700
http: clarify Request docs
R=rsc
CC=golang-dev
https://golang.org/cl/5342041
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/3b901f4515a20c76ea3b120d3c9b1877263a72da
元コミット内容
このコミットの元の内容は、http.Request
のドキュメントを明確にすることです。具体的には、Request
構造体がサーバーが受信するHTTPリクエストとクライアントが送信するHTTPリクエストの両方を表すことを明記し、いくつかのフィールドの振る舞いについて、クライアント側とサーバー側での違いを説明する記述が追加されています。
変更の背景
Go言語の net/http
パッケージは、HTTPクライアントとサーバーの両方を実装するための基盤を提供します。http.Request
構造体は、これらの両方のコンテキストで使用されます。しかし、初期のドキュメントでは、Request
構造体が「パースされたHTTPリクエストヘッダー」とだけ記述されており、これがサーバー側での利用に限定されるかのような誤解を招く可能性がありました。また、ContentLength
や TransferEncoding
といった特定のフィールドが、クライアントがリクエストを送信する際とサーバーがリクエストを受信する際で、どのように解釈され、使用されるかについての詳細が不足していました。
このコミットは、これらの曖昧さを解消し、http.Request
構造体のドキュメントをより包括的で正確なものにすることを目的としています。特に、クライアントがリクエストを構築する際の ContentLength
の扱い、TransferEncoding
の自動処理、そして Form
、MultipartForm
、RemoteAddr
、TLS
といったフィールドがHTTPクライアントによって無視されることなどを明記することで、開発者が http.Request
をより適切に利用できるようになります。
前提知識の解説
HTTPリクエストの基本
HTTP (Hypertext Transfer Protocol) は、Web上でデータを交換するためのプロトコルです。クライアント(Webブラウザなど)がサーバーにリクエストを送信し、サーバーがレスポンスを返します。HTTPリクエストは、以下の主要な要素で構成されます。
- メソッド (Method): リクエストの目的を示します(例: GET, POST, PUT, DELETE)。
- URL (Uniform Resource Locator): リクエストの対象となるリソースの場所を示します。
- ヘッダー (Headers): リクエストに関する追加情報を提供します(例:
Content-Type
,User-Agent
,Accept
)。 - ボディ (Body): POSTやPUTリクエストなどで、サーバーに送信されるデータが含まれます。
Go言語の net/http
パッケージ
Go言語の標準ライブラリである net/http
パッケージは、HTTPクライアントとサーバーを簡単に構築するための強力な機能を提供します。
http.Request
構造体: HTTPリクエストを表す構造体です。メソッド、URL、ヘッダー、ボディなどのリクエストのすべての側面をカプセル化します。サーバーが受信したリクエストを処理する際にも、クライアントが送信するリクエストを構築する際にも使用されます。http.Response
構造体: HTTPレスポンスを表す構造体です。http.Handler
インターフェース: HTTPリクエストを処理するためのインターフェースです。サーバー側でリクエストをルーティングし、ビジネスロジックを実行するために使用されます。http.Client
構造体: HTTPリクエストを送信するためのクライアントです。
http.Request
構造体の主要フィールド
Method
: HTTPメソッド(例: "GET", "POST")。URL
: リクエストのURLを表す*url.URL
型のポインタ。Header
: リクエストヘッダーを表すhttp.Header
型のマップ。Body
: リクエストボディを表すio.ReadCloser
インターフェース。ContentLength
: リクエストボディの長さ(バイト単位)。-1は長さが不明であることを示します。TransferEncoding
: 転送エンコーディングのリスト(例: "chunked")。Close
: リクエスト処理後にコネクションを閉じるべきかどうかを示すブール値。Host
: リクエストの対象となるホスト名。Form
: URLエンコードされたフォームデータ(application/x-www-form-urlencoded
)やクエリパラメータをパースした結果。ParseForm
メソッドを呼び出すことで利用可能になります。MultipartForm
: マルチパートフォームデータ(multipart/form-data
)をパースした結果。ファイルアップロードなどが含まれます。ParseMultipartForm
メソッドを呼び出すことで利用可能になります。Trailer
: トレーラーヘッダー(HTTP/1.1のチャンク転送エンコーディングの最後に送信されるヘッダー)。RemoteAddr
: クライアントのネットワークアドレス(IPアドレスとポート番号)。サーバー側で設定されます。TLS
: TLS接続の状態を表す*tls.ConnectionState
型のポインタ。サーバー側でTLS接続の場合に設定されます。
技術的詳細
このコミットは、http.Request
構造体のコメントを修正することで、そのセマンティクスをより正確に定義しています。特に重要な変更点は以下の通りです。
-
Request
構造体の定義の明確化:- 変更前:
// A Request represents a parsed HTTP request header.
- 変更後:
// A Request represents an HTTP request received by a server // or to be sent by a client.
この変更により、http.Request
がサーバーが受信するリクエストだけでなく、クライアントが送信するリクエストも表すことが明確になりました。これは、net/http
パッケージがクライアントとサーバーの両方の機能を提供するため、非常に重要な明確化です。
- 変更前:
-
ContentLength
フィールドの明確化:- 変更前:
// Values >= 0 indicate that the given number of bytes may be read from Body.
- 変更後:
// Values >= 0 indicate that the given number of bytes may // be read from Body. // For outgoing requests, a value of 0 means unknown if Body is not nil.
クライアントがリクエストを送信する際、Body
がnil
でないにもかかわらずContentLength
が0
の場合、その長さは不明として扱われることが明記されました。これは、クライアントがストリーミングでボディを送信する場合などに重要です。
- 変更前:
-
TransferEncoding
フィールドの明確化:- 変更前:
// TransferEncoding lists the transfer encodings from outermost to innermost. // An empty list denotes the "identity" encoding.
- 変更後:
// TransferEncoding lists the transfer encodings from outermost to // innermost. An empty list denotes the "identity" encoding. // TransferEncoding can usually be ignored; chunked encoding is // automatically added and removed as necessary when sending and // receiving requests.
TransferEncoding
は通常無視できること、そしてチャンクエンコーディングはリクエストの送受信時に自動的に追加・削除されることが追記されました。これにより、開発者がこのフィールドを直接操作する必要がないことが示唆されています。
- 変更前:
-
Close
フィールドの明確化:- 変更前:
// Whether to close the connection after replying to this request.
- 変更後:
// Close indicates whether to close the connection after // replying to this request.
コメントの表現がより自然な英語に修正されました。
- 変更前:
-
Form
およびMultipartForm
フィールドの明確化:- 変更前:
// The parsed form. Only available after ParseForm is called.
- 変更後:
// Form contains the parsed form data, including both the URL // field's query parameters and the POST or PUT form data. // This field is only available after ParseForm is called. // The HTTP client ignores Form and uses Body instead.
- 変更前:
// The parsed multipart form, including file uploads. // Only available after ParseMultipartForm is called.
- 変更後:
// MultipartForm is the parsed multipart form, including file uploads. // This field is only available after ParseMultipartForm is called. // The HTTP client ignores MultipartForm and uses Body instead.
これらのフィールドが、HTTPクライアントによって無視され、代わりにBody
が使用されることが明記されました。これは、クライアントがリクエストを送信する際に、これらのフィールドに値を設定しても効果がないことを意味します。これらのフィールドは、主にサーバーが受信したリクエストをパースする際に使用されます。
- 変更前:
-
Trailer
フィールドの明確化:- 変更前: (なし)
- 変更後:
// Trailer support is only partially complete.
Trailer
フィールドのサポートが部分的にしか完了していないことが追記されました。これは、この機能がまだ完全に安定していないか、すべてのエッジケースをカバーしていない可能性があることを示唆しています。
-
RemoteAddr
およびTLS
フィールドの明確化:- 変更前: (なし)
- 変更後:
// This field is ignored by the HTTP client.
(両フィールドに追加) これらのフィールドがHTTPクライアントによって無視されることが明記されました。RemoteAddr
はサーバーがクライアントの接続元アドレスを記録するために使用され、TLS
はサーバーがTLS接続の状態を記録するために使用されるため、クライアントがリクエストを送信する際には関連性がありません。
これらの変更は、http.Request
構造体の各フィールドの役割と、それがクライアントとサーバーのどちらのコンテキストで意味を持つのかを明確にすることで、GoのHTTPプログラミングにおける一般的な混乱を解消し、より堅牢なコードの記述を促進します。
コアとなるコードの変更箇所
変更は src/pkg/net/http/request.go
ファイルに集中しており、主に Request
構造体のフィールドに対するコメントの修正と追加が行われています。
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -69,7 +69,8 @@ var reqWriteExcludeHeader = map[string]bool{\
"Trailer": true,\
}\
\
-// A Request represents a parsed HTTP request header.\
+// A Request represents an HTTP request received by a server\
+// or to be sent by a client.\
type Request struct {\
Method string // GET, POST, PUT, etc.\
URL *url.URL\
@@ -106,14 +107,20 @@ type Request struct {\
\
// ContentLength records the length of the associated content.\
// The value -1 indicates that the length is unknown.\
-\t// Values >= 0 indicate that the given number of bytes may be read from Body.\
+\t// Values >= 0 indicate that the given number of bytes may\
+\t// be read from Body.\
+\t// For outgoing requests, a value of 0 means unknown if Body is not nil.\
\tContentLength int64\
\
-\t// TransferEncoding lists the transfer encodings from outermost to innermost.\
-\t// An empty list denotes the "identity" encoding.\
+\t// TransferEncoding lists the transfer encodings from outermost to\n+\t// innermost. An empty list denotes the "identity" encoding.\
+\t// TransferEncoding can usually be ignored; chunked encoding is\n+\t// automatically added and removed as necessary when sending and\n+\t// receiving requests.\
\tTransferEncoding []string\
\
-\t// Whether to close the connection after replying to this request.\
+\t// Close indicates whether to close the connection after\n+\t// replying to this request.\
\tClose bool\
\
\t// The host on which the URL is sought.\
@@ -121,16 +128,21 @@ type Request struct {\
\t// or the host name given in the URL itself.\
\tHost string\
\
-\t// The parsed form. Only available after ParseForm is called.\
+\t// Form contains the parsed form data, including both the URL\n+\t// field's query parameters and the POST or PUT form data.\
+\t// This field is only available after ParseForm is called.\
+\t// The HTTP client ignores Form and uses Body instead.\
\tForm url.Values\
\
-\t// The parsed multipart form, including file uploads.\
-\t// Only available after ParseMultipartForm is called.\
+\t// MultipartForm is the parsed multipart form, including file uploads.\
+\t// This field is only available after ParseMultipartForm is called.\
+\t// The HTTP client ignores MultipartForm and uses Body instead.\
\tMultipartForm *multipart.Form\
\
\t// Trailer maps trailer keys to values. Like for Header, if the\
\t// response has multiple trailer lines with the same key, they will be\
\t// concatenated, delimited by commas.\
+\t// Trailer support is only partially complete.\
\tTrailer Header\
\
\t// RemoteAddr allows HTTP servers and other software to record\
@@ -139,6 +141,7 @@ type Request struct {\
\t// has no defined format. The HTTP server in this package\
\t// sets RemoteAddr to an "IP:port" address before invoking a\
\t// handler.\
+\t// This field is ignored by the HTTP client.\
\tRemoteAddr string\
\
\t// TLS allows HTTP servers and other software to record\
@@ -147,6 +150,7 @@ type Request struct {\
\t// The HTTP server in this package sets the field for\
\t// TLS-enabled connections before invoking a handler;\
\t// otherwise it leaves the field nil.\
+\t// This field is ignored by the HTTP client.\
\tTLS *tls.ConnectionState\
}\
\
コアとなるコードの解説
このコミットは、Go言語の net/http
パッケージにおける Request
構造体のドキュメンテーションを改善するものです。コード自体に機能的な変更はなく、既存のフィールドの振る舞いを変更するものでもありません。代わりに、各フィールドのコメントがより詳細になり、特にHTTPクライアントとサーバーの両方のコンテキストでの Request
構造体の使用方法が明確化されています。
具体的には、以下の点が変更されています。
-
Request
構造体自体の説明:- 以前は「パースされたHTTPリクエストヘッダー」と説明されていましたが、このコミットにより「サーバーが受信するHTTPリクエスト、またはクライアントが送信するHTTPリクエスト」と明確に定義されました。これにより、
Request
構造体がクライアントとサーバーの両方で利用される汎用的な表現であることが強調されます。
- 以前は「パースされたHTTPリクエストヘッダー」と説明されていましたが、このコミットにより「サーバーが受信するHTTPリクエスト、またはクライアントが送信するHTTPリクエスト」と明確に定義されました。これにより、
-
ContentLength
フィールド:- 送信するリクエスト(クライアント側)において、
Body
がnil
でない場合にContentLength
が0
であれば、長さが不明であることを示すという注意書きが追加されました。これは、ストリーミングリクエストなどでボディの長さが事前にわからない場合に重要です。
- 送信するリクエスト(クライアント側)において、
-
TransferEncoding
フィールド:- このフィールドは通常無視できること、そしてチャンクエンコーディングはリクエストの送受信時に自動的に処理されることが追記されました。これにより、開発者がこの低レベルの詳細に通常は関与する必要がないことが示唆されます。
-
Form
およびMultipartForm
フィールド:- これらのフィールドは
ParseForm
やParseMultipartForm
が呼び出された後にのみ利用可能であることに加え、HTTPクライアントはこれらのフィールドを無視し、代わりにBody
を使用することが明記されました。これは、クライアントがリクエストを送信する際に、これらのフィールドに値を設定しても効果がないことを意味し、サーバー側でのリクエスト処理に特化したフィールドであることを明確にしています。
- これらのフィールドは
-
Trailer
フィールド:- トレーラーヘッダーのサポートが「部分的にしか完了していない」という注意書きが追加されました。これは、この機能がまだ完全に実装されていないか、安定していない可能性があることを示唆しています。
-
RemoteAddr
およびTLS
フィールド:- これらのフィールドがHTTPクライアントによって無視されることが明記されました。
RemoteAddr
はサーバーが接続元を識別するために、TLS
はサーバーがTLS接続の詳細を把握するために使用されるため、クライアントがリクエストを送信する際にはこれらのフィールドは関連性がありません。
- これらのフィールドがHTTPクライアントによって無視されることが明記されました。
これらのコメントの追加と修正は、net/http
パッケージのドキュメンテーションの品質を向上させ、開発者が http.Request
構造体をより正確に理解し、適切に使用できるようにすることを目的としています。
関連リンク
- Go言語の
net/http
パッケージのドキュメント: https://pkg.go.dev/net/http - Go言語の
url
パッケージのドキュメント: https://pkg.go.dev/net/url - Go言語の
crypto/tls
パッケージのドキュメント: https://pkg.go.dev/crypto/tls - このコミットのGo CL (Code Review) ページ: https://golang.org/cl/5342041
参考にした情報源リンク
- Go言語の公式ドキュメント
- HTTP/1.1 RFC (特にヘッダー、ボディ、転送エンコーディングに関するセクション)
- Go言語の
net/http
パッケージのソースコード - Go言語のコードレビュープロセスに関する情報 (Go CL)
- Go言語のGitHubリポジトリ