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

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

このコミットは、Go言語の標準ライブラリであるnet/httpパッケージにおけるhttp.ResponseWriterインターフェースのWriteメソッドと、net/http/sniffパッケージのDetectContentType関数のドキュメントを改善するものです。具体的には、WriteメソッドがContent-Typeヘッダが設定されていない場合にDetectContentTypeを使用してコンテンツタイプを自動検出する挙動と、DetectContentType関数の動作(特にスニッフィングのバイト数と戻り値の保証)について、より明確な説明を追加しています。

コミット

commit d9da346078f4b2887c26c55cdd162b15bf8bfcc6
Author: Russ Cox <rsc@golang.org>
Date:   Sun Feb 12 23:14:48 2012 -0500

    net/http: document use of DetectContentType
    
    Fixes #2365.
    
    R=golang-dev, dsymonds
    CC=golang-dev
    https://golang.org/cl/5653070

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

https://github.com/golang/go/commit/d9da346078f4b2887c26c55cdd162b15bf8bfcc6

元コミット内容

net/http: document use of DetectContentType
    
Fixes #2365.
    
R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5653070

変更の背景

このコミットは、GoのIssue #2365を修正するために行われました。Issue #2365は、net/httpパッケージのhttp.ResponseWriterインターフェースのWriteメソッドが、Content-Typeヘッダが明示的に設定されていない場合に、内部的にDetectContentType関数を使用してコンテンツタイプを自動的に推測するという重要な挙動について、ドキュメントに記載がないことを指摘していました。

開発者がhttp.ResponseWriterを使用してHTTPレスポンスを書き込む際、Content-Typeヘッダを設定し忘れることはよくあります。このような場合、Webブラウザやクライアントはレスポンスボディの内容に基づいてコンテンツタイプを推測しようとしますが、これはセキュリティ上の問題(MIMEタイプスニッフィング攻撃など)や、意図しないレンダリングを引き起こす可能性があります。Goのnet/httpパッケージは、この問題を緩和するために、Writeメソッドが最初の512バイトのデータに基づいてコンテンツタイプを自動的に検出する機能を提供していました。しかし、この挙動がドキュメントに明記されていなかったため、開発者はこの自動検出機能の存在やその詳細を知ることができず、予期せぬ動作に遭遇したり、適切なContent-Typeヘッダの設定を怠ったりする可能性がありました。

このコミットは、この重要な自動検出の挙動をhttp.ResponseWriter.Writeのドキュメントに追加することで、開発者がより安全で予測可能なHTTPサービスを構築できるようにすることを目的としています。また、DetectContentType関数のドキュメントも改善され、その動作原理(スニッフィングのバイト数、常に有効なMIMEタイプを返すこと)がより明確に説明されています。

前提知識の解説

Content-Type (MIMEタイプ)

Content-Typeは、HTTPヘッダの一つで、HTTPメッセージのボディに含まれるデータのメディアタイプ(MIMEタイプ)を示すものです。例えば、text/htmlはHTMLドキュメント、application/jsonはJSONデータ、image/pngはPNG画像を表します。クライアント(Webブラウザなど)は、このContent-Typeヘッダを見て、受信したデータをどのように解釈し、表示すべきかを判断します。

MIMEタイプスニッフィング (MIME Type Sniffing)

MIMEタイプスニッフィングとは、HTTPレスポンスにContent-Typeヘッダがない場合や、ヘッダが不正確な場合に、Webブラウザなどのクライアントがレスポンスボディの先頭バイトを検査して、データの実際のコンテンツタイプを推測するプロセスです。これはユーザーエクスペリエンスを向上させるために導入されましたが、悪意のあるコンテンツが誤ったMIMEタイプで提供され、ブラウザがそれを実行可能なスクリプトとして解釈してしまうなど、セキュリティ上の脆弱性(MIMEタイプスニッフィング攻撃)を引き起こす可能性があります。

net/httpパッケージ (Go言語)

