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

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

このコミットは、Go言語の標準ライブラリである net/http パッケージにおいて、multipart/byteranges 形式のレスポンスに対する特別な処理を削除するものです。これにより、net/http クライアントが multipart/byteranges レスポンスをより汎用的に扱えるようになり、特定のケースでの不適切なエラー処理が修正されます。

コミット

  • コミットハッシュ: 0bc38b7fe4715512908e9a50988aa382e423a3cd
  • Author: Brad Fitzpatrick bradfitz@golang.org
  • Date: Thu Feb 28 16:58:26 2013 -0800

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

https://github.com/golang/go/commit/0bc38b7fe4715512908e9a50988aa382e423a3cd

元コミット内容

net/http: don't special-case multipart/byteranges responses

Fixes #4767

R=golang-dev, adg
CC=golang-dev
https://golang.org/cl/7435046

変更の背景

このコミットは、Goの net/http パッケージが multipart/byteranges コンテンツタイプを持つHTTPレスポンスを不適切に扱っていた問題を修正するために行われました。以前の実装では、Content-Type ヘッダーに "multipart/byteranges" が含まれている場合、net/http クライアントはボディの長さを -1 (不明) と判断し、ErrNotSupported エラーを返すという特殊な処理を行っていました。

これは、HTTPの Range リクエストに対する 206 Partial Content レスポンスでよく使用される multipart/byteranges の仕様を誤解していたか、あるいは初期の実装段階で特定のユースケースを想定していなかったためと考えられます。この特殊な処理により、正当な multipart/byteranges レスポンスがクライアント側で正しく処理されず、アプリケーションが意図しないエラーを受け取る可能性がありました。

コミットメッセージにある Fixes #4767 は、この問題がGoのIssueトラッカーで報告されていたことを示しています。この変更は、net/http パッケージがHTTP標準に準拠し、より堅牢に動作するようにするための改善です。

前提知識の解説

HTTP 206 Partial Content

HTTPステータスコード 206 Partial Content は、クライアントが Range ヘッダーを使用してリソースの一部を要求し、サーバーがその要求を正常に処理してリソースの一部を返した場合に用いられます。例えば、大きなファイルのダウンロードを中断した後に再開する場合や、動画のストリーミングなどで特定の範囲のデータを取得する際に利用されます。

Content-Type: multipart/byteranges

multipart/byteranges は、HTTPの Content-Type ヘッダーで指定されるメディアタイプの一つです。これは、206 Partial Content レスポンスにおいて、複数のバイト範囲(レンジ)のデータをまとめて返す際に使用されます。

この形式のレスポンスボディは、MIMEマルチパートメッセージの構造を持ちます。各バイト範囲は、それぞれ異なる Content-Type ヘッダーと Content-Range ヘッダーを持つ独立したパートとして区切られます。これにより、クライアントは単一のHTTPレスポンスで複数の不連続なデータ範囲を受け取ることができます。

例:

HTTP/1.1 206 Partial Content
Content-Type: multipart/byteranges; boundary=THIS_STRING_SEPARATES_PARTS

--THIS_STRING_SEPARATES_PARTS
Content-Type: application/octet-stream
Content-Range: bytes 0-499/12345

... (最初の500バイトのデータ) ...
--THIS_STRING_SEPARATES_PARTS
Content-Type: application/octet-stream
Content-Range: bytes 1000-1499/12345

... (次の500バイトのデータ) ...
--THIS_STRING_SEPARATES_PARTS--

Goの net/http パッケージ

net/http はGo言語の標準ライブラリであり、HTTPクライアントとサーバーの実装を提供します。このパッケージは、HTTPプロトコルの低レベルな詳細を抽象化し、開発者が簡単にWebアプリケーションやクライアントを構築できるようにします。HTTPリクエストの送信、レスポンスの受信、ヘッダーの解析、ボディの読み取りなど、HTTP通信に必要な機能が網羅されています。

