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  }