github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/pkg/logql/log/logfmt/decode.go (about)

     1  // Adapted from https://github.com/go-logfmt/logfmt/ but []byte as parameter instead
     2  // Original license is MIT.
     3  package logfmt
     4  
     5  import (
     6  	"bytes"
     7  	"fmt"
     8  	"unicode/utf8"
     9  )
    10  
    11  // A Decoder reads and decodes logfmt records from an input stream.
    12  type Decoder struct {
    13  	pos   int
    14  	key   []byte
    15  	value []byte
    16  	line  []byte
    17  	err   error
    18  }
    19  
    20  // NewDecoder returns a new decoder that reads from r.
    21  //
    22  // The decoder introduces its own buffering and may read data from r beyond
    23  // the logfmt records requested.
    24  func NewDecoder(line []byte) *Decoder {
    25  	dec := &Decoder{line: line}
    26  	return dec
    27  }
    28  
    29  func (dec *Decoder) Reset(line []byte) {
    30  	dec.pos = 0
    31  	dec.line = line
    32  	dec.err = nil
    33  }
    34  
    35  // ScanKeyval advances the Decoder to the next key/value pair of the current
    36  // record, which can then be retrieved with the Key and Value methods. It
    37  // returns false when decoding stops, either by reaching the end of the
    38  // current record or an error.
    39  func (dec *Decoder) ScanKeyval() bool {
    40  	dec.key, dec.value = nil, nil
    41  
    42  	line := dec.line
    43  	// garbage
    44  	for p, c := range line[dec.pos:] {
    45  		if c > ' ' {
    46  			dec.pos += p
    47  			goto key
    48  		}
    49  	}
    50  	dec.pos = len(line)
    51  	return false
    52  
    53  key:
    54  	const invalidKeyError = "invalid key"
    55  
    56  	start, multibyte := dec.pos, false
    57  	for p, c := range line[dec.pos:] {
    58  		switch {
    59  		case c == '=':
    60  			dec.pos += p
    61  			if dec.pos > start {
    62  				dec.key = line[start:dec.pos]
    63  				if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
    64  					dec.syntaxError(invalidKeyError)
    65  					return false
    66  				}
    67  			}
    68  			if dec.key == nil {
    69  				dec.unexpectedByte(c)
    70  				return false
    71  			}
    72  			goto equal
    73  		case c == '"':
    74  			dec.pos += p
    75  			dec.unexpectedByte(c)
    76  			return false
    77  		case c <= ' ':
    78  			dec.pos += p
    79  			if dec.pos > start {
    80  				dec.key = line[start:dec.pos]
    81  				if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
    82  					dec.syntaxError(invalidKeyError)
    83  					return false
    84  				}
    85  			}
    86  			return true
    87  		case c >= utf8.RuneSelf:
    88  			multibyte = true
    89  		}
    90  	}
    91  	dec.pos = len(line)
    92  	if dec.pos > start {
    93  		dec.key = line[start:dec.pos]
    94  		if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
    95  			dec.syntaxError(invalidKeyError)
    96  			return false
    97  		}
    98  	}
    99  	return true
   100  
   101  equal:
   102  	dec.pos++
   103  	if dec.pos >= len(line) {
   104  		return true
   105  	}
   106  	switch c := line[dec.pos]; {
   107  	case c <= ' ':
   108  		return true
   109  	case c == '"':
   110  		goto qvalue
   111  	}
   112  
   113  	// value
   114  	start = dec.pos
   115  	for p, c := range line[dec.pos:] {
   116  		switch {
   117  		case c == '=' || c == '"':
   118  			dec.pos += p
   119  			dec.unexpectedByte(c)
   120  			return false
   121  		case c <= ' ':
   122  			dec.pos += p
   123  			if dec.pos > start {
   124  				dec.value = line[start:dec.pos]
   125  			}
   126  			return true
   127  		}
   128  	}
   129  	dec.pos = len(line)
   130  	if dec.pos > start {
   131  		dec.value = line[start:dec.pos]
   132  	}
   133  	return true
   134  
   135  qvalue:
   136  	const (
   137  		untermQuote  = "unterminated quoted value"
   138  		invalidQuote = "invalid quoted value"
   139  	)
   140  
   141  	hasEsc, esc := false, false
   142  	start = dec.pos
   143  	for p, c := range line[dec.pos+1:] {
   144  		switch {
   145  		case esc:
   146  			esc = false
   147  		case c == '\\':
   148  			hasEsc, esc = true, true
   149  		case c == '"':
   150  			dec.pos += p + 2
   151  			if hasEsc {
   152  				v, ok := unquoteBytes(line[start:dec.pos])
   153  				if !ok {
   154  					dec.syntaxError(invalidQuote)
   155  					return false
   156  				}
   157  				dec.value = v
   158  			} else {
   159  				start++
   160  				end := dec.pos - 1
   161  				if end > start {
   162  					dec.value = line[start:end]
   163  				}
   164  			}
   165  			return true
   166  		}
   167  	}
   168  	dec.pos = len(line)
   169  	dec.syntaxError(untermQuote)
   170  	return false
   171  }
   172  
   173  // Key returns the most recent key found by a call to ScanKeyval. The returned
   174  // slice may point to internal buffers and is only valid until the next call
   175  // to ScanRecord.  It does no allocation.
   176  func (dec *Decoder) Key() []byte {
   177  	return dec.key
   178  }
   179  
   180  // Value returns the most recent value found by a call to ScanKeyval. The
   181  // returned slice may point to internal buffers and is only valid until the
   182  // next call to ScanRecord.  It does no allocation when the value has no
   183  // escape sequences.
   184  func (dec *Decoder) Value() []byte {
   185  	return dec.value
   186  }
   187  
   188  // Err returns the first non-EOF error that was encountered by the Scanner.
   189  func (dec *Decoder) Err() error {
   190  	return dec.err
   191  }
   192  
   193  func (dec *Decoder) syntaxError(msg string) {
   194  	dec.err = &SyntaxError{
   195  		Msg: msg,
   196  		Pos: dec.pos + 1,
   197  	}
   198  }
   199  
   200  func (dec *Decoder) unexpectedByte(c byte) {
   201  	dec.err = &SyntaxError{
   202  		Msg: fmt.Sprintf("unexpected %q", c),
   203  		Pos: dec.pos + 1,
   204  	}
   205  }
   206  
   207  // A SyntaxError represents a syntax error in the logfmt input stream.
   208  type SyntaxError struct {
   209  	Msg string
   210  	Pos int
   211  }
   212  
   213  func (e *SyntaxError) Error() string {
   214  	return fmt.Sprintf("logfmt syntax error at pos %d : %s", e.Pos, e.Msg)
   215  }