github.com/soulteary/pocket-bookcase@v0.0.0-20240428065142-0b5a9a0fc98a/internal/core/url.go (about) 1 package core 2 3 import ( 4 "fmt" 5 nurl "net/url" 6 "sort" 7 "strings" 8 ) 9 10 // queryEncodeWithoutEmptyValues is a copy of `values.Encode` but checking if the queryparam 11 // value is empty to prevent sending the = symbol empty which breaks in some servers. 12 func queryEncodeWithoutEmptyValues(v nurl.Values) string { 13 if v == nil { 14 return "" 15 } 16 var buf strings.Builder 17 keys := make([]string, 0, len(v)) 18 for k := range v { 19 keys = append(keys, k) 20 } 21 sort.Strings(keys) 22 for _, k := range keys { 23 vs := v[k] 24 keyEscaped := nurl.QueryEscape(k) 25 for _, v := range vs { 26 if buf.Len() > 0 { 27 buf.WriteByte('&') 28 } 29 buf.WriteString(keyEscaped) 30 if v != "" { 31 buf.WriteByte('=') 32 buf.WriteString(nurl.QueryEscape(v)) 33 } 34 } 35 } 36 return buf.String() 37 } 38 39 // RemoveUTMParams removes the UTM parameters from URL. 40 func RemoveUTMParams(url string) (string, error) { 41 // Parse string URL 42 tmp, err := nurl.Parse(url) 43 if err != nil || tmp.Scheme == "" || tmp.Hostname() == "" { 44 return url, fmt.Errorf("URL is not valid") 45 } 46 47 // Remove UTM queries 48 queries := tmp.Query() 49 for key := range queries { 50 if strings.HasPrefix(key, "utm_") { 51 queries.Del(key) 52 } 53 } 54 55 tmp.RawQuery = queryEncodeWithoutEmptyValues(queries) 56 return tmp.String(), nil 57 }