1
2
3
4
5 package template
6
7 import (
8 "errors"
9 "fmt"
10 "io"
11 "net/url"
12 "reflect"
13 "strings"
14 "sync"
15 "unicode"
16 "unicode/utf8"
17 )
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 type FuncMap map[string]any
34
35
36
37
38
39 func builtins() FuncMap {
40 return FuncMap{
41 "and": and,
42 "call": emptyCall,
43 "html": HTMLEscaper,
44 "index": index,
45 "slice": slice,
46 "js": JSEscaper,
47 "len": length,
48 "not": not,
49 "or": or,
50 "print": fmt.Sprint,
51 "printf": fmt.Sprintf,
52 "println": fmt.Sprintln,
53 "urlquery": URLQueryEscaper,
54
55
56 "eq": eq,
57 "ge": ge,
58 "gt": gt,
59 "le": le,
60 "lt": lt,
61 "ne": ne,
62 }
63 }
64
65
66 var builtinFuncs = sync.OnceValue(func() map[string]reflect.Value {
67 funcMap := builtins()
68 m := make(map[string]reflect.Value, len(funcMap))
69 addValueFuncs(m, funcMap)
70 return m
71 })
72
73
74 func addValueFuncs(out map[string]reflect.Value, in FuncMap) {
75 for name, fn := range in {
76 if !goodName(name) {
77 panic(fmt.Errorf("function name %q is not a valid identifier", name))
78 }
79 v := reflect.ValueOf(fn)
80 if v.Kind() != reflect.Func {
81 panic("value for " + name + " not a function")
82 }
83 if err := goodFunc(name, v.Type()); err != nil {
84 panic(err)
85 }
86 out[name] = v
87 }
88 }
89
90
91
92 func addFuncs(out, in FuncMap) {
93 for name, fn := range in {
94 out[name] = fn
95 }
96 }
97
98
99 func goodFunc(name string, typ reflect.Type) error {
100
101 switch numOut := typ.NumOut(); {
102 case numOut == 1:
103 return nil
104 case numOut == 2 && typ.Out(1) == errorType:
105 return nil
106 case numOut == 2:
107 return fmt.Errorf("invalid function signature for %s: second return value should be error; is %s", name, typ.Out(1))
108 default:
109 return fmt.Errorf("function %s has %d return values; should be 1 or 2", name, typ.NumOut())
110 }
111 }
112
113
114 func goodName(name string) bool {
115 if name == "" {
116 return false
117 }
118 for i, r := range name {
119 switch {
120 case r == '_':
121 case i == 0 && !unicode.IsLetter(r):
122 return false
123 case !unicode.IsLetter(r) && !unicode.IsDigit(r):
124 return false
125 }
126 }
127 return true
128 }
129
130
131 func findFunction(name string, tmpl *Template) (v reflect.Value, isBuiltin, ok bool) {
132 if tmpl != nil && tmpl.common != nil {
133 tmpl.muFuncs.RLock()
134 defer tmpl.muFuncs.RUnlock()
135 if fn := tmpl.execFuncs[name]; fn.IsValid() {
136 return fn, false, true
137 }
138 }
139 if fn := builtinFuncs()[name]; fn.IsValid() {
140 return fn, true, true
141 }
142 return reflect.Value{}, false, false
143 }
144
145
146
147 func prepareArg(value reflect.Value, argType reflect.Type) (reflect.Value, error) {
148 if !value.IsValid() {
149 if !canBeNil(argType) {
150 return reflect.Value{}, fmt.Errorf("value is nil; should be of type %s", argType)
151 }
152 value = reflect.Zero(argType)
153 }
154 if value.Type().AssignableTo(argType) {
155 return value, nil
156 }
157 if intLike(value.Kind()) && intLike(argType.Kind()) && value.Type().ConvertibleTo(argType) {
158 value = value.Convert(argType)
159 return value, nil
160 }
161 return reflect.Value{}, fmt.Errorf("value has type %s; should be %s", value.Type(), argType)
162 }
163
164 func intLike(typ reflect.Kind) bool {
165 switch typ {
166 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
167 return true
168 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
169 return true
170 }
171 return false
172 }
173
174
175 func indexArg(index reflect.Value, cap int) (int, error) {
176 var x int64
177 switch index.Kind() {
178 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
179 x = index.Int()
180 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
181 x = int64(index.Uint())
182 case reflect.Invalid:
183 return 0, fmt.Errorf("cannot index slice/array with nil")
184 default:
185 return 0, fmt.Errorf("cannot index slice/array with type %s", index.Type())
186 }
187 if x < 0 || int(x) < 0 || int(x) > cap {
188 return 0, fmt.Errorf("index out of range: %d", x)
189 }
190 return int(x), nil
191 }
192
193
194
195
196
197
198 func index(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {
199 item = indirectInterface(item)
200 if !item.IsValid() {
201 return reflect.Value{}, fmt.Errorf("index of untyped nil")
202 }
203 for _, index := range indexes {
204 index = indirectInterface(index)
205 var isNil bool
206 if item, isNil = indirect(item); isNil {
207 return reflect.Value{}, fmt.Errorf("index of nil pointer")
208 }
209 switch item.Kind() {
210 case reflect.Array, reflect.Slice, reflect.String:
211 x, err := indexArg(index, item.Len())
212 if err != nil {
213 return reflect.Value{}, err
214 }
215 item = item.Index(x)
216 case reflect.Map:
217 index, err := prepareArg(index, item.Type().Key())
218 if err != nil {
219 return reflect.Value{}, err
220 }
221 if x := item.MapIndex(index); x.IsValid() {
222 item = x
223 } else {
224 item = reflect.Zero(item.Type().Elem())
225 }
226 case reflect.Invalid:
227
228 panic("unreachable")
229 default:
230 return reflect.Value{}, fmt.Errorf("can't index item of type %s", item.Type())
231 }
232 }
233 return item, nil
234 }
235
236
237
238
239
240
241
242 func slice(item reflect.Value, indexes ...reflect.Value) (reflect.Value, error) {
243 item = indirectInterface(item)
244 if !item.IsValid() {
245 return reflect.Value{}, fmt.Errorf("slice of untyped nil")
246 }
247 var isNil bool
248 if item, isNil = indirect(item); isNil {
249 return reflect.Value{}, fmt.Errorf("slice of nil pointer")
250 }
251 if len(indexes) > 3 {
252 return reflect.Value{}, fmt.Errorf("too many slice indexes: %d", len(indexes))
253 }
254 var cap int
255 switch item.Kind() {
256 case reflect.String:
257 if len(indexes) == 3 {
258 return reflect.Value{}, fmt.Errorf("cannot 3-index slice a string")
259 }
260 cap = item.Len()
261 case reflect.Array, reflect.Slice:
262 cap = item.Cap()
263 default:
264 return reflect.Value{}, fmt.Errorf("can't slice item of type %s", item.Type())
265 }
266
267 idx := [3]int{0, item.Len()}
268 for i, index := range indexes {
269 x, err := indexArg(index, cap)
270 if err != nil {
271 return reflect.Value{}, err
272 }
273 idx[i] = x
274 }
275
276 if idx[0] > idx[1] {
277 return reflect.Value{}, fmt.Errorf("invalid slice index: %d > %d", idx[0], idx[1])
278 }
279 if len(indexes) < 3 {
280 return item.Slice(idx[0], idx[1]), nil
281 }
282
283 if idx[1] > idx[2] {
284 return reflect.Value{}, fmt.Errorf("invalid slice index: %d > %d", idx[1], idx[2])
285 }
286 return item.Slice3(idx[0], idx[1], idx[2]), nil
287 }
288
289
290
291
292 func length(item reflect.Value) (int, error) {
293 item, isNil := indirect(item)
294 if isNil {
295 return 0, fmt.Errorf("len of nil pointer")
296 }
297 switch item.Kind() {
298 case reflect.Array, reflect.Chan, reflect.Map, reflect.Slice, reflect.String:
299 return item.Len(), nil
300 }
301 return 0, fmt.Errorf("len of type %s", item.Type())
302 }
303
304
305
306 func emptyCall(fn reflect.Value, args ...reflect.Value) reflect.Value {
307 panic("unreachable")
308 }
309
310
311
312 func call(name string, fn reflect.Value, args ...reflect.Value) (reflect.Value, error) {
313 fn = indirectInterface(fn)
314 if !fn.IsValid() {
315 return reflect.Value{}, fmt.Errorf("call of nil")
316 }
317 typ := fn.Type()
318 if typ.Kind() != reflect.Func {
319 return reflect.Value{}, fmt.Errorf("non-function %s of type %s", name, typ)
320 }
321
322 if err := goodFunc(name, typ); err != nil {
323 return reflect.Value{}, err
324 }
325 numIn := typ.NumIn()
326 var dddType reflect.Type
327 if typ.IsVariadic() {
328 if len(args) < numIn-1 {
329 return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want at least %d", name, len(args), numIn-1)
330 }
331 dddType = typ.In(numIn - 1).Elem()
332 } else {
333 if len(args) != numIn {
334 return reflect.Value{}, fmt.Errorf("wrong number of args for %s: got %d want %d", name, len(args), numIn)
335 }
336 }
337 argv := make([]reflect.Value, len(args))
338 for i, arg := range args {
339 arg = indirectInterface(arg)
340
341 argType := dddType
342 if !typ.IsVariadic() || i < numIn-1 {
343 argType = typ.In(i)
344 }
345
346 var err error
347 if argv[i], err = prepareArg(arg, argType); err != nil {
348 return reflect.Value{}, fmt.Errorf("arg %d: %w", i, err)
349 }
350 }
351 return safeCall(fn, argv)
352 }
353
354
355
356 func safeCall(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) {
357 defer func() {
358 if r := recover(); r != nil {
359 if e, ok := r.(error); ok {
360 err = e
361 } else {
362 err = fmt.Errorf("%v", r)
363 }
364 }
365 }()
366
367
368
369 if f, ok := reflect.TypeAssert[func(...any) string](fun); ok {
370 anyArgs := make([]any, len(args))
371 for i, arg := range args {
372 anyArgs[i] = arg.Interface()
373 }
374 return reflect.ValueOf(f(anyArgs...)), nil
375 }
376
377 switch fun.Type() {
378 case eqFuncType:
379 f, _ := reflect.TypeAssert[func(reflect.Value, ...reflect.Value) (bool, error)](fun)
380 r, err := f(unwrapArg(args[0]), unwrapArgs(args[1:])...)
381 return reflect.ValueOf(r), err
382 case notFuncType:
383 f, _ := reflect.TypeAssert[func(reflect.Value) bool](fun)
384 return reflect.ValueOf(f(unwrapArg(args[0]))), nil
385 case cmpFuncType:
386 f, _ := reflect.TypeAssert[func(reflect.Value, reflect.Value) (bool, error)](fun)
387 r, err := f(unwrapArg(args[0]), unwrapArg(args[1]))
388 return reflect.ValueOf(r), err
389 case printfFuncType:
390 f, _ := reflect.TypeAssert[func(string, ...any) string](fun)
391 anyArgs := make([]any, len(args)-1)
392 for i, arg := range args[1:] {
393 anyArgs[i] = arg.Interface()
394 }
395 return reflect.ValueOf(f(args[0].String(), anyArgs...)), nil
396 }
397 ret := fun.Call(args)
398 if len(ret) == 2 && !ret[1].IsNil() {
399 return ret[0], ret[1].Interface().(error)
400 }
401 return ret[0], nil
402 }
403
404 var (
405 eqFuncType = reflect.TypeFor[func(reflect.Value, ...reflect.Value) (bool, error)]()
406 notFuncType = reflect.TypeFor[func(reflect.Value) bool]()
407 cmpFuncType = reflect.TypeFor[func(reflect.Value, reflect.Value) (bool, error)]()
408 printfFuncType = reflect.TypeFor[func(string, ...any) string]()
409 )
410
411
412
413 func unwrapArg(arg reflect.Value) reflect.Value {
414 v, ok := reflect.TypeAssert[reflect.Value](arg)
415 if !ok {
416 panic("text/template: argument is not a wrapped reflect.Value")
417 }
418 return v
419 }
420
421 func unwrapArgs(args []reflect.Value) []reflect.Value {
422 vs := make([]reflect.Value, len(args))
423 for i, arg := range args {
424 vs[i] = unwrapArg(arg)
425 }
426 return vs
427 }
428
429
430
431 func truth(arg reflect.Value) bool {
432 t, _ := isTrue(indirectInterface(arg))
433 return t
434 }
435
436
437
438 func and(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
439 panic("unreachable")
440 }
441
442
443
444 func or(arg0 reflect.Value, args ...reflect.Value) reflect.Value {
445 panic("unreachable")
446 }
447
448
449 func not(arg reflect.Value) bool {
450 return !truth(arg)
451 }
452
453
454
455
456
457 var (
458 errBadComparisonType = errors.New("invalid type for comparison")
459 errNoComparison = errors.New("missing argument for comparison")
460 )
461
462 type kind int
463
464 const (
465 invalidKind kind = iota
466 boolKind
467 complexKind
468 intKind
469 floatKind
470 stringKind
471 uintKind
472 )
473
474 func basicKind(v reflect.Value) (kind, error) {
475 switch v.Kind() {
476 case reflect.Bool:
477 return boolKind, nil
478 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
479 return intKind, nil
480 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
481 return uintKind, nil
482 case reflect.Float32, reflect.Float64:
483 return floatKind, nil
484 case reflect.Complex64, reflect.Complex128:
485 return complexKind, nil
486 case reflect.String:
487 return stringKind, nil
488 }
489 return invalidKind, errBadComparisonType
490 }
491
492
493 func isNil(v reflect.Value) bool {
494 if !v.IsValid() {
495 return true
496 }
497 switch v.Kind() {
498 case reflect.Chan, reflect.Func, reflect.Interface, reflect.Map, reflect.Pointer, reflect.Slice:
499 return v.IsNil()
500 }
501 return false
502 }
503
504
505
506 func canCompare(v1, v2 reflect.Value) bool {
507 k1 := v1.Kind()
508 k2 := v2.Kind()
509 if k1 == k2 {
510 return true
511 }
512
513 return k1 == reflect.Invalid || k2 == reflect.Invalid
514 }
515
516
517 func eq(arg1 reflect.Value, arg2 ...reflect.Value) (bool, error) {
518 arg1 = indirectInterface(arg1)
519 if len(arg2) == 0 {
520 return false, errNoComparison
521 }
522 k1, _ := basicKind(arg1)
523 for _, arg := range arg2 {
524 arg = indirectInterface(arg)
525 k2, _ := basicKind(arg)
526 truth := false
527 if k1 != k2 {
528
529 switch {
530 case k1 == intKind && k2 == uintKind:
531 truth = arg1.Int() >= 0 && uint64(arg1.Int()) == arg.Uint()
532 case k1 == uintKind && k2 == intKind:
533 truth = arg.Int() >= 0 && arg1.Uint() == uint64(arg.Int())
534 default:
535 if arg1.IsValid() && arg.IsValid() {
536 return false, fmt.Errorf("incompatible types for comparison: %v and %v", arg1.Type(), arg.Type())
537 }
538 }
539 } else {
540 switch k1 {
541 case boolKind:
542 truth = arg1.Bool() == arg.Bool()
543 case complexKind:
544 truth = arg1.Complex() == arg.Complex()
545 case floatKind:
546 truth = arg1.Float() == arg.Float()
547 case intKind:
548 truth = arg1.Int() == arg.Int()
549 case stringKind:
550 truth = arg1.String() == arg.String()
551 case uintKind:
552 truth = arg1.Uint() == arg.Uint()
553 default:
554 if !canCompare(arg1, arg) {
555 return false, fmt.Errorf("non-comparable types %s: %v, %s: %v", arg1, arg1.Type(), arg.Type(), arg)
556 }
557 if isNil(arg1) || isNil(arg) {
558 truth = isNil(arg) == isNil(arg1)
559 } else {
560 if !arg.Type().Comparable() {
561 return false, fmt.Errorf("non-comparable type %s: %v", arg, arg.Type())
562 }
563 truth = arg1.Interface() == arg.Interface()
564 }
565 }
566 }
567 if truth {
568 return true, nil
569 }
570 }
571 return false, nil
572 }
573
574
575 func ne(arg1, arg2 reflect.Value) (bool, error) {
576
577 equal, err := eq(arg1, arg2)
578 return !equal, err
579 }
580
581
582 func lt(arg1, arg2 reflect.Value) (bool, error) {
583 arg1 = indirectInterface(arg1)
584 k1, err := basicKind(arg1)
585 if err != nil {
586 return false, err
587 }
588 arg2 = indirectInterface(arg2)
589 k2, err := basicKind(arg2)
590 if err != nil {
591 return false, err
592 }
593 truth := false
594 if k1 != k2 {
595
596 switch {
597 case k1 == intKind && k2 == uintKind:
598 truth = arg1.Int() < 0 || uint64(arg1.Int()) < arg2.Uint()
599 case k1 == uintKind && k2 == intKind:
600 truth = arg2.Int() >= 0 && arg1.Uint() < uint64(arg2.Int())
601 default:
602 return false, fmt.Errorf("incompatible types for comparison: %v and %v", arg1.Type(), arg2.Type())
603 }
604 } else {
605 switch k1 {
606 case boolKind, complexKind:
607 return false, errBadComparisonType
608 case floatKind:
609 truth = arg1.Float() < arg2.Float()
610 case intKind:
611 truth = arg1.Int() < arg2.Int()
612 case stringKind:
613 truth = arg1.String() < arg2.String()
614 case uintKind:
615 truth = arg1.Uint() < arg2.Uint()
616 default:
617 panic("invalid kind")
618 }
619 }
620 return truth, nil
621 }
622
623
624 func le(arg1, arg2 reflect.Value) (bool, error) {
625
626 lessThan, err := lt(arg1, arg2)
627 if lessThan || err != nil {
628 return lessThan, err
629 }
630 return eq(arg1, arg2)
631 }
632
633
634 func gt(arg1, arg2 reflect.Value) (bool, error) {
635
636 lessOrEqual, err := le(arg1, arg2)
637 if err != nil {
638 return false, err
639 }
640 return !lessOrEqual, nil
641 }
642
643
644 func ge(arg1, arg2 reflect.Value) (bool, error) {
645
646 lessThan, err := lt(arg1, arg2)
647 if err != nil {
648 return false, err
649 }
650 return !lessThan, nil
651 }
652
653
654
655 var (
656 htmlQuot = []byte(""")
657 htmlApos = []byte("'")
658 htmlAmp = []byte("&")
659 htmlLt = []byte("<")
660 htmlGt = []byte(">")
661 htmlNull = []byte("\uFFFD")
662 )
663
664
665 func HTMLEscape(w io.Writer, b []byte) {
666 last := 0
667 for i, c := range b {
668 var html []byte
669 switch c {
670 case '\000':
671 html = htmlNull
672 case '"':
673 html = htmlQuot
674 case '\'':
675 html = htmlApos
676 case '&':
677 html = htmlAmp
678 case '<':
679 html = htmlLt
680 case '>':
681 html = htmlGt
682 default:
683 continue
684 }
685 w.Write(b[last:i])
686 w.Write(html)
687 last = i + 1
688 }
689 w.Write(b[last:])
690 }
691
692
693 func HTMLEscapeString(s string) string {
694
695 if !strings.ContainsAny(s, "'\"&<>\000") {
696 return s
697 }
698 var b strings.Builder
699 HTMLEscape(&b, []byte(s))
700 return b.String()
701 }
702
703
704
705 func HTMLEscaper(args ...any) string {
706 return HTMLEscapeString(evalArgs(args))
707 }
708
709
710
711 var (
712 jsLowUni = []byte(`\u00`)
713 hex = []byte("0123456789ABCDEF")
714
715 jsBackslash = []byte(`\\`)
716 jsApos = []byte(`\'`)
717 jsQuot = []byte(`\"`)
718 jsLt = []byte(`\u003C`)
719 jsGt = []byte(`\u003E`)
720 jsAmp = []byte(`\u0026`)
721 jsEq = []byte(`\u003D`)
722 )
723
724
725 func JSEscape(w io.Writer, b []byte) {
726 last := 0
727 for i := 0; i < len(b); i++ {
728 c := b[i]
729
730 if !jsIsSpecial(rune(c)) {
731
732 continue
733 }
734 w.Write(b[last:i])
735
736 if c < utf8.RuneSelf {
737
738
739 switch c {
740 case '\\':
741 w.Write(jsBackslash)
742 case '\'':
743 w.Write(jsApos)
744 case '"':
745 w.Write(jsQuot)
746 case '<':
747 w.Write(jsLt)
748 case '>':
749 w.Write(jsGt)
750 case '&':
751 w.Write(jsAmp)
752 case '=':
753 w.Write(jsEq)
754 default:
755 w.Write(jsLowUni)
756 t, b := c>>4, c&0x0f
757 w.Write(hex[t : t+1])
758 w.Write(hex[b : b+1])
759 }
760 } else {
761
762 r, size := utf8.DecodeRune(b[i:])
763 if unicode.IsPrint(r) {
764 w.Write(b[i : i+size])
765 } else {
766 fmt.Fprintf(w, "\\u%04X", r)
767 }
768 i += size - 1
769 }
770 last = i + 1
771 }
772 w.Write(b[last:])
773 }
774
775
776 func JSEscapeString(s string) string {
777
778 if strings.IndexFunc(s, jsIsSpecial) < 0 {
779 return s
780 }
781 var b strings.Builder
782 JSEscape(&b, []byte(s))
783 return b.String()
784 }
785
786 func jsIsSpecial(r rune) bool {
787 switch r {
788 case '\\', '\'', '"', '<', '>', '&', '=':
789 return true
790 }
791 return r < ' ' || utf8.RuneSelf <= r
792 }
793
794
795
796 func JSEscaper(args ...any) string {
797 return JSEscapeString(evalArgs(args))
798 }
799
800
801
802 func URLQueryEscaper(args ...any) string {
803 return url.QueryEscape(evalArgs(args))
804 }
805
806
807
808
809
810
811
812
813 func evalArgs(args []any) string {
814 ok := false
815 var s string
816
817 if len(args) == 1 {
818 s, ok = args[0].(string)
819 }
820 if !ok {
821 for i, arg := range args {
822 a, ok := printableValue(reflect.ValueOf(arg))
823 if ok {
824 args[i] = a
825 }
826 }
827 s = fmt.Sprint(args...)
828 }
829 return s
830 }
831
View as plain text