github.com/rajeev159/opa@v0.45.0/topdown/regex_template.go (about)

     1  package topdown
     2  
     3  // Copyright 2012 The Gorilla Authors. All rights reserved.
     4  // Use of this source code is governed by a BSD-style
     5  // license as follows:
     6  
     7  // Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
     8  //
     9  // Redistribution and use in source and binary forms, with or without
    10  // modification, are permitted provided that the following conditions are
    11  // met:
    12  //
    13  // * Redistributions of source code must retain the above copyright
    14  //  notice, this list of conditions and the following disclaimer.
    15  // * Redistributions in binary form must reproduce the above
    16  //  copyright notice, this list of conditions and the following disclaimer
    17  //  in the documentation and/or other materials provided with the
    18  //  distribution.
    19  // * Neither the name of Google Inc. nor the names of its
    20  //  contributors may be used to endorse or promote products derived from
    21  //  this software without specific prior written permission.
    22  //
    23  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    24  // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    25  // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    26  // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    27  // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    28  // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    29  // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    30  // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    31  // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    32  // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    33  // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    34  
    35  // This file was forked from https://github.com/gorilla/mux/commit/eac83ba2c004bb75
    36  
    37  import (
    38  	"bytes"
    39  	"fmt"
    40  	"regexp"
    41  )
    42  
    43  // delimiterIndices returns the first level delimiter indices from a string.
    44  // It returns an error in case of unbalanced delimiters.
    45  func delimiterIndices(s string, delimiterStart, delimiterEnd byte) ([]int, error) {
    46  	var level, idx int
    47  	idxs := make([]int, 0)
    48  	for i := 0; i < len(s); i++ {
    49  		switch s[i] {
    50  		case delimiterStart:
    51  			if level++; level == 1 {
    52  				idx = i
    53  			}
    54  		case delimiterEnd:
    55  			if level--; level == 0 {
    56  				idxs = append(idxs, idx, i+1)
    57  			} else if level < 0 {
    58  				return nil, fmt.Errorf(`unbalanced braces in %q`, s)
    59  			}
    60  		}
    61  	}
    62  
    63  	if level != 0 {
    64  		return nil, fmt.Errorf(`unbalanced braces in %q`, s)
    65  	}
    66  
    67  	return idxs, nil
    68  }
    69  
    70  // compileRegexTemplate parses a template and returns a Regexp.
    71  //
    72  // You can define your own delimiters. It is e.g. common to use curly braces {} but I recommend using characters
    73  // which have no special meaning in Regex, e.g.: <, >
    74  //
    75  //  reg, err := compiler.CompileRegex("foo:bar.baz:<[0-9]{2,10}>", '<', '>')
    76  //  // if err != nil ...
    77  //  reg.MatchString("foo:bar.baz:123")
    78  func compileRegexTemplate(tpl string, delimiterStart, delimiterEnd byte) (*regexp.Regexp, error) {
    79  	// Check if it is well-formed.
    80  	idxs, errBraces := delimiterIndices(tpl, delimiterStart, delimiterEnd)
    81  	if errBraces != nil {
    82  		return nil, errBraces
    83  	}
    84  	varsR := make([]*regexp.Regexp, len(idxs)/2)
    85  	pattern := bytes.NewBufferString("")
    86  
    87  	// WriteByte's error value is always nil for bytes.Buffer, no need to check it.
    88  	pattern.WriteByte('^')
    89  
    90  	var end int
    91  	var err error
    92  	for i := 0; i < len(idxs); i += 2 {
    93  		// Set all values we are interested in.
    94  		raw := tpl[end:idxs[i]]
    95  		end = idxs[i+1]
    96  		patt := tpl[idxs[i]+1 : end-1]
    97  		// Build the regexp pattern.
    98  		varIdx := i / 2
    99  		fmt.Fprintf(pattern, "%s(%s)", regexp.QuoteMeta(raw), patt)
   100  		varsR[varIdx], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
   101  		if err != nil {
   102  			return nil, err
   103  		}
   104  	}
   105  
   106  	// Add the remaining.
   107  	raw := tpl[end:]
   108  
   109  	// WriteString's error value is always nil for bytes.Buffer, no need to check it.
   110  	pattern.WriteString(regexp.QuoteMeta(raw))
   111  
   112  	// WriteByte's error value is always nil for bytes.Buffer, no need to check it.
   113  	pattern.WriteByte('$')
   114  
   115  	// Compile full regexp.
   116  	reg, errCompile := regexp.Compile(pattern.String())
   117  	if errCompile != nil {
   118  		return nil, errCompile
   119  	}
   120  
   121  	return reg, nil
   122  }