[インデックス 12882] ファイルの概要
このコミットは、Go言語のhtml
パッケージおよびexp/html
パッケージにおけるHTMLエスケープ処理の改善に関するものです。具体的には、シングルクォート('
)とダブルクォート("
)のエスケープ方法を、従来のエンティティ参照('
、"
)から数値文字参照('
、"
)に変更しています。これにより、Internet Explorer 8(IE8)以前のブラウザでの互換性問題が解決され、text/template
パッケージのHTMLEscape
関数との一貫性が確保されます。
コミット
commit 6277656d69640da9166bbac2a132a3ddee61dcac
Author: Nigel Tao <nigeltao@golang.org>
Date: Thu Apr 12 09:35:43 2012 +1000
html, exp/html: escape ' and " as ' and ", since IE8 and
below do not support '.
This makes package html consistent with package text/template's
HTMLEscape function.
Fixes #3489.
R=rsc, mikesamuel, dsymonds
CC=golang-dev
https://golang.org/cl/5992071
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/6277656d69640da9166bbac2a132a3ddee61dcac
元コミット内容
html, exp/html: escape ' and " as ' and ", since IE8 and below do not support '. This makes package html consistent with package text/template's HTMLEscape function. Fixes #3489.
(日本語訳)
html
, exp/html
: IE8以前が'
をサポートしないため、'
と"
を'
と"
としてエスケープする。
これにより、html
パッケージがtext/template
パッケージのHTMLEscape
関数と一貫性を持つようになる。
Issue #3489を修正。
変更の背景
この変更の主な背景は、Internet Explorer 8(IE8)およびそれ以前のバージョンのブラウザが、HTMLの標準で定義されているはずの文字実体参照'
(アポストロフィ、シングルクォート)を正しく解釈しないという互換性問題にありました。
HTML 4.01までは'
は標準で定義されておらず、XMLやXHTMLで使われるエンティティでした。HTML5で正式に導入されましたが、古いブラウザ、特にIE8以前ではサポートされていませんでした。そのため、Go言語のhtml
パッケージが'
を使用してシングルクォートをエスケープすると、IE8以前のブラウザで表示が崩れるなどの問題が発生する可能性がありました。
また、Go言語の標準ライブラリには、HTMLエスケープを行う複数のパッケージが存在します。html
パッケージとtext/template
パッケージはその代表例です。このコミット以前は、html
パッケージが'
と"
を使用していたのに対し、text/template
パッケージは既に数値文字参照である'
と"
を使用しており、両者間で一貫性がありませんでした。この不一致は、開発者がどちらのパッケージを使用するかによって異なるエスケープ結果になるという混乱を招く可能性がありました。
このコミットは、これらの問題を解決するために、より互換性の高い数値文字参照('
と"
)を使用するように変更し、同時に標準ライブラリ内でのエスケープ処理の一貫性を高めることを目的としています。
前提知識の解説
HTMLエスケープとは
HTMLエスケープとは、HTMLドキュメント内で特殊な意味を持つ文字(例: <
、>
、&
、"
、'
)を、その文字自体として表示するために、特別な表記(文字実体参照や数値文字参照)に変換する処理のことです。これにより、ブラウザがこれらの文字をHTMLタグやエンティティの開始として誤って解釈することを防ぎ、セキュリティ上の脆弱性(例: クロスサイトスクリプティング XSS)を防ぐ役割も果たします。
- 文字実体参照 (Named Character Reference):
&
で始まり;
で終わる、文字の名前を使った参照です。例:<
(<
)、>
(>
)、&
(&
)、"
("
)、'
('
)。 - 数値文字参照 (Numeric Character Reference):
&#
で始まり;
で終わる、文字のUnicodeコードポイントを使った参照です。10進数(&#DDDD;
)または16進数(&#xHHHH;
)で表記されます。例:<
(<
)、>
(>
)、&
(&
)、"
("
)、'
('
)。
'
と'
の互換性問題
前述の通り、'
はHTML 4.01の標準では定義されていませんでした。XMLやXHTMLでは標準でしたが、HTML5で初めてHTMLの標準として導入されました。そのため、HTML5以前の仕様に準拠している、またはその仕様を厳密に解釈する古いブラウザ(特にIE8以前)では、'
を認識せず、そのまま文字列として表示してしまう、あるいは表示が崩れるといった問題が発生しました。
一方、'
のような数値文字参照は、HTMLのバージョンに関わらず、Unicodeコードポイントに基づいて文字を表現するため、ほとんどのブラウザで広くサポートされています。これは、ブラウザが文字の名前を知らなくても、その数値表現を解釈できるためです。
Go言語のhtml
パッケージとtext/template
パッケージ
html
パッケージ: HTMLドキュメントのパース、レンダリング、エスケープなど、HTML関連の低レベルな処理を提供します。text/template
パッケージ: テキストベースのテンプレートエンジンを提供し、HTML出力にも利用されます。このパッケージには、HTMLエスケープを行うHTMLEscape
関数が含まれています。
このコミット以前は、html
パッケージが'
と"
を使用し、text/template
パッケージが'
と"
を使用していたため、同じGo言語の標準ライブラリ内でエスケープの挙動が異なっていました。
Go言語のIssueトラッカー (#3489)
Go言語のIssueトラッカーは、バグ報告、機能要望、議論などを管理するためのシステムです。Fixes #3489
という記述は、このコミットがGo言語のIssue #3489で報告された問題を解決したことを意味します。Issue #3489は、まさにIE8における'
の互換性問題に関するものでした。
技術的詳細
このコミットでは、Go言語の以下のファイルが変更されています。
src/pkg/exp/html/escape.go
src/pkg/exp/html/render_test.go
src/pkg/exp/html/token_test.go
src/pkg/html/escape.go
src/pkg/net/http/server.go
src/pkg/text/template/funcs.go
主要な変更点は、シングルクォート('
)とダブルクォート("
)のエスケープ処理です。
-
html
およびexp/html
パッケージのエスケープ処理の変更:'
のエスケープを'
から'
に変更。コメントで「'
は'
よりも短く、apos
はHTML5までHTMLにはなかった」と説明されています。"
のエスケープを"
から"
に変更。コメントで「"
は"
よりも短い」と説明されています。EscapeString
関数のコメントも更新され、エスケープされる文字が「amp, apos, lt, gt and quot」から「<, >, &, ' and "」と、より直接的な表記に変更されています。
-
net/http/server.go
の変更:htmlReplacer
という文字列置換マップが更新され、"
と'
のエスケープが同様に"
と'
に変更されています。ここでも同様のコメントが追加されています。
-
text/template/funcs.go
の変更:htmlApos
の定義に関するコメントが更新され、「'
は'
よりも短く、apos
はHTML5までHTMLにはなかった」という説明が追加されています。これは、text/template
パッケージが既に'
を使用していたため、その理由を明確にするものです。
-
テストファイルの更新:
src/pkg/exp/html/render_test.go
とsrc/pkg/exp/html/token_test.go
では、エスケープ結果の期待値が"
や'
から"
や'
に更新されています。これにより、新しいエスケープロジックが正しく機能することを確認しています。src/pkg/exp/html/token_test.go
のTestUnescapeEscape
関数では、テストロジックが改善され、UnescapeString(EscapeString(s))
の結果が元の文字列s
と一致するかどうかをより厳密にチェックするようになっています。
これらの変更により、Go言語のHTMLエスケープ処理は、古いブラウザとの互換性を向上させ、かつ標準ライブラリ全体での一貫性を確保しています。数値文字参照は、文字実体参照よりも一般的に互換性が高く、またバイト数も短くなる場合があるため、パフォーマンス面でもわずかながらメリットがある可能性があります。
コアとなるコードの変更箇所
src/pkg/exp/html/escape.go
および src/pkg/html/escape.go
--- a/src/pkg/exp/html/escape.go
+++ b/src/pkg/exp/html/escape.go
@@ -205,13 +205,15 @@ func escape(w writer, s string) error {
case '&':
esc = "&"
case '\'':
- esc = "'"
+ // "'" is shorter than "'" and apos was not in HTML until HTML5.
+ esc = "'"
case '<':
esc = "<"
case '>':
esc = ">"
case '"':
- esc = """
+ // """ is shorter than """.
+ esc = """
default:
panic("unrecognized escape character")
}
@@ -226,7 +228,7 @@ func escape(w writer, s string) error {
}
// EscapeString escapes special characters like "<" to become "<". It
-// escapes only five such characters: amp, apos, lt, gt and quot.
+// escapes only five such characters: <, >, &, ' and ".
// UnescapeString(EscapeString(s)) == s always holds, but the converse isn't
// always true.
func EscapeString(s string) string {
src/pkg/net/http/server.go
--- a/src/pkg/net/http/server.go
+++ b/src/pkg/net/http/server.go
@@ -785,8 +785,10 @@ var htmlReplacer = strings.NewReplacer(
"&", "&",
"<", "<",
">", ">",
- `"`, """,
- "'", "'",
+ // """ is shorter than """.
+ `"`, """,
+ // "'" is shorter than "'" and apos was not in HTML until HTML5.
+ "'", "'",
)
func htmlEscape(s string) string {
コアとなるコードの解説
上記のコードスニペットは、Go言語のHTMLエスケープ処理における核心的な変更を示しています。
-
escape
関数内の変更 (src/pkg/exp/html/escape.go
およびsrc/pkg/html/escape.go
):- この関数は、HTML特殊文字をエスケープするための主要なロジックを含んでいます。
case '\'':
のブロックでは、シングルクォート('
)が検出された場合のエスケープ文字列が'
から'
に変更されています。追加されたコメントは、この変更の理由として「'
は'
よりも短く、apos
はHTML5までHTMLにはなかった」ことを明確にしています。これは、古いブラウザとの互換性向上と、エスケープ結果のバイト数削減という二重の目的を示唆しています。case '"':
のブロックでは、ダブルクォート("
)が検出された場合のエスケープ文字列が"
から"
に変更されています。同様に、「"
は"
よりも短い」というコメントが追加されており、バイト数削減の意図が伺えます。EscapeString
関数のコメントも更新され、エスケープされる文字がより直接的な表記に変更されています。これは、ユーザーや開発者に対して、この関数が具体的にどの文字をエスケープするのかを明確に伝えるための改善です。
-
htmlReplacer
の変更 (src/pkg/net/http/server.go
):net/http
パッケージ内のhtmlReplacer
は、HTTPサーバーがHTMLコンテンツを生成する際に使用される文字列置換マップです。- ここでも、ダブルクォートとシングルクォートのエスケープ定義が、それぞれ
"
から"
、'
から'
に変更されています。これにより、net/http
パッケージも新しいエスケープ規則に準拠し、Go言語全体でのHTMLエスケープの一貫性が保たれます。コメントもescape.go
と同様の理由を説明しています。
これらの変更は、Go言語のHTMLエスケープ処理をより堅牢で互換性の高いものにし、特に古いブラウザ環境での表示問題を回避することを目的としています。また、数値文字参照を使用することで、エスケープされた文字列の長さが短くなる可能性があり、これはわずかながらパフォーマンス上の利点にもなり得ます。
関連リンク
- Go言語 Issue #3489: https://github.com/golang/go/issues/3489
- Go言語 Change-ID 5992071: https://golang.org/cl/5992071 (Gerrit Code Review)
参考にした情報源リンク
- HTML Standard - Named character references: https://html.spec.whatwg.org/multipage/named-characters.html
- HTML Standard - Numeric character references: https://html.spec.whatwg.org/multipage/syntax.html#numeric-character-reference
- MDN Web Docs - HTML entities: https://developer.mozilla.org/en-US/docs/Glossary/HTML_entity
- Stack Overflow - Why is ' not working in HTML?: https://stackoverflow.com/questions/1091945/why-is-apos-not-working-in-html
- W3C - HTML 4.01 Specification: https://www.w3.org/TR/html401/
- W3C - HTML5 Specification: https://www.w3.org/TR/html5/
- GoDoc -
html
package: https://pkg.go.dev/html - GoDoc -
text/template
package: https://pkg.go.dev/text/template - GoDoc -
net/http
package: https://pkg.go.dev/net/http