[インデックス 18103] ファイルの概要
このコミットは、Go言語の標準ライブラリである net/http
パッケージにおける Content-Type
ヘッダーの解釈に関する挙動の修正を扱っています。具体的には、HTTPリクエストの Content-Type
ヘッダーが空の場合に、RFC 2616の規定に従い application/octet-stream
として扱われるように変更されました。
コミット
commit 57e27a879eea9ea4e11f07ecb76393434ff54d1e
Author: Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
Date: Fri Dec 20 11:49:42 2013 -0800
net/http: empty contenty-type treated as application/octet-stream
RFC 2616, section 7.2.1 - empty type SHOULD be treated as
application/octet-stream.
Fixes #6616.
R=golang-codereviews, gobot, bradfitz, josharian
CC=golang-codereviews
https://golang.org/cl/31810043
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/57e27a879eea9ea4e11f07ecb76393434ff54d1e
元コミット内容
net/http: empty contenty-type treated as application/octet-stream
RFC 2616, section 7.2.1 - empty type SHOULD be treated as application/octet-stream. Fixes #6616.
変更の背景
この変更の背景には、HTTP/1.1の仕様を定義するRFC 2616の規定への準拠があります。RFC 2616のセクション7.2.1「Content-Type」では、エンティティボディを持つメッセージにおいて Content-Type
ヘッダーフィールドが存在しない場合、受信者はそのメディアタイプを application/octet-stream
と見なすべきであると規定されています。
Goの net/http
パッケージは、HTTPプロトコルを扱うための基盤を提供しており、その正確な挙動はWebアプリケーションの相互運用性にとって非常に重要です。以前のGoの net/http
パッケージでは、Content-Type
ヘッダーが空文字列の場合に、このRFCの規定に従って application/octet-stream
として扱われていませんでした。これにより、特定のクライアントやサーバーとの間で予期せぬ挙動や互換性の問題が発生する可能性がありました。
具体的には、Go issue #6616で報告された問題がこのコミットによって修正されました。この問題は、Content-Type
ヘッダーが空の場合に parsePostForm
関数が正しく動作しないというものでした。この修正により、GoのHTTPクライアントおよびサーバーがより堅牢になり、RFCに厳密に準拠した動作をするようになりました。
前提知識の解説
HTTP Content-Type
ヘッダー
HTTP (Hypertext Transfer Protocol) は、Web上でデータを交換するためのプロトコルです。Content-Type
ヘッダーは、HTTPメッセージのエンティティボディに含まれるデータのメディアタイプ(MIMEタイプ)を示すために使用されます。これにより、受信側はデータの種類を識別し、適切に処理することができます。
例:
Content-Type: text/html
(HTMLドキュメント)Content-Type: application/json
(JSONデータ)Content-Type: image/jpeg
(JPEG画像)Content-Type: application/x-www-form-urlencoded
(HTMLフォームのデータ)Content-Type: multipart/form-data
(ファイルアップロードなど)
RFC 2616
RFC 2616は、HTTP/1.1プロトコルの主要な仕様を定義した文書です。Webの基盤となるプロトコルであり、Webサーバー、クライアント、プロキシなどがどのように通信すべきかを詳細に規定しています。このRFCは、HTTPヘッダー、メソッド、ステータスコード、メッセージ構造など、HTTPのあらゆる側面を網羅しています。
RFC 2616, Section 7.2.1 "Content-Type"
このセクションは、Content-Type
ヘッダーフィールドの役割と、それが存在しない場合のデフォルトの挙動について記述しています。重要な点は以下の通りです。
Any HTTP/1.1 message containing an entity-body SHOULD include a Content-Type header field defining the media type of that body. If and only if the media type is not given by a Content-Type header field, the recipient MAY attempt to guess the media type via inspection of its content and/or the name extension(s) of the URI used to identify the resource. If the media type remains unknown, the recipient SHOULD treat it as type "application/octet-stream".
要約すると、エンティティボディを持つHTTP/1.1メッセージは Content-Type
ヘッダーを含むべきですが、もし含まれていない場合、受信者はその内容を検査してメディアタイプを推測してもよいとされています。それでもメディアタイプが不明な場合は、application/octet-stream
として扱うべきであると明確に指示されています。
application/octet-stream
これは、MIMEタイプの一つで、「任意のバイナリデータ」を意味します。特定のアプリケーションで開かれるべきファイル形式が不明な場合や、汎用的なバイナリデータを送信する場合に用いられます。ブラウザがこのMIMEタイプを受け取ると、通常はファイルをダウンロードするダイアログを表示します。
Go言語の net/http
パッケージ
Go言語の net/http
パッケージは、HTTPクライアントとサーバーを実装するための強力な機能を提供します。このパッケージは、HTTPリクエストの解析、レスポンスの生成、ルーティング、ミドルウェアのサポートなど、Webアプリケーション開発に必要な多くの機能を含んでいます。
mime.ParseMediaType
Go言語の mime
パッケージは、MIMEメディアタイプを解析するための機能を提供します。mime.ParseMediaType
関数は、Content-Type
ヘッダーのような文字列を解析し、メディアタイプ(例: text/plain
)とパラメータ(例: charset=utf-8
)に分割します。
技術的詳細
このコミットは、net/http
パッケージ内の parsePostForm
関数に修正を加えています。parsePostForm
関数は、HTTPリクエストのボディからフォームデータを解析するために使用されます。この関数は、リクエストヘッダーから Content-Type
を取得し、それに基づいてボディの解析方法を決定します。
修正前は、r.Header.Get("Content-Type")
が空文字列を返した場合、その後の mime.ParseMediaType
関数に空文字列が渡され、これが予期せぬ挙動を引き起こす可能性がありました。RFC 2616の規定では、Content-Type
が指定されていない場合は application/octet-stream
と見なすべきであるため、このギャップを埋める必要がありました。
コミットによって追加されたコードは、Content-Type
ヘッダーの値が空文字列 (""
) であるかどうかをチェックします。もし空であれば、明示的に ct = "application/octet-stream"
と設定し、その後の処理がRFCの規定に従って行われるようにします。これにより、Content-Type
が空のリクエストボディも適切に処理され、互換性が向上します。
また、関連するテストファイル src/pkg/net/http/request_test.go
も更新され、空の Content-Type
ヘッダーが application/octet-stream
として正しく扱われることを検証するテストケースが追加されています。これにより、将来の回帰を防ぎ、修正の正当性を保証しています。
コアとなるコードの変更箇所
src/pkg/net/http/request.go
--- a/src/pkg/net/http/request.go
+++ b/src/pkg/net/http/request.go
@@ -673,6 +673,11 @@ func parsePostForm(r *Request) (vs url.Values, err error) {
return
}
ct := r.Header.Get("Content-Type")
+ // RFC 2616, section 7.2.1 - empty type
+ // SHOULD be treated as application/octet-stream
+ if ct == "" {
+ ct = "application/octet-stream"
+ }
ct, _, err = mime.ParseMediaType(ct)
switch {
case ct == "application/x-www-form-urlencoded":
src/pkg/net/http/request_test.go
--- a/src/pkg/net/http/request_test.go
+++ b/src/pkg/net/http/request_test.go
@@ -68,8 +68,9 @@ type parseContentTypeTest struct {
var parseContentTypeTests = []parseContentTypeTest{
{false, stringMap{"Content-Type": {"text/plain"}}},
- // Non-existent keys are not placed. The value nil is illegal.
- {true, stringMap{}},
+ // Empty content type is legal - shoult be treated as
+ // application/octet-stream (RFC 2616, section 7.2.1)
+ {false, stringMap{}},
{true, stringMap{"Content-Type": {"text/plain; boundary="}}},
{false, stringMap{"Content-Type": {"application/unknown"}}},
}
コアとなるコードの解説
src/pkg/net/http/request.go
の変更
parsePostForm
関数内で、まず r.Header.Get("Content-Type")
を呼び出して Content-Type
ヘッダーの値を取得し、ct
変数に格納しています。
追加されたコードブロックは以下の通りです。
// RFC 2616, section 7.2.1 - empty type
// SHOULD be treated as application/octet-stream
if ct == "" {
ct = "application/octet-stream"
}
この if
文は、取得した ct
が空文字列であるかどうかをチェックします。もし空であれば、RFC 2616の規定に従い、ct
の値を明示的に "application/octet-stream"
に設定しています。これにより、Content-Type
ヘッダーが欠落しているか空である場合に、後続の mime.ParseMediaType(ct)
および switch
文が application/octet-stream
として処理を進めることが保証されます。
src/pkg/net/http/request_test.go
の変更
テストケース parseContentTypeTests
に変更が加えられています。
元のコード:
// Non-existent keys are not placed. The value nil is illegal.
{true, stringMap{}},
このテストケースは、Content-Type
ヘッダーが全く存在しない(stringMap{}
)場合にエラー (true
) となることを期待していました。コメントは「存在しないキーは配置されない。nil値は不正である」と述べています。
変更後のコード:
// Empty content type is legal - shoult be treated as
// application/octet-stream (RFC 2616, section 7.2.1)
{false, stringMap{}},
このテストケースは、Content-Type
ヘッダーが全く存在しない(stringMap{}
)場合にエラーとならない (false
) ことを期待するように変更されました。新しいコメントは、RFC 2616のセクション7.2.1に従って、空の Content-Type
が合法であり、application/octet-stream
として扱われるべきであることを明確にしています。これにより、parsePostForm
の修正が正しく機能していることを検証しています。
関連リンク
- Go issue #6616: https://github.com/golang/go/issues/6616
- Go CL 31810043: https://golang.org/cl/31810043
参考にした情報源リンク
- RFC 2616 - Hypertext Transfer Protocol -- HTTP/1.1: https://www.w3.org/Protocols/rfc2616/rfc2616.html
- RFC 2616 Section 7.2.1 Content-Type: https://www.w3.org/Protocols/rfc2616/rfc2616-sec07.html#sec7.2.1
- MIME types (MDN Web Docs): https://developer.mozilla.org/ja/docs/Web/HTTP/Basics_of_HTTP/MIME_types
- Go net/http package documentation: https://pkg.go.dev/net/http
- Go mime package documentation: https://pkg.go.dev/mime