@@ -354,8 +354,13 @@ func parseExprWithoutPipe(e string) (Expr, string, error) {
354354 val , tail , err := parseString (e )
355355 return & expr {valStr : val , etype : EtString }, tail , err
356356 }
357+
357358 var name string
358- name , e = parseName (e )
359+ var err error
360+ name , e , err = parseName (e )
361+ if err != nil {
362+ return nil , e , err
363+ }
359364
360365 if strings .ToLower (name ) == "false" || strings .ToLower (name ) == "true" {
361366 return & expr {valStr : name , etype : EtString , target : name }, e , nil
@@ -420,7 +425,6 @@ func IsNameChar(r byte) bool {
420425 r == '.' || r == '_' ||
421426 r == '-' || r == '*' ||
422427 r == '?' || r == ':' ||
423- r == '[' || r == ']' ||
424428 r == '^' || r == '$' ||
425429 r == '<' || r == '>' ||
426430 r == '&' || r == '#'
@@ -557,48 +561,118 @@ func parseConst(s string) (float64, string, error) {
557561// RangeTables is an array of *unicode.RangeTable
558562var RangeTables []* unicode.RangeTable
559563
560- func parseName (s string ) (string , string ) {
561-
564+ // parseName parses the next symbol from s and returns
565+ // * the parsed symbol (function or metric name),
566+ // * the rest of the string from s
567+ // * syntax error
568+ func parseName (s string ) (string , string , error ) {
562569 var (
563- braces , i , w int
564- r rune
570+ braces , brackets int
571+ i , w int
572+ r rune
565573 )
566574
567575FOR:
568- for braces , i = 0 , 0 ; i < len (s ); i += w {
569-
576+ for i = 0 ; i < len (s ); i += w {
570577 w = 1
571578 if IsNameChar (s [i ]) {
572579 continue
573580 }
574581
582+ // Graphite render spec: https://graphite.readthedocs.io/en/latest/render_api.html#graphing-metrics
575583 switch s [i ] {
576584 case '{' :
585+ // No way escape { in metric names, thus using it
586+ // in the range brackets should be an error.
587+ if brackets > 0 {
588+ return s , "" , ErrBraceInBrackets
589+ }
590+
577591 braces ++
578592 case '}' :
579- if braces == 0 {
580- break FOR
593+ // No way escape } in metric names, thus using it
594+ // in the range brackets should be an error.
595+ if brackets > 0 {
596+ return s , "" , ErrBraceInBrackets
597+ } else if braces == 0 {
598+ return s , "" , ErrMissingBrace
581599 }
600+
582601 braces --
602+ case '[' :
603+ // Nested brackets support isn't really necessary as
604+ // left bracket [ alone can't be in metric name. And
605+ // go-carbon doesn't support it at the moment.
606+ //
607+ // Before this change, no errors are returned to the
608+ // user and no metrics are returned. It's arguably
609+ // worse than just return an error.
610+ if brackets > 0 {
611+ return s , "" , ErrNestedBrackets
612+ }
613+
614+ brackets ++
615+ case ']' :
616+ // No way to escape braces {} and brackets [] in
617+ // graphite query, thus missing open [ means it's a query bug.
618+ if brackets == 0 {
619+ return s , "" , ErrMissingBracket
620+ }
621+
622+ brackets --
583623 case ',' :
624+ // No way to escape a comma in graphite query, thus
625+ // metric name is not allowed to have comma within it,
626+ // thus it isn't allowed to query it within [].
627+ if brackets > 0 {
628+ return s , "" , ErrCommaInBrackets
629+ }
630+
584631 if braces == 0 {
585632 break FOR
586633 }
634+ case ' ' , '\t' , '\n' :
635+ // Spaces is not allowed in metric name, so it isn't
636+ // really needed for us to support it in value list
637+ // {} and range list [] queries.
638+ //
639+ // Although it is nice to allow spaces in value list query,
640+ // support in storage layer like go-carbon is also required.
641+ //
642+ // At the same time, if not using any graphite function,
643+ // the current parser also doesn't support spaces in
644+ // value list syntax {} and would return an 400 error.
645+ if braces > 0 {
646+ return s , "" , ErrSpacesInBraces
647+ }
648+ if brackets > 0 {
649+ return s , "" , ErrSpacesInBrackets
650+ }
651+
652+ break FOR
587653 default :
588654 r , w = utf8 .DecodeRuneInString (s [i :])
589655 if unicode .In (r , RangeTables ... ) {
590656 continue
591657 }
592658 break FOR
593659 }
660+ }
594661
662+ // No way to escape braces {} and brackets [] in graphite query, thus
663+ // missing closed }/] means it's a query bug.
664+ if braces > 0 {
665+ return s , "" , ErrMissingBrace
666+ }
667+ if brackets > 0 {
668+ return s , "" , ErrMissingBracket
595669 }
596670
597671 if i == len (s ) {
598- return s , ""
672+ return s , "" , nil
599673 }
600674
601- return s [:i ], s [i :]
675+ return s [:i ], s [i :], nil
602676}
603677
604678func parseString (s string ) (string , string , error ) {
0 commit comments