このコミットで変更される transfer.go ファイルは、net/http パッケージ内でHTTPボディの転送エンコーディング(チャンク転送、Content-Lengthなど)やボディの読み取りに関するロジックを扱う部分です。

技術的詳細

このコミットの技術的な核心は、src/pkg/net/http/transfer.go ファイル内の fixLength 関数から multipart/byteranges に特化した処理を削除した点にあります。

fixLength 関数は、HTTPレスポンスのボディの長さを決定するためのロジックを含んでいます。これには、Content-Length ヘッダーの有無、チャンク転送エンコーディングの使用、HTTPメソッド(HEADリクエストなど)によるボディの有無などが考慮されます。

変更前のコードでは、fixLength 関数内に以下のロジックが存在しました。

	// Logic based on media type. The purpose of the following code is just
	// to detect whether the unsupported "multipart/byteranges" is being
	// used. A proper Content-Type parser is needed in the future.
	if strings.Contains(strings.ToLower(header.get("Content-Type")), "multipart/byteranges") {
		return -1, ErrNotSupported
	}

このコードは、Content-Type ヘッダーが "multipart/byteranges" を含む場合に、ボディの長さを -1 (不明) と設定し、ErrNotSupported エラーを返していました。これは、multipart/byterangesnet/http パッケージによって「サポートされていない」と見なされていたためです。しかし、multipart/byteranges はHTTP標準の一部であり、正当なレスポンス形式です。この特殊な処理は、net/http クライアントがこのようなレスポンスを正しく処理できない原因となっていました。

このコミットでは、上記の if ブロック全体が削除されました。これにより、multipart/byteranges レスポンスは他の通常のHTTPレスポンスと同様に扱われるようになります。つまり、Content-Length ヘッダーが存在すればその値が使用され、存在しなければチャンク転送エンコーディングや接続のクローズによってボディの終端が判断されるようになります。

また、src/pkg/net/http/response_test.go には、multipart/byteranges レスポンスをテストするための新しいテストケースが追加されました。このテストケースは、206 Partial Content ステータスコードと multipart/byterangesContent-Type ヘッダーを持つレスポンスが、正しくパースされ、ContentLength-1 (不明) となり、Closetrue となることを確認しています。これは、multipart/byteranges レスポンスのボディ長が通常は事前に不明であり、接続がクローズされることでボディの終端が示されるという一般的な挙動を反映しています。

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

