github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/html/template/error.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package template
     6  
     7  import (
     8  	"github.com/shogo82148/std/text/template/parse"
     9  )
    10  
    11  // Errorは、テンプレートのエスケープ処理中に遭遇した問題を説明します。
    12  type Error struct {
    13  	// ErrorCodeはエラーの種類を説明します。
    14  	ErrorCode ErrorCode
    15  	// Nodeは問題を引き起こしたノードです(もし分かる場合)。
    16  	// nilでない場合、NameとLineを上書きします。
    17  	Node parse.Node
    18  	// Nameはエラーが発生したテンプレートの名前です。
    19  	Name string
    20  	// Lineはテンプレートソース内のエラーの行番号、または0です。
    21  	Line int
    22  	// Descriptionは問題の人間が読める説明です。
    23  	Description string
    24  }
    25  
    26  // ErrorCodeはエラーの種類を表すコードです。
    27  type ErrorCode int
    28  
    29  // テンプレートをエスケープする際に現れる各エラーに対してコードを定義していますが、
    30  // エスケープされたテンプレートは実行時にも失敗する可能性があります。
    31  //
    32  // 出力: "ZgotmplZ"
    33  // 例:
    34  //
    35  //	<img src="{{.X}}">
    36  //	ここで {{.X}} は `javascript:...` に評価されます
    37  //
    38  // 議論:
    39  //
    40  //	"ZgotmplZ" は、実行時に安全でないコンテンツがCSSまたはURLのコンテキストに到達したことを示す特別な値です。
    41  //	例の出力は
    42  //	  <img src="#ZgotmplZ">
    43  //	になります。
    44  //	データが信頼できるソースから来る場合は、フィルタリングから免除するためにコンテンツタイプを使用します:URL(`javascript:...`)。
    45  const (
    46  	// OKはエラーがないことを示します。
    47  	OK ErrorCode = iota
    48  
    49  	// ErrAmbigContext: "...はURL内の曖昧なコンテキストに現れます"
    50  	// 例:
    51  	//   <a href="
    52  	//      {{if .C}}
    53  	//        /path/
    54  	//      {{else}}
    55  	//        /search?q=
    56  	//      {{end}}
    57  	//      {{.X}}
    58  	//   ">
    59  	// 議論:
    60  	//   {{.X}}は曖昧なURLコンテキストにあります。なぜなら、{{.C}}によって、
    61  	//   URLの接尾辞かクエリパラメータのどちらかになる可能性があるからです。
    62  	//   {{.X}}を条件の中に移動すると曖昧さがなくなります:
    63  	//   <a href="{{if .C}}/path/{{.X}}{{else}}/search?q={{.X}}">
    64  	ErrAmbigContext
    65  
    66  	// ErrBadHTML: "スペース、属性名、またはタグの終わりを期待していましたが、...が得られました",
    67  	//   "...は引用符で囲まれていない属性内にあります", "...は属性名内にあります"
    68  	// 例:
    69  	//   <a href = /search?q=foo>
    70  	//   <href=foo>
    71  	//   <form na<e=...>
    72  	//   <option selected<
    73  	// 議論:
    74  	//   これは、HTML要素のタイプミスが原因であることが多いですが、一部のルーンは、
    75  	//   パーサーの曖昧さを引き起こす可能性があるため、タグ名、属性名、引用符で囲まれていない属性値で禁止されています。
    76  	//   すべての属性を引用符で囲むのが最善の方針です。
    77  	ErrBadHTML
    78  
    79  	// ErrBranchEnd: "{{if}}の分岐が異なるコンテキストで終わります"
    80  	// 例:
    81  	//   {{if .C}}<a href="{{end}}{{.X}}
    82  	// 議論:
    83  	//   パッケージhtml/templateは、{{if}}、{{range}}、または{{with}}を通じて各パスを静的に調べ、
    84  	//   その後のパイプラインをエスケープします。例は曖昧です。なぜなら、{{.X}}はHTMLテキストノードであるか、
    85  	//   HTML属性のURLプレフィックスである可能性があるからです。{{.X}}のコンテキストは、それをどのようにエスケープするかを
    86  	//   理解するために使用されますが、そのコンテキストは実行時の{{.C}}の値に依存し、それは静的には知られていません。
    87  	//
    88  	//   問題は通常、引用符や角括弧が欠けているなどの問題であり、または、2つのコンテキストをif、range、withの
    89  	//   異なる分岐にリファクタリングすることで回避できます。問題が空であるべきではないコレクションに対する{{range}}にある場合、
    90  	//   ダミーの{{else}}を追加すると役立つことがあります。
    91  	ErrBranchEnd
    92  
    93  	// ErrEndContext: "...は非テキストコンテキストで終わります: ..."
    94  	// 例:
    95  	//   <div
    96  	//   <div title="閉じ引用符なし>
    97  	//   <script>f()
    98  	// 議論:
    99  	//   実行されたテンプレートはHTMLのDocumentFragmentを生成するべきです。
   100  	//   閉じタグなしで終わるテンプレートはこのエラーを引き起こします。
   101  	//   HTMLコンテキストで使用すべきでないテンプレート、または不完全なFragmentを生成するテンプレートは、
   102  	//   直接実行すべきではありません。
   103  	//
   104  	//   {{define "main"}} <script>{{template "helper"}}</script> {{end}}
   105  	//   {{define "helper"}} document.write(' <div title=" ') {{end}}
   106  	//
   107  	//   "helper"は有効なドキュメントフラグメントを生成しないため、直接実行すべきではありません。
   108  	ErrEndContext
   109  
   110  	// ErrNoSuchTemplate: "そのようなテンプレートは存在しません ..."
   111  	// 例:
   112  	//   {{define "main"}}<div {{template "attrs"}}>{{end}}
   113  	//   {{define "attrs"}}href="{{.URL}}"{{end}}
   114  	// 議論:
   115  	//   パッケージhtml/templateはテンプレート呼び出しを見てコンテキストを計算します。
   116  	//   ここでは、"attrs"の{{.URL}}は"main"から呼び出されたときにURLとして扱われなければなりませんが、
   117  	//   "main"が解析されたときに"attrs"が定義されていない場合、このエラーが発生します。
   118  	ErrNoSuchTemplate
   119  
   120  	// ErrOutputContext: "テンプレート...の出力コンテキストを計算できません"
   121  	// 例:
   122  	//   {{define "t"}}{{if .T}}{{template "t" .T}}{{end}}{{.H}}",{{end}}
   123  	// 議論:
   124  	//   再帰的なテンプレートは、開始したときと同じコンテキストで終わらないため、
   125  	//   信頼性のある出力コンテキストを計算することはできません。
   126  	//   名前付きテンプレートのタイプミスを探してみてください。
   127  	//   もしテンプレートが名前付きの開始コンテキストで呼び出されるべきでないなら、
   128  	//   予期しないコンテキストでそのテンプレートへの呼び出しを探してみてください。
   129  	//   再帰的なテンプレートを再帰的でないようにリファクタリングすることも考えてみてください。
   130  	ErrOutputContext
   131  
   132  	// ErrPartialCharset: "未完成のJS正規表現文字セットが...に存在します"
   133  	// 例:
   134  	//     <script>var pattern = /foo[{{.Chars}}]/</script>
   135  	// 議論:
   136  	//   パッケージhtml/templateは、正規表現リテラルの文字セットへの補間をサポートしていません。
   137  	ErrPartialCharset
   138  
   139  	// ErrPartialEscape: "未完成のエスケープシーケンスが...に存在します"
   140  	// 例:
   141  	//   <script>alert("\{{.X}}")</script>
   142  	// 議論:
   143  	//   パッケージhtml/templateは、バックスラッシュの後に続くアクションをサポートしていません。
   144  	//   これは通常、エラーであり、より良い解決策があります。例えば、
   145  	//     <script>alert("{{.X}}")</script>
   146  	//   は動作するはずで、もし{{.X}}が"xA0"のような部分的なエスケープシーケンスであれば、
   147  	//   全体を安全なコンテンツとしてマークします:JSStr(`\xA0`)
   148  	ErrPartialEscape
   149  
   150  	// ErrRangeLoopReentry: "範囲ループの再入時に: ..."
   151  	// 例:
   152  	//   <script>var x = [{{range .}}'{{.}},{{end}}]</script>
   153  	// 議論:
   154  	//   範囲を通じた反復が、以前のパスと異なるコンテキストで終わるような場合、単一のコンテキストは存在しません。
   155  	//   例では、引用符が欠けているため、{{.}}がJS文字列の内部にあるのか、JS値のコンテキストにあるのかが明確ではありません。
   156  	//   2回目の反復では、次のようなものが生成されます。
   157  	//
   158  	//     <script>var x = ['firstValue,'secondValue]</script>
   159  	ErrRangeLoopReentry
   160  
   161  	// ErrSlashAmbig: "'/'は除算または正規表現を開始する可能性があります"
   162  	// 例:
   163  	//   <script>
   164  	//     {{if .C}}var x = 1{{end}}
   165  	//     /-{{.N}}/i.test(x) ? doThis : doThat();
   166  	//   </script>
   167  	// 議論:
   168  	//   上記の例では、最初の'/'が数学的な除算演算子である`var x = 1/-2/i.test(s)...`を生成するか、
   169  	//   最初の'/'が正規表現リテラルを開始する`/-2/i.test(s)`を生成する可能性があります。
   170  	//   分岐内のセミコロンが欠けていないか確認し、どちらの解釈を意図しているか明確にするために
   171  	//   括弧を追加することを検討してみてください。
   172  	ErrSlashAmbig
   173  
   174  	// ErrPredefinedEscaper: "テンプレートで禁止されている事前定義されたエスケーパー..."
   175  	// 例:
   176  	//   <div class={{. | html}}>Hello<div>
   177  	// 議論:
   178  	//   パッケージhtml/templateは、すべてのパイプラインをコンテキストに応じてエスケープして、
   179  	//   コードインジェクションに対して安全なHTML出力を生成します。事前定義されたエスケーパー"html"または"urlquery"を
   180  	//   使用してパイプライン出力を手動でエスケープすることは不要であり、Go 1.8以前ではエスケープされたパイプライン出力の
   181  	//   正確さや安全性に影響を与える可能性があります。
   182  	//
   183  	//   ほとんどの場合、例えば上記の例のような場合、このエラーはパイプラインから事前定義されたエスケーパーを単純に削除し、
   184  	//   コンテキスト自動エスケーパーがパイプラインのエスケープを処理することで解決できます。他の場合、事前定義されたエスケーパーが
   185  	//   パイプラインの中間に存在し、後続のコマンドがエスケープされた入力を期待する場合、例えば
   186  	//     {{.X | html | makeALink}}
   187  	//   ここでmakeALinkは
   188  	//     return `<a href="`+input+`">link</a>`
   189  	//   を行う場合、周囲のテンプレートをリファクタリングしてコンテキスト自動エスケーパーを利用するように考えてみてください。つまり、
   190  	//     <a href="{{.X}}">link</a>
   191  	//
   192  	//   Go 1.9以降への移行を容易にするために、"html"と"urlquery"はパイプラインの最後のコマンドとして引き続き許可されます。
   193  	//   ただし、パイプラインが引用符で囲まれていない属性値のコンテキストで発生する場合、"html"は禁止されます。
   194  	//   新しいテンプレートでは"html"と"urlquery"を全く使用しないようにしてください。
   195  	ErrPredefinedEscaper
   196  
   197  	// ErrJSTemplate: "...はJSテンプレートリテラル内に存在します"
   198  	// 例:
   199  	//     <script>var tmpl = `{{.Interp}}`</script>
   200  	// 議論:
   201  	//   パッケージhtml/templateは、JSテンプレートリテラル内のアクションをサポートしていません。
   202  	//
   203  	// Deprecated: JSテンプレートリテラル内にアクションが存在する場合、ErrJSTemplateはもはや返されません。
   204  	// JSテンプレートリテラル内のアクションは、現在予想通りにエスケープされます。
   205  	ErrJSTemplate
   206  )
   207  
   208  func (e *Error) Error() string