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

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

このコミットは、Go言語の net/http パッケージにおいて、HTTP 204 (No Content) レスポンスに Content-Type ヘッダーを含めることを許可する変更です。以前の Content-Length に関する修正(Issue 6685に関連)によって意図せず Content-Type ヘッダーが抑制されるようになっていた問題を修正します。

コミット

net/http: allow Content-Type on 204 responses

Accidental change from fixing Content-Length on 204s
in http://golang.org/issue/6685 earlier.

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/92400047

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

https://github.com/golang/go/commit/4c8de36e2bb01af620cc2b32d2dba806e9f07f9b

元コミット内容

commit 4c8de36e2bb01af620cc2b32d2dba806e9f07f9b
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Fri May 16 15:39:59 2014 -0700

    net/http: allow Content-Type on 204 responses
    
    Accidental change from fixing Content-Length on 204s
    in http://golang.org/issue/6685 earlier.
    
    LGTM=rsc
    R=rsc
    CC=golang-codereviews
    https://golang.org/cl/92400047

変更の背景

この変更は、Goの net/http パッケージにおける以前の修正に起因する意図しない副作用を是正するために行われました。具体的には、HTTP 204 (No Content) レスポンスにおける Content-Length ヘッダーの取り扱いを修正する過程で(これは http://golang.org/issue/6685 に関連する作業でした)、誤って Content-Type ヘッダーも抑制されるようになってしまいました。

HTTP 204 レスポンスは、リクエストが正常に処理されたものの、レスポンスボディにコンテンツが含まれないことを示します。このようなレスポンスでは Content-LengthTransfer-Encoding といったボディに関連するヘッダーは通常抑制されますが、Content-Type ヘッダーは必ずしも抑制されるべきではありません。例えば、クライアントが特定の Content-Type を期待している場合や、APIの設計上、メタデータとして Content-Type を含めることが有用な場合があります。

RFC 2616などのHTTP仕様では、HTTP 304 (Not Modified) レスポンスに対しては、Content-Type を含む「エンティティヘッダー」を厳しく抑制するよう規定されていますが、204 レスポンスに対してはそこまで厳格な規定はありません。このコミットは、この仕様のニュアンスを正しく反映し、204 レスポンスにおける Content-Type ヘッダーの不必要な抑制を解除することを目的としています。

前提知識の解説

HTTP ステータスコード 204 (No Content)

HTTP 204 "No Content" は、サーバーがリクエストを正常に処理したが、レスポンスボディとしてコンテンツを返さないことを示すステータスコードです。例えば、リソースの更新リクエストが成功したが、クライアントに新しいデータを返す必要がない場合などに使用されます。204 レスポンスにはメッセージボディが含まれないため、Content-LengthTransfer-Encoding といったボディの長さを指定するヘッダーは通常含まれません。

HTTP ステータスコード 304 (Not Modified)

HTTP 304 "Not Modified" は、クライアントが条件付きGETリクエスト(例: If-Modified-SinceIf-None-Match ヘッダーを使用)を送信し、リクエストされたリソースが変更されていない場合に返されるステータスコードです。この場合もレスポンスボディは含まれません。RFC 2616のセクション 10.3.5 では、304 レスポンスは Content-Type を含む「エンティティヘッダー」を送信してはならないと明確に規定されています。これは、クライアントがキャッシュされたリソースのヘッダーを使用することを意図しているためです。

HTTP ヘッダーの抑制

HTTPレスポンスにおいて、特定のステータスコード(特にボディを持たないもの)の場合、一部のヘッダーは送信されるべきではありません。

  • Content-Length: レスポンスボディの長さをバイト単位で示すヘッダー。ボディがない場合は不要。
  • Transfer-Encoding: メッセージボディに適用されたエンコーディング形式(例: chunked)を示すヘッダー。ボディがない場合は不要。
  • Content-Type: レスポンスボディのメディアタイプ(例: application/json, text/html)を示すヘッダー。ボディがない場合は、その必要性が状況によって異なります。304 の場合はRFCで抑制が義務付けられていますが、204 の場合はそうではありません。

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

net/http はGo言語の標準ライブラリで、HTTPクライアントとサーバーの実装を提供します。このパッケージは、HTTPリクエストの解析、レスポンスの生成、ヘッダーの管理など、HTTP通信の低レベルな詳細を抽象化します。サーバーサイドでは、ResponseWriter インターフェースを通じてレスポンスヘッダーの設定やボディの書き込みを行います。

技術的詳細

このコミットの技術的な核心は、Goの net/http パッケージがレスポンスヘッダーを処理するロジック、特にボディを持たないHTTPステータスコード(204や304など)に対するヘッダーの抑制方法の変更にあります。

以前の実装では、server.go 内の writeHeader 関数において、bodyAllowedForStatus(code)false を返す(つまり、そのステータスコードではボディが許可されない)場合、一律に Content-TypeContent-LengthTransfer-Encoding の各ヘッダーを削除していました。これは、HTTP 304 レスポンスの要件(RFC 2616 Section 10.3.5)を満たすためのものでしたが、HTTP 204 レスポンスに対しても同様に Content-Type を削除してしまうという副作用がありました。

このコミットでは、この一律の抑制ロジックを改善し、ステータスコードに応じて抑制するヘッダーをより細かく制御するように変更しました。

  1. suppressedHeaders 関数の導入: src/pkg/net/http/transfer.gosuppressedHeaders(status int) []string という新しい関数が導入されました。この関数は、与えられたHTTPステータスコードに基づいて、抑制すべきヘッダー名のスライスを返します。

    • status == 304 の場合: suppressedHeaders304 (定義は {"Content-Type", "Content-Length", "Transfer-Encoding"}) を返します。これはRFC 2616の規定に厳密に従います。
    • !bodyAllowedForStatus(status) (かつ304ではない) の場合: suppressedHeadersNoBody (定義は {"Content-Length", "Transfer-Encoding"}) を返します。これにより、204のようなボディを持たないが Content-Type の抑制が不要なステータスコードに対して、Content-Type ヘッダーが保持されるようになります。
    • それ以外の場合: nil を返し、ヘッダーの抑制は行いません。
  2. server.gowriteHeader の変更: src/pkg/net/http/server.go 内の writeHeader 関数が修正され、以前の一律削除ロジックが suppressedHeaders 関数を呼び出す形に置き換えられました。

    // 変更前:
    // if !bodyAllowedForStatus(code) {
    //     for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
    //         delHeader(k)
    //     }
    // } else { ... }
    
    // 変更後:
    // if bodyAllowedForStatus(code) {
    //     // ... (Content-Type sniffing logic)
    // } else {
    //     for _, k := range suppressedHeaders(code) {
    //         delHeader(k)
    //     }
    // }
    

    この変更により、bodyAllowedForStatus(code)false の場合でも、Content-TypesuppressedHeaders によって抑制されない限り、レスポンスヘッダーに残るようになります。

  3. テストケースの追加: src/pkg/net/http/serve_test.goTestContentTypeOkayOn204 という新しいテストケースが追加されました。このテストは、HTTP 204 レスポンスに対して Content-Type ヘッダーが正しく含まれ、Content-Length ヘッダーが抑制されることを検証します。これにより、意図した動作が保証されます。

この変更は、HTTP仕様の解釈をより正確に反映し、Goの net/http パッケージの堅牢性と柔軟性を向上させるものです。

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

  • src/pkg/net/http/serve_test.go:
    • TestContentTypeOkayOn204 という新しいテスト関数が追加されました。このテストは、204 レスポンスで Content-Type ヘッダーが設定され、Content-Length ヘッダーが抑制されることを確認します。
  • src/pkg/net/http/server.go:
    • writeHeader 関数内のヘッダー抑制ロジックが変更されました。以前は bodyAllowedForStatus に基づいて一律に Content-Type などが削除されていましたが、新しい suppressedHeaders 関数を使用して、ステータスコードに応じた適切なヘッダーのみを削除するように修正されました。
  • src/pkg/net/http/transfer.go:
    • suppressedHeaders304suppressedHeadersNoBody という2つの文字列スライス変数が追加されました。これらはそれぞれ、304 レスポンスとボディを持たない他のレスポンス(204など)で抑制されるべきヘッダーのリストを定義します。
    • suppressedHeaders(status int) []string という新しい関数が追加されました。この関数は、与えられたステータスコードに基づいて、どのヘッダーを抑制すべきかを決定し、対応するヘッダー名のスライスを返します。

コアとなるコードの解説

  • src/pkg/net/http/serve_test.go の変更: TestContentTypeOkayOn204 テストは、このコミットが修正しようとしている問題を直接検証します。ハンドラ内で Content-LengthContent-Type を設定し、204 ステータスコードを返します。その後、レスポンスを解析し、Content-Type が存在し、Content-Length が存在しないことをアサートします。これにより、変更が正しく機能していることが保証されます。

  • src/pkg/net/http/server.go の変更: writeHeader 関数は、HTTPレスポンスのヘッダーを実際に書き込むGoのHTTPサーバーの中核部分です。この変更により、ヘッダーの抑制ロジックがより洗練され、HTTP仕様のニュアンス(特に304と204の違い)を正確に反映するようになりました。以前は Content-Type が不必要に削除されていましたが、この修正により、204 レスポンスでは Content-Type が保持されるようになります。

  • src/pkg/net/http/transfer.go の変更: suppressedHeaders 関数は、ヘッダー抑制のポリシーをカプセル化します。これにより、server.gowriteHeader 関数は、どのヘッダーを削除すべきかという詳細なロジックから解放され、よりクリーンなコードになります。suppressedHeaders304suppressedHeadersNoBody の導入は、異なるステータスコードに対する異なるヘッダー抑制ルールを明確に定義し、コードの可読性と保守性を向上させます。

これらの変更は全体として、Goの net/http パッケージがHTTP仕様に準拠しつつ、より柔軟なヘッダー処理を可能にすることを目指しています。

関連リンク

  • Go Change List (CL) for this commit: https://golang.org/cl/92400047
  • 関連する以前のIssue (Issue 6685): このコミットメッセージで参照されていますが、直接的なGoのIssueトラッカー上のリンクは見つかりませんでした。しかし、Content-Length の修正に関連するものであったことが示唆されています。

参考にした情報源リンク

  • RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1, Section 10.3.5 304 Not Modified: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
  • HTTP 204 No Content Status Code: 一般的なHTTP仕様に関する情報源 (例: MDN Web Docsなど)
  • Go言語の net/http パッケージのドキュメント (Go公式ドキュメント)
  • Web検索結果: "HTTP 204 response Content-Type", "golang issue 6685"```markdown

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

このコミットは、Go言語の net/http パッケージにおいて、HTTP 204 (No Content) レスポンスに Content-Type ヘッダーを含めることを許可する変更です。以前の Content-Length に関する修正(Issue 6685に関連)によって意図せず Content-Type ヘッダーが抑制されるようになっていた問題を修正します。

コミット

net/http: allow Content-Type on 204 responses

Accidental change from fixing Content-Length on 204s
in http://golang.org/issue/6685 earlier.

LGTM=rsc
R=rsc
CC=golang-codereviews
https://golang.org/cl/92400047

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

https://github.com/golang/go/commit/4c8de36e2bb01af620cc2b32d2dba806e9f07f9b

元コミット内容

commit 4c8de36e2bb01af620cc2b32d2dba806e9f07f9b
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date:   Fri May 16 15:39:59 2014 -0700

    net/http: allow Content-Type on 204 responses
    
    Accidental change from fixing Content-Length on 204s
    in http://golang.org/issue/6685 earlier.
    
    LGTM=rsc
    R=rsc
    CC=golang-codereviews
    https://golang.org/cl/92400047

変更の背景

この変更は、Goの net/http パッケージにおける以前の修正に起因する意図しない副作用を是正するために行われました。具体的には、HTTP 204 (No Content) レスポンスにおける Content-Length ヘッダーの取り扱いを修正する過程で(これは http://golang.org/issue/6685 に関連する作業でした)、誤って Content-Type ヘッダーも抑制されるようになってしまいました。

HTTP 204 レスポンスは、リクエストが正常に処理されたものの、レスポンスボディにコンテンツが含まれないことを示します。このようなレスポンスでは Content-LengthTransfer-Encoding といったボディに関連するヘッダーは通常抑制されますが、Content-Type ヘッダーは必ずしも抑制されるべきではありません。例えば、クライアントが特定の Content-Type を期待している場合や、APIの設計上、メタデータとして Content-Type を含めることが有用な場合があります。

RFC 2616などのHTTP仕様では、HTTP 304 (Not Modified) レスポンスに対しては、Content-Type を含む「エンティティヘッダー」を厳しく抑制するよう規定されていますが、204 レスポンスに対してはそこまで厳格な規定はありません。このコミットは、この仕様のニュアンスを正しく反映し、204 レスポンスにおける Content-Type ヘッダーの不必要な抑制を解除することを目的としています。

前提知識の解説

HTTP ステータスコード 204 (No Content)

HTTP 204 "No Content" は、サーバーがリクエストを正常に処理したが、レスポンスボディとしてコンテンツを返さないことを示すステータスコードです。例えば、リソースの更新リクエストが成功したが、クライアントに新しいデータを返す必要がない場合などに使用されます。204 レスポンスにはメッセージボディが含まれないため、Content-LengthTransfer-Encoding といったボディの長さを指定するヘッダーは通常含まれません。

HTTP ステータスコード 304 (Not Modified)

HTTP 304 "Not Modified" は、クライアントが条件付きGETリクエスト(例: If-Modified-SinceIf-None-Match ヘッダーを使用)を送信し、リクエストされたリソースが変更されていない場合に返されるステータスコードです。この場合もレスポンスボディは含まれません。RFC 2616のセクション 10.3.5 では、304 レスポンスは Content-Type を含む「エンティティヘッダー」を送信してはならないと明確に規定されています。これは、クライアントがキャッシュされたリソースのヘッダーを使用することを意図しているためです。

HTTP ヘッダーの抑制

HTTPレスポンスにおいて、特定のステータスコード(特にボディを持たないもの)の場合、一部のヘッダーは送信されるべきではありません。

  • Content-Length: レスポンスボディの長さをバイト単位で示すヘッダー。ボディがない場合は不要。
  • Transfer-Encoding: メッセージボディに適用されたエンコーディング形式(例: chunked)を示すヘッダー。ボディがない場合は不要。
  • Content-Type: レスポンスボディのメディアタイプ(例: application/json, text/html)を示すヘッダー。ボディがない場合は、その必要性が状況によって異なります。304 の場合はRFCで抑制が義務付けられていますが、204 の場合はそうではありません。

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

net/http はGo言語の標準ライブラリで、HTTPクライアントとサーバーの実装を提供します。このパッケージは、HTTPリクエストの解析、レスポンスの生成、ヘッダーの管理など、HTTP通信の低レベルな詳細を抽象化します。サーバーサイドでは、ResponseWriter インターフェースを通じてレスポンスヘッダーの設定やボディの書き込みを行います。

技術的詳細

このコミットの技術的な核心は、Goの net/http パッケージがレスポンスヘッダーを処理するロジック、特にボディを持たないHTTPステータスコード(204や304など)に対するヘッダーの抑制方法の変更にあります。

以前の実装では、server.go 内の writeHeader 関数において、bodyAllowedForStatus(code)false を返す(つまり、そのステータスコードではボディが許可されない)場合、一律に Content-TypeContent-LengthTransfer-Encoding の各ヘッダーを削除していました。これは、HTTP 304 レスポンスの要件(RFC 2616 Section 10.3.5)を満たすためのものでしたが、HTTP 204 レスポンスに対しても同様に Content-Type を削除してしまうという副作用がありました。

このコミットでは、この一律の抑制ロジックを改善し、ステータスコードに応じて抑制するヘッダーをより細かく制御するように変更しました。

  1. suppressedHeaders 関数の導入: src/pkg/net/http/transfer.gosuppressedHeaders(status int) []string という新しい関数が導入されました。この関数は、与えられたHTTPステータスコードに基づいて、抑制すべきヘッダー名のスライスを返します。

    • status == 304 の場合: suppressedHeaders304 (定義は {"Content-Type", "Content-Length", "Transfer-Encoding"}) を返します。これはRFC 2616の規定に厳密に従います。
    • !bodyAllowedForStatus(status) (かつ304ではない) の場合: suppressedHeadersNoBody (定義は {"Content-Length", "Transfer-Encoding"}) を返します。これにより、204のようなボディを持たないが Content-Type の抑制が不要なステータスコードに対して、Content-Type ヘッダーが保持されるようになります。
    • それ以外の場合: nil を返し、ヘッダーの抑制は行いません。
  2. server.gowriteHeader の変更: src/pkg/net/http/server.go 内の writeHeader 関数が修正され、以前の一律削除ロジックが suppressedHeaders 関数を呼び出す形に置き換えられました。

    // 変更前:
    // if !bodyAllowedForStatus(code) {
    //     for _, k := range []string{"Content-Type", "Content-Length", "Transfer-Encoding"} {
    //         delHeader(k)
    //     }
    // } else { ... }
    
    // 変更後:
    // if bodyAllowedForStatus(code) {
    //     // ... (Content-Type sniffing logic)
    // } else {
    //     for _, k := range suppressedHeaders(code) {
    //         delHeader(k)
    //     }
    // }
    

    この変更により、bodyAllowedForStatus(code)false の場合でも、Content-TypesuppressedHeaders によって抑制されない限り、レスポンスヘッダーに残るようになります。

  3. テストケースの追加: src/pkg/net/http/serve_test.goTestContentTypeOkayOn204 という新しいテストケースが追加されました。このテストは、HTTP 204 レスポンスに対して Content-Type ヘッダーが正しく含まれ、Content-Length ヘッダーが抑制されることを検証します。これにより、意図した動作が保証されます。

この変更は、HTTP仕様の解釈をより正確に反映し、Goの net/http パッケージの堅牢性と柔軟性を向上させるものです。

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

  • src/pkg/net/http/serve_test.go:
    • TestContentTypeOkayOn204 という新しいテスト関数が追加されました。このテストは、204 レスポンスで Content-Type ヘッダーが設定され、Content-Length ヘッダーが抑制されることを確認します。
  • src/pkg/net/http/server.go:
    • writeHeader 関数内のヘッダー抑制ロジックが変更されました。以前は bodyAllowedForStatus に基づいて一律に Content-Type などが削除されていましたが、新しい suppressedHeaders 関数を使用して、ステータスコードに応じた適切なヘッダーのみを削除するように修正されました。
  • src/pkg/net/http/transfer.go:
    • suppressedHeaders304suppressedHeadersNoBody という2つの文字列スライス変数が追加されました。これらはそれぞれ、304 レスポンスとボディを持たない他のレスポンス(204など)で抑制されるべきヘッダーのリストを定義します。
    • suppressedHeaders(status int) []string という新しい関数が追加されました。この関数は、与えられたステータスコードに基づいて、どのヘッダーを抑制すべきかを決定し、対応するヘッダー名のスライスを返します。

コアとなるコードの解説

  • src/pkg/net/http/serve_test.go の変更: TestContentTypeOkayOn204 テストは、このコミットが修正しようとしている問題を直接検証します。ハンドラ内で Content-LengthContent-Type を設定し、204 ステータスコードを返します。その後、レスポンスを解析し、Content-Type が存在し、Content-Length が存在しないことをアサートします。これにより、変更が正しく機能していることが保証されます。

  • src/pkg/net/http/server.go の変更: writeHeader 関数は、HTTPレスポンスのヘッダーを実際に書き込むGoのHTTPサーバーの中核部分です。この変更により、ヘッダーの抑制ロジックがより洗練され、HTTP仕様のニュアンス(特に304と204の違い)を正確に反映するようになりました。以前は Content-Type が不必要に削除されていましたが、この修正により、204 レスポンスでは Content-Type が保持されるようになります。

  • src/pkg/net/http/transfer.go の変更: suppressedHeaders 関数は、ヘッダー抑制のポリシーをカプセル化します。これにより、server.gowriteHeader 関数は、どのヘッダーを削除すべきかという詳細なロジックから解放され、よりクリーンなコードになります。suppressedHeaders304suppressedHeadersNoBody の導入は、異なるステータスコードに対する異なるヘッダー抑制ルールを明確に定義し、コードの可読性と保守性を向上させます。

これらの変更は全体として、Goの net/http パッケージがHTTP仕様に準拠しつつ、より柔軟なヘッダー処理を可能にすることを目指しています。

関連リンク

  • Go Change List (CL) for this commit: https://golang.org/cl/92400047
  • 関連する以前のIssue (Issue 6685): このコミットメッセージで参照されていますが、直接的なGoのIssueトラッカー上のリンクは見つかりませんでした。しかし、Content-Length の修正に関連するものであったことが示唆されています。

参考にした情報源リンク

  • RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1, Section 10.3.5 304 Not Modified: https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
  • HTTP 204 No Content Status Code: 一般的なHTTP仕様に関する情報源 (例: MDN Web Docsなど)
  • Go言語の net/http パッケージのドキュメント (Go公式ドキュメント)
  • Web検索結果: "HTTP 204 response Content-Type", "golang issue 6685"