-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathurl_join.go
111 lines (91 loc) · 2.38 KB
/
url_join.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package urljoin
import (
"regexp"
"strings"
)
// Config is config for joining URL parts
type Config struct {
// Adds or removes leading slash. Turned on by default.
LeadingSlash bool
// Preserves what the leading slash only if it's present on the input.
KeepLeadingSlash bool
// Adds or removes trailing slash.
TrailingSlash bool
// Preserves what the trailing slash only if it's present on the input.
KeepTrailingSlash bool
}
var defaultUrlRegExp = regexp.MustCompile(`^(\w+://[^/?]+)?(.*?)(\?.+)?$`)
func normalizeParts(input []string) []string {
var output []string
for _, v := range input {
s := strings.TrimSpace(v)
if s != "" {
output = append(output, s)
}
}
return output
}
// Join joins all given URL segments together with default config.
func Join(parts ...string) string {
return JoinWithConfig(Config{LeadingSlash: true}, parts...)
}
// Join joins all given URL segments together with given config.
func JoinWithConfig(config Config, parts ...string) string {
parts = normalizeParts(parts)
var prefix string
var pathname string
var suffix string
joinedParts := strings.Join(parts, "/")
matched := defaultUrlRegExp.FindStringSubmatch(joinedParts)
if len(matched) > 0 {
prefix = matched[1]
pathname = matched[2]
suffix = matched[3]
}
var hasLeading bool
var hasTrailing bool
if suffix != "" {
hasLeading = regexp.MustCompile(`^//+`).MatchString(pathname)
hasTrailing = regexp.MustCompile(`//+$`).MatchString(pathname)
} else {
hasLeading = regexp.MustCompile(`^/+`).MatchString(pathname)
hasTrailing = regexp.MustCompile(`/+$`).MatchString(pathname)
}
addLeading := config.LeadingSlash || (hasLeading && config.KeepLeadingSlash)
addTrailing := config.TrailingSlash || (hasTrailing && config.KeepTrailingSlash)
var u string
var pathnameParts []string
for _, part := range strings.Split(pathname, "/") {
if part != "" {
pathnameParts = append(pathnameParts, part)
}
}
if len(pathnameParts) > 0 {
u = strings.Join(pathnameParts, "/")
if prefix == "" {
if !strings.HasPrefix(u, "/") {
if strings.HasPrefix(joinedParts, "//") {
u = "//" + u
} else if addLeading {
u = "/" + u
}
}
} else {
if !strings.HasPrefix(u, "/") {
u = prefix + "/" + u
} else {
u = prefix + u
}
}
}
if addTrailing {
u += "/"
}
if u == "" && addLeading {
u += "/"
}
if suffix != "" {
u += suffix
}
return u
}