Go言語の標準ライブラリであるnet/httpパッケージは、HTTPクライアントとサーバーの実装を提供します。WebアプリケーションやAPIサーバーを構築する際に中心的に使用されます。

  • http.ResponseWriter: HTTPレスポンスを構築するために使用されるインターフェースです。このインターフェースを通じて、HTTPヘッダの設定やレスポンスボディの書き込みが行われます。
  • http.Request: 受信したHTTPリクエストを表す構造体です。
  • http.Handler: HTTPリクエストを処理するためのインターフェースです。

DetectContentType関数

DetectContentType関数は、Goのnet/http/sniffパッケージで提供されるユーティリティ関数です。この関数は、与えられたバイトスライス(通常はHTTPレスポンスボディの先頭部分)を分析し、その内容に基づいてMIMEタイプを推測します。この推測は、WHATWGのMIME Sniffing Standardに準拠しています。

技術的詳細

このコミットの技術的詳細は、主にGoのnet/httpパッケージにおけるHTTPレスポンスのContent-Typeヘッダの自動設定メカニズムと、その基盤となるDetectContentType関数の動作に関するドキュメントの改善にあります。

http.ResponseWriter.Writeの挙動

Goのnet/httpパッケージでは、http.ResponseWriterインターフェースのWriteメソッドが呼び出された際に、以下のようなロジックが内部的に実行されます。

  1. ヘッダの書き込み: もしWriteHeaderメソッドがまだ呼び出されていない場合、Writeメソッドは自動的にWriteHeader(http.StatusOK)を呼び出し、HTTPステータスコード200 OKでレスポンスヘッダを送信します。
  2. Content-Typeの自動検出: ここがこのコミットの核心です。もしレスポンスヘッダにContent-Typeが明示的に設定されていない場合、Writeメソッドは書き込まれるデータの最初の512バイト(sniffLenで定義される定数)をDetectContentType関数に渡します。DetectContentTypeが返したMIMEタイプが、レスポンスのContent-Typeヘッダとして自動的に設定されます。この挙動は、開発者がContent-Typeを明示的に設定し忘れた場合でも、ある程度の適切なデフォルト値が提供されることを保証します。
  3. データ書き込み: その後、与えられたデータがHTTP接続に書き込まれます。

この自動検出メカニズムは、WebブラウザのMIMEタイプスニッフィングと同様の原理に基づいていますが、サーバー側で制御されるため、より予測可能で安全な挙動を提供します。

DetectContentType関数の動作

