| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | package replacer
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | import (
 | 
					
						
							| 
									
										
										
										
											2018-11-13 14:20:49 -05:00
										 |  |  | 	"context"
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 	"strconv"
 | 
					
						
							|  |  |  | 	"strings"
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 	"sync"
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 	"time"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-13 14:20:49 -05:00
										 |  |  | 	"github.com/coredns/coredns/plugin/metadata"
 | 
					
						
							| 
									
										
										
										
											2017-09-21 15:15:47 +01:00
										 |  |  | 	"github.com/coredns/coredns/plugin/pkg/dnstest"
 | 
					
						
							| 
									
										
										
										
											2017-02-21 22:51:47 -08:00
										 |  |  | 	"github.com/coredns/coredns/request"
 | 
					
						
							| 
									
										
										
										
											2016-09-07 11:10:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 	"github.com/miekg/dns"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | // Replacer replaces labels for values in strings.
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | type Replacer struct{}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // New makes a new replacer. This only needs to be called once in the setup and
 | 
					
						
							|  |  |  | // then call Replace for each incoming message. A replacer is safe for concurrent use.
 | 
					
						
							|  |  |  | func New() Replacer {
 | 
					
						
							|  |  |  | 	return Replacer{}
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Replace performs a replacement of values on s and returns the string with the replaced values.
 | 
					
						
							|  |  |  | func (r Replacer) Replace(ctx context.Context, state request.Request, rr *dnstest.Recorder, s string) string {
 | 
					
						
							|  |  |  | 	return loadFormat(s).Replace(ctx, state, rr)
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | const (
 | 
					
						
							|  |  |  | 	headerReplacer = "{>"
 | 
					
						
							|  |  |  | 	// EmptyValue is the default empty value.
 | 
					
						
							|  |  |  | 	EmptyValue = "-"
 | 
					
						
							|  |  |  | )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | // labels are all supported labels that can be used in the default Replacer.
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | var labels = map[string]struct{}{
 | 
					
						
							|  |  |  | 	"{type}":   {},
 | 
					
						
							|  |  |  | 	"{name}":   {},
 | 
					
						
							|  |  |  | 	"{class}":  {},
 | 
					
						
							|  |  |  | 	"{proto}":  {},
 | 
					
						
							|  |  |  | 	"{size}":   {},
 | 
					
						
							|  |  |  | 	"{remote}": {},
 | 
					
						
							|  |  |  | 	"{port}":   {},
 | 
					
						
							|  |  |  | 	"{local}":  {},
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 	// Header values.
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 	headerReplacer + "id}":      {},
 | 
					
						
							|  |  |  | 	headerReplacer + "opcode}":  {},
 | 
					
						
							|  |  |  | 	headerReplacer + "do}":      {},
 | 
					
						
							|  |  |  | 	headerReplacer + "bufsize}": {},
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 	// Recorded replacements.
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 	"{rcode}":                  {},
 | 
					
						
							|  |  |  | 	"{rsize}":                  {},
 | 
					
						
							|  |  |  | 	"{duration}":               {},
 | 
					
						
							|  |  |  | 	headerReplacer + "rflags}": {},
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | // appendValue appends the current value of label.
 | 
					
						
							|  |  |  | func appendValue(b []byte, state request.Request, rr *dnstest.Recorder, label string) []byte {
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 	switch label {
 | 
					
						
							|  |  |  | 	// Recorded replacements.
 | 
					
						
							|  |  |  | 	case "{rcode}":
 | 
					
						
							| 
									
										
										
										
											2021-07-09 13:15:34 +02:00
										 |  |  | 		if rr == nil || rr.Msg == nil {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 			return append(b, EmptyValue...)
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		if rcode := dns.RcodeToString[rr.Rcode]; rcode != "" {
 | 
					
						
							|  |  |  | 			return append(b, rcode...)
 | 
					
						
							| 
									
										
										
										
											2016-03-19 20:17:44 +00:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		return strconv.AppendInt(b, int64(rr.Rcode), 10)
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 	case "{rsize}":
 | 
					
						
							|  |  |  | 		if rr == nil {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 			return append(b, EmptyValue...)
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		return strconv.AppendInt(b, int64(rr.Len), 10)
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 	case "{duration}":
 | 
					
						
							|  |  |  | 		if rr == nil {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 			return append(b, EmptyValue...)
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		secs := time.Since(rr.Start).Seconds()
 | 
					
						
							|  |  |  | 		return append(strconv.AppendFloat(b, secs, 'f', -1, 64), 's')
 | 
					
						
							| 
									
										
										
										
											2019-02-21 07:13:05 +00:00
										 |  |  | 	case headerReplacer + "rflags}":
 | 
					
						
							| 
									
										
										
										
											2019-02-12 07:38:49 +00:00
										 |  |  | 		if rr != nil && rr.Msg != nil {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 			return appendFlags(b, rr.Msg.MsgHdr)
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 		}
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		return append(b, EmptyValue...)
 | 
					
						
							| 
									
										
										
										
											2023-08-14 14:01:13 -04:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (request.Request{}) == state {
 | 
					
						
							|  |  |  | 		return append(b, EmptyValue...)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch label {
 | 
					
						
							|  |  |  | 	case "{type}":
 | 
					
						
							|  |  |  | 		return append(b, state.Type()...)
 | 
					
						
							|  |  |  | 	case "{name}":
 | 
					
						
							|  |  |  | 		return append(b, state.Name()...)
 | 
					
						
							|  |  |  | 	case "{class}":
 | 
					
						
							|  |  |  | 		return append(b, state.Class()...)
 | 
					
						
							|  |  |  | 	case "{proto}":
 | 
					
						
							|  |  |  | 		return append(b, state.Proto()...)
 | 
					
						
							|  |  |  | 	case "{size}":
 | 
					
						
							|  |  |  | 		return strconv.AppendInt(b, int64(state.Req.Len()), 10)
 | 
					
						
							|  |  |  | 	case "{remote}":
 | 
					
						
							|  |  |  | 		return appendAddrToRFC3986(b, state.IP())
 | 
					
						
							|  |  |  | 	case "{port}":
 | 
					
						
							|  |  |  | 		return append(b, state.Port()...)
 | 
					
						
							|  |  |  | 	case "{local}":
 | 
					
						
							|  |  |  | 		return appendAddrToRFC3986(b, state.LocalIP())
 | 
					
						
							|  |  |  | 	// Header placeholders (case-insensitive).
 | 
					
						
							|  |  |  | 	case headerReplacer + "id}":
 | 
					
						
							|  |  |  | 		return strconv.AppendInt(b, int64(state.Req.Id), 10)
 | 
					
						
							|  |  |  | 	case headerReplacer + "opcode}":
 | 
					
						
							|  |  |  | 		return strconv.AppendInt(b, int64(state.Req.Opcode), 10)
 | 
					
						
							|  |  |  | 	case headerReplacer + "do}":
 | 
					
						
							|  |  |  | 		return strconv.AppendBool(b, state.Do())
 | 
					
						
							|  |  |  | 	case headerReplacer + "bufsize}":
 | 
					
						
							|  |  |  | 		return strconv.AppendInt(b, int64(state.Size()), 10)
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 	default:
 | 
					
						
							|  |  |  | 		return append(b, EmptyValue...)
 | 
					
						
							| 
									
										
										
										
											2016-03-18 20:57:35 +00:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2016-04-03 17:16:46 +01:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | // appendFlags checks all header flags and appends those
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | // that are set as a string separated with commas
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | func appendFlags(b []byte, h dns.MsgHdr) []byte {
 | 
					
						
							|  |  |  | 	origLen := len(b)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	if h.Response {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		b = append(b, "qr,"...)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	if h.Authoritative {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		b = append(b, "aa,"...)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	if h.Truncated {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		b = append(b, "tc,"...)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	if h.RecursionDesired {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		b = append(b, "rd,"...)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	if h.RecursionAvailable {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		b = append(b, "ra,"...)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	if h.Zero {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		b = append(b, "z,"...)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	if h.AuthenticatedData {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		b = append(b, "ad,"...)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	}
 | 
					
						
							|  |  |  | 	if h.CheckingDisabled {
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 		b = append(b, "cd,"...)
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 	if n := len(b); n > origLen {
 | 
					
						
							|  |  |  | 		return b[:n-1] // trim trailing ','
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return b
 | 
					
						
							| 
									
										
										
										
											2017-08-07 03:49:40 -07:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | // appendAddrToRFC3986 will add brackets to the address if it is an IPv6 address.
 | 
					
						
							|  |  |  | func appendAddrToRFC3986(b []byte, addr string) []byte {
 | 
					
						
							|  |  |  | 	if strings.IndexByte(addr, ':') != -1 {
 | 
					
						
							|  |  |  | 		b = append(b, '[')
 | 
					
						
							|  |  |  | 		b = append(b, addr...)
 | 
					
						
							|  |  |  | 		b = append(b, ']')
 | 
					
						
							|  |  |  | 	} else {
 | 
					
						
							|  |  |  | 		b = append(b, addr...)
 | 
					
						
							| 
									
										
										
										
											2018-02-28 18:15:12 -08:00
										 |  |  | 	}
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 	return b
 | 
					
						
							| 
									
										
										
										
											2018-02-28 18:15:12 -08:00
										 |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | type nodeType int
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-13 14:20:49 -05:00
										 |  |  | const (
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 	typeLabel    nodeType = iota // "{type}"
 | 
					
						
							|  |  |  | 	typeLiteral                  // "foo"
 | 
					
						
							|  |  |  | 	typeMetadata                 // "{/metadata}"
 | 
					
						
							| 
									
										
										
										
											2018-11-13 14:20:49 -05:00
										 |  |  | )
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // A node represents a segment of a parsed format.  For example: "A {type}"
 | 
					
						
							|  |  |  | // contains two nodes: "A " (literal); and "{type}" (label).
 | 
					
						
							|  |  |  | type node struct {
 | 
					
						
							|  |  |  | 	value string // Literal value, label or metadata label
 | 
					
						
							|  |  |  | 	typ   nodeType
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // A replacer is an ordered list of all the nodes in a format.
 | 
					
						
							|  |  |  | type replacer []node
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func parseFormat(s string) replacer {
 | 
					
						
							|  |  |  | 	// Assume there is a literal between each label - its cheaper to over
 | 
					
						
							|  |  |  | 	// allocate once than allocate twice.
 | 
					
						
							|  |  |  | 	rep := make(replacer, 0, strings.Count(s, "{")*2)
 | 
					
						
							|  |  |  | 	for {
 | 
					
						
							|  |  |  | 		// We find the right bracket then backtrack to find the left bracket.
 | 
					
						
							|  |  |  | 		// This allows us to handle formats like: "{ {foo} }".
 | 
					
						
							|  |  |  | 		j := strings.IndexByte(s, '}')
 | 
					
						
							|  |  |  | 		if j < 0 {
 | 
					
						
							|  |  |  | 			break
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		i := strings.LastIndexByte(s[:j], '{')
 | 
					
						
							|  |  |  | 		if i < 0 {
 | 
					
						
							|  |  |  | 			// Handle: "A } {foo}" by treating "A }" as a literal
 | 
					
						
							|  |  |  | 			rep = append(rep, node{
 | 
					
						
							|  |  |  | 				value: s[:j+1],
 | 
					
						
							|  |  |  | 				typ:   typeLiteral,
 | 
					
						
							|  |  |  | 			})
 | 
					
						
							|  |  |  | 			s = s[j+1:]
 | 
					
						
							|  |  |  | 			continue
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		val := s[i : j+1]
 | 
					
						
							|  |  |  | 		var typ nodeType
 | 
					
						
							|  |  |  | 		switch _, ok := labels[val]; {
 | 
					
						
							|  |  |  | 		case ok:
 | 
					
						
							|  |  |  | 			typ = typeLabel
 | 
					
						
							|  |  |  | 		case strings.HasPrefix(val, "{/"):
 | 
					
						
							|  |  |  | 			// Strip "{/}" from metadata labels
 | 
					
						
							|  |  |  | 			val = val[2 : len(val)-1]
 | 
					
						
							|  |  |  | 			typ = typeMetadata
 | 
					
						
							|  |  |  | 		default:
 | 
					
						
							|  |  |  | 			// Given: "A {X}" val is "{X}" expand it to the whole literal.
 | 
					
						
							|  |  |  | 			val = s[:j+1]
 | 
					
						
							|  |  |  | 			typ = typeLiteral
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Append any leading literal.  Given "A {type}" the literal is "A "
 | 
					
						
							|  |  |  | 		if i != 0 && typ != typeLiteral {
 | 
					
						
							|  |  |  | 			rep = append(rep, node{
 | 
					
						
							|  |  |  | 				value: s[:i],
 | 
					
						
							|  |  |  | 				typ:   typeLiteral,
 | 
					
						
							|  |  |  | 			})
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 		rep = append(rep, node{
 | 
					
						
							|  |  |  | 			value: val,
 | 
					
						
							|  |  |  | 			typ:   typ,
 | 
					
						
							|  |  |  | 		})
 | 
					
						
							|  |  |  | 		s = s[j+1:]
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	if len(s) != 0 {
 | 
					
						
							|  |  |  | 		rep = append(rep, node{
 | 
					
						
							|  |  |  | 			value: s,
 | 
					
						
							|  |  |  | 			typ:   typeLiteral,
 | 
					
						
							|  |  |  | 		})
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	return rep
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var replacerCache sync.Map // map[string]replacer
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func loadFormat(s string) replacer {
 | 
					
						
							|  |  |  | 	if v, ok := replacerCache.Load(s); ok {
 | 
					
						
							|  |  |  | 		return v.(replacer)
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	v, _ := replacerCache.LoadOrStore(s, parseFormat(s))
 | 
					
						
							|  |  |  | 	return v.(replacer)
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // bufPool stores pointers to scratch buffers.
 | 
					
						
							|  |  |  | var bufPool = sync.Pool{
 | 
					
						
							|  |  |  | 	New: func() interface{} {
 | 
					
						
							|  |  |  | 		return make([]byte, 0, 256)
 | 
					
						
							|  |  |  | 	},
 | 
					
						
							|  |  |  | }
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (r replacer) Replace(ctx context.Context, state request.Request, rr *dnstest.Recorder) string {
 | 
					
						
							|  |  |  | 	b := bufPool.Get().([]byte)
 | 
					
						
							|  |  |  | 	for _, s := range r {
 | 
					
						
							|  |  |  | 		switch s.typ {
 | 
					
						
							|  |  |  | 		case typeLabel:
 | 
					
						
							|  |  |  | 			b = appendValue(b, state, rr, s.value)
 | 
					
						
							|  |  |  | 		case typeLiteral:
 | 
					
						
							|  |  |  | 			b = append(b, s.value...)
 | 
					
						
							|  |  |  | 		case typeMetadata:
 | 
					
						
							|  |  |  | 			if fm := metadata.ValueFunc(ctx, s.value); fm != nil {
 | 
					
						
							|  |  |  | 				b = append(b, fm()...)
 | 
					
						
							|  |  |  | 			} else {
 | 
					
						
							|  |  |  | 				b = append(b, EmptyValue...)
 | 
					
						
							|  |  |  | 			}
 | 
					
						
							|  |  |  | 		}
 | 
					
						
							|  |  |  | 	}
 | 
					
						
							|  |  |  | 	s := string(b)
 | 
					
						
							| 
									
										
										
										
											2022-07-10 20:06:33 +02:00
										 |  |  | 	//nolint:staticcheck
 | 
					
						
							| 
									
										
										
										
											2019-07-17 02:57:46 -04:00
										 |  |  | 	bufPool.Put(b[:0])
 | 
					
						
							|  |  |  | 	return s
 | 
					
						
							|  |  |  | }
 |