[インデックス 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リポジトリ