github.com/erda-project/erda-infra@v1.0.10-0.20240327085753-f3a249292aeb/pkg/transport/http/httprule/compile.go (about)

     1  // Copyright (c) 2021 Terminus, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Reference: https://github.com/grpc-ecosystem/grpc-gateway/blob/v2.3.0/internal/httprule/compile.go
    16  
    17  package httprule
    18  
    19  import (
    20  	"github.com/erda-project/erda-infra/pkg/transport/http/utilities"
    21  )
    22  
    23  const (
    24  	// SupportPackageIsVersion1 .
    25  	SupportPackageIsVersion1 = 1
    26  	opcodeVersion            = 1
    27  )
    28  
    29  // Template is a compiled representation of path templates.
    30  type Template struct {
    31  	// Version is the version number of the format.
    32  	Version int
    33  	// OpCodes is a sequence of operations.
    34  	OpCodes []int
    35  	// Pool is a constant pool
    36  	Pool []string
    37  	// Verb is a VERB part in the template.
    38  	Verb string
    39  	// Fields is a list of field paths bound in this template.
    40  	Fields []string
    41  	// Original template (example: /v1/a_bit_of_everything)
    42  	Template string
    43  }
    44  
    45  // Compiler compiles utilities representation of path templates into marshallable operations.
    46  // They can be unmarshalled by runtime.NewPattern.
    47  type Compiler interface {
    48  	Compile() Template
    49  }
    50  
    51  type op struct {
    52  	// code is the opcode of the operation
    53  	code utilities.OpCode
    54  
    55  	// str is a string operand of the code.
    56  	// num is ignored if str is not empty.
    57  	str string
    58  
    59  	// num is a numeric operand of the code.
    60  	num int
    61  }
    62  
    63  func (w wildcard) compile() []op {
    64  	return []op{
    65  		{code: utilities.OpPush},
    66  	}
    67  }
    68  
    69  func (w deepWildcard) compile() []op {
    70  	return []op{
    71  		{code: utilities.OpPushM},
    72  	}
    73  }
    74  
    75  func (l literal) compile() []op {
    76  	return []op{
    77  		{
    78  			code: utilities.OpLitPush,
    79  			str:  string(l),
    80  		},
    81  	}
    82  }
    83  
    84  func (v variable) compile() []op {
    85  	var ops []op
    86  	for _, s := range v.segments {
    87  		ops = append(ops, s.compile()...)
    88  	}
    89  	ops = append(ops, op{
    90  		code: utilities.OpConcatN,
    91  		num:  len(v.segments),
    92  	}, op{
    93  		code: utilities.OpCapture,
    94  		str:  v.path,
    95  	})
    96  
    97  	return ops
    98  }
    99  
   100  func (t template) Compile() Template {
   101  	var rawOps []op
   102  	for _, s := range t.segments {
   103  		rawOps = append(rawOps, s.compile()...)
   104  	}
   105  
   106  	var (
   107  		ops    []int
   108  		pool   []string
   109  		fields []string
   110  	)
   111  	consts := make(map[string]int)
   112  	for _, op := range rawOps {
   113  		ops = append(ops, int(op.code))
   114  		if op.str == "" {
   115  			ops = append(ops, op.num)
   116  		} else {
   117  			if _, ok := consts[op.str]; !ok {
   118  				consts[op.str] = len(pool)
   119  				pool = append(pool, op.str)
   120  			}
   121  			ops = append(ops, consts[op.str])
   122  		}
   123  		if op.code == utilities.OpCapture {
   124  			fields = append(fields, op.str)
   125  		}
   126  	}
   127  	return Template{
   128  		Version:  opcodeVersion,
   129  		OpCodes:  ops,
   130  		Pool:     pool,
   131  		Verb:     t.verb,
   132  		Fields:   fields,
   133  		Template: t.template,
   134  	}
   135  }