DetectContentType関数は、WHATWGのMIME Sniffing Standard (http://mimesniff.spec.whatwg.org/) に従ってコンテンツタイプを検出します。

  • スニッフィングのバイト数: この関数は、与えられたデータの最大512バイト(sniffLen)を検査してコンテンツタイプを決定します。データが512バイト未満の場合、利用可能なすべてのバイトが検査されます。
  • 戻り値の保証: DetectContentTypeは、常に有効なMIMEタイプ文字列を返します。もしより具体的なMIMEタイプを決定できない場合(例えば、データが空であるか、既知のパターンに一致しない場合)、デフォルトのフォールバックとしてapplication/octet-stream(汎用的なバイナリデータ)を返します。これにより、クライアントが常に何らかのContent-Type情報を受け取ることが保証されます。

このコミットは、これらの重要な挙動をGoのドキュメントに明記することで、開発者がnet/httpパッケージの動作をより深く理解し、適切に利用できるようにすることを目的としています。特に、Content-Typeヘッダの自動設定は、多くのWebアプリケーションで暗黙的に利用される機能であるため、その存在と動作原理を明確にすることは、予期せぬ挙動の回避やセキュリティの向上に寄与します。

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

このコミットでは、以下の2つのファイルが変更されています。

  1. src/pkg/net/http/server.go
  2. src/pkg/net/http/sniff.go

それぞれの変更箇所は以下の通りです。

diff --git a/src/pkg/net/http/server.go b/src/pkg/net/http/server.go
index 8c4822ec74..fb3bc81756 100644
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -59,7 +59,9 @@ type ResponseWriter interface {
 
 	// Write writes the data to the connection as part of an HTTP reply.
 	// If WriteHeader has not yet been called, Write calls WriteHeader(http.StatusOK)
-	// before writing the data.
+	// before writing the data.  If the Header does not contain a
+	// Content-Type line, Write adds a Content-Type set to the result of passing
+	// the initial 512 bytes of written data to DetectContentType.
 	Write([]byte) (int, error)
 
 	// WriteHeader sends an HTTP response header with status code.
diff --git a/src/pkg/net/http/sniff.go b/src/pkg/net/http/sniff.go
index c1c78e2417..68f519b054 100644
--- a/src/pkg/net/http/sniff.go
+++ b/src/pkg/net/http/sniff.go
@@ -9,15 +9,15 @@ import (
 	"encoding/binary"
 )
 
-// Content-type sniffing algorithm.
-// References in this file refer to this draft specification:
-//   http://mimesniff.spec.whatwg.org/
-
-// The algorithm prefers to use sniffLen bytes to make its decision.
+// The algorithm uses at most sniffLen bytes to make its decision.
 const sniffLen = 512
 
-// DetectContentType returns the sniffed Content-Type string
-// for the given data. This function always returns a valid MIME type.
+// DetectContentType implements the algorithm described
+// at http://mimesniff.spec.whatwg.org/ to determine the
+// Content-Type of the given data.  It considers at most the
+// first 512 bytes of data.  DetectContentType always returns
+// a valid MIME type: if it cannot determine a more specific one, it
+// returns "application/octet-stream".
 func DetectContentType(data []byte) string {
 	if len(data) > sniffLen {
 		data = data[:sniffLen]

コアとなるコードの解説

src/pkg/net/http/server.goの変更

http.ResponseWriterインターフェースのWriteメソッドのドキュメントに、以下の行が追加されました。

+	// before writing the data.  If the Header does not contain a
+	// Content-Type line, Write adds a Content-Type set to the result of passing
+	// the initial 512 bytes of written data to DetectContentType.

この変更により、WriteメソッドがContent-Typeヘッダが未設定の場合に、書き込まれるデータの最初の512バイトをDetectContentTypeに渡し、その結果をContent-Typeとして自動的に設定するという重要な挙動が明示されました。これにより、開発者はこの自動検出メカニズムの存在を認識し、必要に応じて明示的にContent-Typeを設定するか、この自動検出に依存するかを判断できるようになります。

src/pkg/net/http/sniff.goの変更

DetectContentType関数のドキュメントが大幅に改善されました。

変更前:

// Content-type sniffing algorithm.
// References in this file refer to this draft specification:
//   http://mimesniff.spec.whatwg.org/

// The algorithm prefers to use sniffLen bytes to make its decision.
const sniffLen = 512

// DetectContentType returns the sniffed Content-Type string
// for the given data. This function always returns a valid MIME type.
func DetectContentType(data []byte) string {

変更後:

// The algorithm uses at most sniffLen bytes to make its decision.
const sniffLen = 512

// DetectContentType implements the algorithm described
// at http://mimesniff.spec.whatwg.org/ to determine the
// Content-Type of the given data.  It considers at most the
// first 512 bytes of data.  DetectContentType always returns
// a valid MIME type: if it cannot determine a more specific one, it
// returns "application/octet-stream".
func DetectContentType(data []byte) string {

この変更により、DetectContentType関数の動作がより詳細かつ正確に説明されています。

  • 標準への準拠: DetectContentTypeがWHATWGのMIME Sniffing Standard (http://mimesniff.spec.whatwg.org/) に従ってコンテンツタイプを決定することが明確に述べられています。
  • スニッフィングのバイト数: 「It considers at most the first 512 bytes of data.」という記述により、最大512バイトのデータが考慮されることが強調されています。以前の「The algorithm prefers to use sniffLen bytes to make its decision.」よりも具体的です。
  • 戻り値の保証: 「DetectContentType always returns a valid MIME type: if it cannot determine a more specific one, it returns "application/octet-stream".」という記述により、関数が常に有効なMIMEタイプを返し、より具体的なタイプを決定できない場合はapplication/octet-streamを返すことが明確に示されています。これは、関数の堅牢性と予測可能性を保証する重要な情報です。

これらのドキュメントの改善は、Goのnet/httpパッケージの透明性を高め、開発者がHTTPレスポンスのContent-Type処理をより正確に理解し、制御できるようにするために非常に重要です。

関連リンク

参考にした情報源リンク