github.com/treeverse/lakefs@v1.24.1-0.20240520134607-95648127bfb0/pkg/gateway/serde/encoder_test.go (about) 1 package serde_test 2 3 import ( 4 "strings" 5 "testing" 6 ) 7 8 func shouldEscape(c byte) bool { 9 if 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' { 10 return false 11 } 12 13 switch c { 14 case '-', '_', '.', '/', '*': 15 return false 16 } 17 return true 18 } 19 20 // s3URLEncode is based on Golang's url.QueryEscape() code, 21 // while considering some S3 exceptions: 22 // - Avoid encoding '/' and '*' 23 // - Force encoding of '~' 24 func s3URLEncode(s string) string { 25 spaceCount, hexCount := 0, 0 26 for i := 0; i < len(s); i++ { 27 c := s[i] 28 if shouldEscape(c) { 29 if c == ' ' { 30 spaceCount++ 31 } else { 32 hexCount++ 33 } 34 } 35 } 36 37 if spaceCount == 0 && hexCount == 0 { 38 return s 39 } 40 41 var buf [64]byte 42 var t []byte 43 44 required := len(s) + 2*hexCount 45 if required <= len(buf) { 46 t = buf[:required] 47 } else { 48 t = make([]byte, required) 49 } 50 51 if hexCount == 0 { 52 copy(t, s) 53 for i := 0; i < len(s); i++ { 54 if s[i] == ' ' { 55 t[i] = '+' 56 } 57 } 58 return string(t) 59 } 60 61 j := 0 62 for i := 0; i < len(s); i++ { 63 switch c := s[i]; { 64 case c == ' ': 65 t[j] = '+' 66 j++ 67 case shouldEscape(c): 68 t[j] = '%' 69 t[j+1] = "0123456789ABCDEF"[c>>4] 70 t[j+2] = "0123456789ABCDEF"[c&15] 71 j += 3 72 default: 73 t[j] = s[i] 74 j++ 75 } 76 } 77 return string(t) 78 } 79 80 func TestEncoder(t *testing.T) { 81 cases := []struct { 82 Input string 83 Expected string 84 }{ 85 {"foo bar", "foo+bar"}, 86 } 87 for _, test := range cases { 88 got := s3URLEncode(test.Input) 89 if !strings.EqualFold(got, test.Expected) { 90 t.Fatalf("for string \"%s\" got \"%s\" expected \"%s\"", test.Input, got, test.Expected) 91 } 92 } 93 }