url.go raw
1 package dara
2
3 import (
4 "fmt"
5 "net/url"
6 "strings"
7 )
8
9 // PortMap maps protocols to their corresponding ports.
10 var portMap = map[string]string{
11 "ftp": "21",
12 "gopher": "70",
13 "http": "80",
14 "https": "443",
15 "ws": "80",
16 "wss": "443",
17 }
18
19 // URL is a wrapper around the URL type.
20 type URL struct {
21 _url *url.URL
22 }
23
24 // NewURL constructs a new URL from a string.
25 func NewURL(str string) (*URL, error) {
26 parsedURL, err := url.Parse(str)
27 if err != nil {
28 return nil, err
29 }
30 return &URL{_url: parsedURL}, nil
31 }
32
33 // Path returns the path and query of the URL.
34 func (t *URL) Path() string {
35 if t._url.RawQuery == "" {
36 return t._url.Path
37 }
38 return t._url.Path + "?" + t._url.RawQuery
39 }
40
41 // Pathname returns the pathname of the URL.
42 func (t *URL) Pathname() string {
43 return t._url.Path
44 }
45
46 // Protocol returns the protocol of the URL.
47 func (t *URL) Protocol() string {
48 return strings.TrimSuffix(t._url.Scheme, ":")
49 }
50
51 // Hostname returns the hostname of the URL.
52 func (t *URL) Hostname() string {
53 return t._url.Hostname()
54 }
55
56 // Host returns the host (host:port) of the URL.
57 func (t *URL) Host() string {
58 return t._url.Host
59 }
60
61 // Port returns the port of the URL, or the default for the protocol if not specified.
62 func (t *URL) Port() string {
63 if p := t._url.Port(); p != "" {
64 return p
65 }
66 return portMap[t.Protocol()]
67 }
68
69 // Hash returns the hash of the URL without the #.
70 func (t *URL) Hash() string {
71 return strings.TrimPrefix(t._url.Fragment, "#")
72 }
73
74 // Search returns the search part of the URL without the ?.
75 func (t *URL) Search() string {
76 return strings.TrimPrefix(t._url.RawQuery, "?")
77 }
78
79 // Href returns the full URL.
80 func (t *URL) Href() string {
81 return t._url.String()
82 }
83
84 // Auth returns the username and password of the URL.
85 func (t *URL) Auth() string {
86 password := getPassword(t._url.User)
87 username := t._url.User.Username()
88 if username == "" && password == "" {
89 return ""
90 }
91 return fmt.Sprintf("%s:%s", username, password)
92 }
93
94 // getPassword retrieves the password from a URL.User.
95 func getPassword(user *url.Userinfo) string {
96 if password, ok := user.Password(); ok {
97 return password
98 }
99 return ""
100 }
101
102 // Parse constructs a new URL from a string.
103 func ParseURL(urlStr string) (*URL, error) {
104 return NewURL(urlStr)
105 }
106
107 // EncodeURL encodes a URL string.
108 func EncodeURL(urlStr string) string {
109 if urlStr == "" {
110 return ""
111 }
112 strs := strings.Split(urlStr, "/")
113 for i, v := range strs {
114 strs[i] = url.QueryEscape(v)
115 }
116 urlStr = strings.Join(strs, "/")
117 urlStr = strings.Replace(urlStr, "+", "%20", -1)
118 urlStr = strings.Replace(urlStr, "*", "%2A", -1)
119 urlStr = strings.Replace(urlStr, "%7E", "~", -1)
120 return urlStr
121 }
122
123 // PercentEncode encodes a string for use in URLs, replacing certain characters.
124 func PercentEncode(uri string) string {
125 if uri == "" {
126 return ""
127 }
128 uri = url.QueryEscape(uri)
129 uri = strings.Replace(uri, "+", "%20", -1)
130 uri = strings.Replace(uri, "*", "%2A", -1)
131 uri = strings.Replace(uri, "%7E", "~", -1)
132 return uri
133 }
134
135 // PathEncode encodes each segment of a path.
136 func PathEncode(path string) string {
137 if path == "" || path == "/" {
138 return path
139 }
140 strs := strings.Split(path, "/")
141 for i, v := range strs {
142 strs[i] = url.QueryEscape(v)
143 }
144 path = strings.Join(strs, "/")
145 path = strings.Replace(path, "+", "%20", -1)
146 path = strings.Replace(path, "*", "%2A", -1)
147 path = strings.Replace(path, "%7E", "~", -1)
148 return path
149 }
150