github.com/crowdsecurity/crowdsec@v1.6.1/pkg/appsec/query_utils.go (about) 1 package appsec 2 3 // This file is mostly stolen from net/url package, but with some modifications to allow less strict parsing of query strings 4 5 import ( 6 "net/url" 7 "strings" 8 ) 9 10 // parseQuery and parseQuery are copied net/url package, but allow semicolon in values 11 func ParseQuery(query string) url.Values { 12 m := make(url.Values) 13 parseQuery(m, query) 14 return m 15 } 16 17 func parseQuery(m url.Values, query string) { 18 for query != "" { 19 var key string 20 key, query, _ = strings.Cut(query, "&") 21 22 if key == "" { 23 continue 24 } 25 key, value, _ := strings.Cut(key, "=") 26 //for now we'll just ignore the errors, but ideally we want to fire some "internal" rules when we see invalid query strings 27 key = unescape(key) 28 value = unescape(value) 29 m[key] = append(m[key], value) 30 } 31 } 32 33 func hexDigitToByte(digit byte) (byte, bool) { 34 switch { 35 case digit >= '0' && digit <= '9': 36 return digit - '0', true 37 case digit >= 'a' && digit <= 'f': 38 return digit - 'a' + 10, true 39 case digit >= 'A' && digit <= 'F': 40 return digit - 'A' + 10, true 41 default: 42 return 0, false 43 } 44 } 45 46 func unescape(input string) string { 47 ilen := len(input) 48 res := strings.Builder{} 49 res.Grow(ilen) 50 for i := 0; i < ilen; i++ { 51 ci := input[i] 52 if ci == '+' { 53 res.WriteByte(' ') 54 continue 55 } 56 if ci == '%' { 57 if i+2 >= ilen { 58 res.WriteByte(ci) 59 continue 60 } 61 hi, ok := hexDigitToByte(input[i+1]) 62 if !ok { 63 res.WriteByte(ci) 64 continue 65 } 66 lo, ok := hexDigitToByte(input[i+2]) 67 if !ok { 68 res.WriteByte(ci) 69 continue 70 } 71 res.WriteByte(hi<<4 | lo) 72 i += 2 73 continue 74 } 75 res.WriteByte(ci) 76 } 77 return res.String() 78 }