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 }