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

[インデックス 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 の修正が正しく機能していることを検証しています。

関連リンク

参考にした情報源リンク