[インデックス 12964] ファイルの概要
このコミットは、Go言語の標準ライブラリ mime
パッケージにおける ParseMediaType
関数のエラーハンドリングを改善するものです。具体的には、メディアタイプ文字列のパースに失敗した場合に、関数がゼロ値(空文字列とnilマップ)を返すように変更し、エラー発生時の挙動をより明確にしています。
コミット
commit 7f7a70f225b5f08b601ce3bef091887d79a34f06
Author: Brad Fitzpatrick <bradfitz@golang.org>
Date: Wed Apr 25 12:01:01 2012 -0700
mime: make ParseMediaType return zero results on error
Fixes #3562
R=golang-dev, adg, rsc
CC=golang-dev
https://golang.org/cl/6119051
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/7f7a70f225b5f08b601ce3bef091887d79a34f06
元コミット内容
mime: make ParseMediaType return zero results on error
Fixes #3562
R=golang-dev, adg, rsc
CC=golang-dev
https://golang.org/cl/6119051
変更の背景
この変更は、Go言語のIssue #3562に対応するものです。ParseMediaType
関数は、HTTPのContent-Type
ヘッダなどで使用されるメディアタイプ文字列(例: text/html; charset=utf-8
)をパースし、メディアタイプ本体とパラメータのマップを返します。しかし、パース中にエラーが発生した場合、これまでの実装では、エラーが返されるにもかかわらず、mediatype
(文字列)や params
(マップ)に中途半端な値が設定されてしまう可能性がありました。
プログラミングにおける良いプラクティスとして、関数がエラーを返す場合、その戻り値は「ゼロ値」であるべき、という考え方があります。これは、エラーが発生した際には、有効な結果が生成されなかったことを明確にし、呼び出し元がエラーの有無だけで結果の有効性を判断できるようにするためです。中途半端な値が返されると、呼び出し元がその値を誤って使用してしまうリスクがあり、予期せぬバグにつながる可能性があります。
このコミットは、この問題を解決し、ParseMediaType
がエラーを返した際には、mediatype
に空文字列 ""
、params
に nil
を返すように修正することで、より堅牢で予測可能なAPI挙動を実現しています。
前提知識の解説
MIMEタイプ (Media Type / Content-Type)
MIMEタイプ(Multipurpose Internet Mail Extensions)は、インターネット上でやり取りされるデータの種類を識別するための標準的な方法です。HTTPのContent-Type
ヘッダや電子メールの添付ファイルなどで広く利用されています。
MIMEタイプは通常、type/subtype
の形式で表現されます(例: text/html
, image/jpeg
, application/json
)。さらに、セミコロンで区切られたパラメータを持つこともあります(例: text/html; charset=utf-8
, application/json; boundary=something
)。
Go言語のエラーハンドリング
Go言語では、エラーは多値戻り値の最後の要素として返されるのが一般的です。慣習として、関数がエラーを返す場合、他の戻り値は「ゼロ値」であるべきとされています。例えば、func (T, error)
のようなシグネチャを持つ関数でエラーが発生した場合、T
のゼロ値(数値型なら0、文字列型なら""、ポインタやマップ、スライスならnil)が返されるべきです。これにより、呼び出し元はエラーの有無だけを確認すればよく、エラーが発生したにもかかわらず中途半端な値が返されることによる混乱を防ぎます。
mime
パッケージ
Go言語の標準ライブラリ mime
パッケージは、MIMEタイプ文字列のパースや生成、エンコーディング/デコーディングなどの機能を提供します。ParseMediaType
関数はその中でも中心的な役割を担い、MIMEタイプ文字列を構造化されたデータ(メディアタイプ本体とパラメータマップ)に分解します。
技術的詳細
このコミットの技術的な変更点は非常にシンプルですが、Go言語のエラーハンドリングの慣習に則った重要な改善です。
ParseMediaType
関数の元の実装では、checkMediaTypeDisposition
関数がエラーを返した場合、単に return
していました。この return
は、mediatype
と params
にそれまでの処理で設定された可能性のある中途半端な値をそのまま返してしまうことを意味します。
変更後、エラーが発生した場合に return "", nil, err
と明示的に記述することで、mediatype
には空文字列 ""
、params
には nil
が設定され、エラー情報と共にゼロ値が返されるようになります。これにより、呼び出し元はエラーが返された場合に、戻り値の mediatype
や params
を安全に無視できるようになります。
また、テストコード (src/pkg/mime/mediatype_test.go
) も更新され、エラーが発生した場合に ParseMediaType
が非nilのパラメータや非空のメディアタイプ文字列を返さないことを確認するテストケースが追加されています。これにより、将来的に同様の回帰バグが発生するのを防ぎます。
コアとなるコードの変更箇所
src/pkg/mime/mediatype.go
--- a/src/pkg/mime/mediatype.go
+++ b/src/pkg/mime/mediatype.go
@@ -99,7 +99,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e
err = checkMediaTypeDisposition(mediatype)
if err != nil {
- return
+ return "", nil, err
}
params = make(map[string]string)
src/pkg/mime/mediatype_test.go
--- a/src/pkg/mime/mediatype_test.go
+++ b/src/pkg/mime/mediatype_test.go
@@ -244,13 +244,33 @@ func TestParseMediaType(t *testing.T) {
}\n}\n\n+type badMediaTypeTest {\n+\tin string\n+\terr string\n+}\n+\n+var badMediaTypeTests = []badMediaTypeTest{\n+\t{\"bogus ;=========\", \"mime: invalid media parameter\"},\n+\t{\"bogus/<script>alert</script>\", \"mime: expected token after slash\"},\n+\t{\"bogus/bogus<script>alert</script>\", \"mime: unexpected content after media subtype\"},\n+}\n+\n func TestParseMediaTypeBogus(t *testing.T) {\n-\tmt, params, err := ParseMediaType(\"bogus ;=========\")\n-\tif err == nil {\n-\t\tt.Fatalf(\"expected an error parsing invalid media type; got type %q, params %#v\", mt, params)\n-\t}\n-\tif err.Error() != \"mime: invalid media parameter\" {\n-\t\tt.Errorf(\"expected invalid media parameter; got error %q\", err)\n+\tfor _, tt := range badMediaTypeTests {\n+\t\tmt, params, err := ParseMediaType(tt.in)\n+\t\tif err == nil {\n+\t\t\tt.Errorf(\"ParseMediaType(%q) = nil error; want parse error\", tt.in)\n+\t\t\tcontinue\n+\t\t}\n+\t\tif err.Error() != tt.err {\n+\t\t\tt.Errorf(\"ParseMediaType(%q) = err %q; want %q\", tt.in, err.Error(), tt.err)\n+\t\t}\n+\t\tif params != nil {\n+\t\t\tt.Errorf(\"ParseMediaType(%q): got non-nil params on error\", tt.in)\n+\t\t}\n+\t\tif mt != \"\" {\n+\t\t\tt.Errorf(\"ParseMediaType(%q): got non-empty media type string on error\", tt.in)\n+\t\t}\n \t}\n }\n \n```
## コアとなるコードの解説
### `src/pkg/mime/mediatype.go` の変更
`ParseMediaType` 関数内で、`checkMediaTypeDisposition(mediatype)` がエラーを返した場合の処理が変更されています。
- **変更前**:
```go
if err != nil {
return
}
この return
は、ParseMediaType
の戻り値である mediatype
, params
, err
のうち、err
にはエラーが設定されますが、mediatype
と params
にはそれまでの処理で設定された値(中途半端な値や、関数の冒頭で宣言された際のゼロ値)がそのまま返されていました。
- 変更後:
エラーが発生した場合に、if err != nil { return "", nil, err }
mediatype
には空文字列""
、params
にはnil
を明示的に設定して返しています。これにより、エラーが返された際には、有効なメディアタイプやパラメータが取得できなかったことが明確になり、呼び出し元はこれらの値を安全に無視できます。これはGo言語におけるエラーハンドリングのベストプラクティスに沿った変更です。
src/pkg/mime/mediatype_test.go
の変更
テストファイルでは、TestParseMediaTypeBogus
関数が大幅に修正されています。
-
変更前: 単一の不正なメディアタイプ文字列
\"bogus ;=========\"
に対してのみテストを行っていました。エラーが返されることを確認するのみで、mt
(mediatype) やparams
がどのような値になるかは確認していませんでした。 -
変更後:
badMediaTypeTest
という構造体とbadMediaTypeTests
というスライスが導入され、複数の不正なメディアタイプ文字列とその期待されるエラーメッセージを定義しています。 ループ処理でこれらのテストケースを一つずつ実行し、以下の点を厳密に検証しています。ParseMediaType
がエラーを返すこと。- 返されたエラーメッセージが期待されるものと一致すること。
- 最も重要な点として、エラー発生時に
params
がnil
であること。 - エラー発生時に
mt
(mediatype) が空文字列""
であること。
これらのテストの追加により、ParseMediaType
がエラーを返した際に、不完全な結果を返さないことが保証されるようになりました。
関連リンク
- Go Issue #3562: https://github.com/golang/go/issues/3562
- Go CL 6119051: https://golang.org/cl/6119051
参考にした情報源リンク
- Go言語の公式ドキュメント (mimeパッケージ): https://pkg.go.dev/mime
- Go言語のエラーハンドリングに関する一般的な慣習: (Go言語の公式ブログやEffective Goなど)
- MIMEタイプに関するRFC: (例: RFC 2045, RFC 6838)