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  }