Appendix B. Implementation Notes (実装注意事項)
本附録は、RFC 8941を実装するための実用的なアドバイスとベストプラクティスを提供します。
汎用実装アーキテクチャ
汎用実装は、トップレベルのserialize(セクション4.1)およびparse(セクション4.2)関数を公開すべきです (SHOULD)。
実装形式
これらは関数である必要はありません。例えば、異なるトップレベル型ごとにメソッドを提供するオブジェクトとして実装できます。
// 関数型API
const result = parseList(input);
const output = serializeDict(dict);
// オブジェクト型API
const parser = new StructuredFieldParser();
const result = parser.parseList(input);
const serializer = new StructuredFieldSerializer();
const output = serializer.serializeDict(dict);
完全性と一貫性
相互運用性のため、汎用実装は完全であり、アルゴリズムに厳格に従わなければなりません (MUST)。セクション1.1を参照してください。
コミュニティテストスイート
実装を支援するため、コミュニティは汎用テストスイートを維持しています:
URL: https://github.com/httpwg/structured-field-tests
テストカバレッジ
テストスイートには以下が含まれます:
- ✓ すべてのデータ型のシリアライゼーションとパース
- ✓ エッジケース
- ✓ エラー条件
- ✓ 相互運用性テスト
順序付きマッピング
実装者は、DictionariesとParametersが順序保持マッピング (order-preserving maps) であることに注意すべきです (SHOULD)。
なぜ順序が重要か?
一部のフィールドはこれらのデータ型の順序で意味を伝達しない場合がありますが、それでもそれを公開して、使用する必要があるアプリケーションが使用できるようにする必要があります。
実装例
// ✓ 良い - 順序を保持
class OrderedDict {
constructor() {
this.items = []; // [{key, value}, ...]
}
set(key, value) {
const index = this.items.findIndex(i => i.key === key);
if (index >= 0) {
this.items[index].value = value;
} else {
this.items.push({key, value});
}
}
}
// ✗ 悪い - 順序を保持しない
const dict = {}; // JavaScriptオブジェクトは順序を保証しない場合がある
TokenとStringの区別
実装は、TokenとStringの間の区別を維持することが重要であることに注意すべきです (SHOULD)。
問題
// ✗ 悪い - 型情報が失われる
const value = "text/html"; // これはTokenかStringか?
// ✓ 良い - 型を保持
const value = {type: 'token', value: 'text/html'};
const value2 = {type: 'string', value: 'text/html'};
エラー処理
パースが失敗した場合、実装はフィールド全体を無視しなければなりません (MUST)。
function parseStructuredField(input, type) {
try {
return parse(input, type);
} catch (error) {
// フィールド全体を無視
return null;
}
}
パフォーマンス考慮事項
1. 段階的パース
大きなフィールドの場合、段階的なパースを検討してください:
// 必要な部分のみをパース
const dict = parseDictionary(input);
const priority = dict.get('priority'); // 他の部分を遅延パース
2. キャッシング
頻繁にアクセスされるフィールドのパース結果をキャッシュします:
const cache = new Map();
function getCachedParse(fieldValue) {
if (!cache.has(fieldValue)) {
cache.set(fieldValue, parse(fieldValue));
}
return cache.get(fieldValue);
}
セキュリティ実装チェックリスト
実装時には以下を確認してください:
- 最大フィールドサイズを制限
- List/Dictionaryの最大メンバー数を制限
- 文字列の最大長を制限
- すべての型を厳格に検証
- 重複キーを拒否
- パースエラーで適切に失敗
- 型変換を試みない
言語固有の注意事項
JavaScript/TypeScript
// Map を使用して順序を保持
const dict = new Map<string, any>();
// 型安全性のための型定義
type StructuredItem = {
value: BareItem;
params: Map<string, BareItem>;
};
Python
# OrderedDict を使用
from collections import OrderedDict
dict_value = OrderedDict([
('key1', value1),
('key2', value2)
])
Go
// スライスを使用して順序を保持
type Dictionary struct {
items []DictItem
}
type DictItem struct {
Key string
Value interface{}
}
テストのベストプラクティス
- コミュニティテストスイートを使用: 基本的な相互運用性を保証
- エッジケースをテスト: 最大値、最小値、空の値
- エラーケースをテスト: 無効な入力が適切に処理されることを確認
- ラウンドトリップテスト: serialize(parse(x)) == x
- 相互運用性テスト: 他の実装との互換性を検証
重要なポイント
- アルゴリズムに従う: 仕様のアルゴリズムに厳格に従う
- テストスイートを使用: コミュニティテストで検証
- 順序を保持: DictionaryとParameterの順序を維持
- 型を区別: TokenとStringを明確に区別
- 適切に失敗: エラー時にフィールド全体を無視
- セキュリティ制限: 合理的なサイズ制限を実装