diff --git a/src/pkg/net/http/response_test.go b/src/pkg/net/http/response_test.go
index 8411964dc8..2f5f77369f 100644
--- a/src/pkg/net/http/response_test.go
+++ b/src/pkg/net/http/response_test.go
@@ -324,6 +324,30 @@ var respTests = []respTest{\n 
 		\"\",\n 	},\n+\n+\t// golang.org/issue/4767: don't special-case multipart/byteranges responses\n+\t{\n+\t\t`HTTP/1.1 206 Partial Content\n+Connection: close\n+Content-Type: multipart/byteranges; boundary=18a75608c8f47cef\n+\n+some body`,\n+\t\tResponse{\n+\t\t\tStatus:     \"206 Partial Content\",\n+\t\t\tStatusCode: 206,\n+\t\t\tProto:      \"HTTP/1.1\",\n+\t\t\tProtoMajor: 1,\n+\t\t\tProtoMinor: 1,\n+\t\t\tRequest:    dummyReq(\"GET\"),\n+\t\t\tHeader: Header{\n+\t\t\t\t\"Content-Type\": []string{\"multipart/byteranges; boundary=18a75608c8f47cef\"},\n+\t\t\t},\n+\t\t\tClose:         true,\n+\t\t\tContentLength: -1,\n+\t\t},\n+\n+\t\t\"some body\",\n+\t},\n }\n 
 func TestReadResponse(t *testing.T) {\ndiff --git a/src/pkg/net/http/transfer.go b/src/pkg/net/http/transfer.go
index 3b473ad75b..43c6023a3a 100644
--- a/src/pkg/net/http/transfer.go
+++ b/src/pkg/net/http/transfer.go
@@ -454,13 +454,6 @@ func fixLength(isResponse bool, status int, requestMethod string, header Header,\n 
 		return 0, nil\n 	}\n \n-\t// Logic based on media type. The purpose of the following code is just\n-\t// to detect whether the unsupported \"multipart/byteranges\" is being\n-\t// used. A proper Content-Type parser is needed in the future.\n-\tif strings.Contains(strings.ToLower(header.get(\"Content-Type\")), \"multipart/byteranges\") {\n-\t\treturn -1, ErrNotSupported\n-\t}\n-\n \t// Body-EOF logic based on other methods (like closing, or chunked coding)\n \treturn -1, nil\n }\n```

## コアとなるコードの解説

### `src/pkg/net/http/response_test.go` の変更

- **追加されたテストケース**:
    - `respTests` スライスに新しいテスト構造体が追加されました。
    - このテストケースは、`HTTP/1.1 206 Partial Content` ステータスと `Content-Type: multipart/byteranges; boundary=...` ヘッダーを持つHTTPレスポンスをシミュレートします。
    - 期待される `Response` オブジェクトのフィールドは以下の通りです。
        - `Status`: `"206 Partial Content"`
        - `StatusCode`: `206`
        - `Proto`: `"HTTP/1.1"`, `ProtoMajor`: `1`, `ProtoMinor`: `1`
        - `Request`: ダミーのGETリクエスト
        - `Header`: `Content-Type` ヘッダーが正しくパースされていること
        - `Close`: `true` (接続がクローズされることでボディの終端が示されるため)
        - `ContentLength`: `-1` (ボディの長さが不明であることを示す)
    - このテストの目的は、`net/http` パッケージが `multipart/byteranges` レスポンスを正しくパースし、以前のような `ErrNotSupported` を返さずに、ボディの読み取りを適切に処理できるようになったことを検証することです。

### `src/pkg/net/http/transfer.go` の変更

- **`fixLength` 関数からのコード削除**:
    - 以前の `fixLength` 関数には、`Content-Type` ヘッダーに `"multipart/byteranges"` が含まれている場合に、ボディの長さを `-1` に設定し、`ErrNotSupported` を返す特殊なロジックがありました。
    - このコミットでは、この `if` ブロック全体が削除されました。
    - これにより、`multipart/byteranges` レスポンスは、他の一般的なHTTPレスポンスと同様に、`Content-Length` ヘッダーやチャンク転送エンコーディング、または接続のクローズによってボディの終端が決定されるようになります。
    - この変更は、`net/http` パッケージが `multipart/byteranges` を「サポートされていない」と見なすのではなく、標準的なHTTPボディの読み取りメカニズムで処理できるようにすることで、より汎用的な動作を実現します。

## 関連リンク

- **Go CL (Code Review)**: [https://golang.org/cl/7435046](https://golang.org/cl/7435046)
- **関連するGo Issue**: `golang.org/issue/4767` (直接的な検索結果は見つかりませんでしたが、コミットメッセージに記載されています。)

## 参考にした情報源リンク

- HTTP/1.1: Range Requests (RFC 7233): [https://datatracker.ietf.org/doc/html/rfc7233](https://datatracker.ietf.org/doc/html/rfc7233)
- MIME (Multipurpose Internet Mail Extensions) Part Five: Conformance Criteria and Examples (RFC 2049): [https://datatracker.ietf.org/doc/html/rfc2049](https://datatracker.ietf.org/doc/html/rfc2049)
- Go `net/http` package documentation: [https://pkg.go.dev/net/http](https://pkg.go.dev/net/http)
- Go `strings` package documentation: [https://pkg.go.dev/strings](https://pkg.go.dev/strings)