-
Notifications
You must be signed in to change notification settings - Fork 231
/
Copy pathgcpURLParts.go
128 lines (107 loc) · 2.84 KB
/
gcpURLParts.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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package common
import (
"errors"
"net/url"
"regexp"
"strings"
)
// GCPURLParts structure is used to parse and hold the different
// components of GCP Object/Service/Bucket URL
type GCPURLParts struct {
Scheme string
Host string
BucketName string
ObjectKey string
UnparsedParams string
}
const gcpHostPattern = "^storage\\.cloud\\.google\\.com"
const invalidGCPURLErrorMessage = "Invalid GCP URL"
const gcpEssentialHostPart = "google.com"
var gcpHostRegex = regexp.MustCompile(gcpHostPattern)
// IsGCPURL validates whether a given URL is a valid GCP Object/Service/Bucket URL
func IsGCPURL(u url.URL) bool {
if _, isGCPURL := findGCPURLMatches(strings.ToLower(u.Host)); isGCPURL {
return true
}
return false
}
func findGCPURLMatches(lower string) ([]string, bool) {
matches := gcpHostRegex.FindStringSubmatch(lower)
if matches == nil || !strings.Contains(lower, gcpEssentialHostPart) {
return nil, false
}
return matches, true
}
// NewGCPURLParts processes the given URL and returns a valid GCPURLParts
// structure that contains all the necessary components.
func NewGCPURLParts(u url.URL) (GCPURLParts, error) {
host := strings.ToLower(u.Host)
_, isGCPURL := findGCPURLMatches(host)
if !isGCPURL {
return GCPURLParts{}, errors.New(invalidGCPURLErrorMessage)
}
path := u.Path
if path != "" && path[0] == '/' {
path = path[1:]
}
up := GCPURLParts{
Scheme: u.Scheme,
Host: host,
}
if bucketEndIndex := strings.Index(path, "/"); bucketEndIndex != -1 {
up.BucketName = path[:bucketEndIndex]
up.ObjectKey = path[bucketEndIndex+1:]
} else {
up.BucketName = path
}
up.UnparsedParams = u.RawQuery
return up, nil
}
// URL returns a valid net/url.URL object initialised from the components of GCP URL
func (gUrl *GCPURLParts) URL() url.URL {
path := ""
if gUrl.BucketName != "" {
path += "/" + gUrl.BucketName
if gUrl.ObjectKey != "" {
path += "/" + gUrl.ObjectKey
}
}
rawQuery := gUrl.UnparsedParams
u := url.URL{
Scheme: gUrl.Scheme,
Host: gUrl.Host,
Path: path,
RawQuery: rawQuery,
}
return u
}
func (gUrl *GCPURLParts) String() string {
u := gUrl.URL()
return u.String()
}
func (gUrl *GCPURLParts) IsServiceSyntactically() bool {
if gUrl.Host != "" && gUrl.BucketName == "" {
return true
}
return false
}
func (gUrl *GCPURLParts) IsBucketSyntactically() bool {
if gUrl.BucketName != "" && gUrl.ObjectKey == "" {
return true
}
return false
}
func (gUrl *GCPURLParts) IsObjectSyntactically() bool {
if gUrl.BucketName != "" && gUrl.ObjectKey != "" {
return true
}
return false
}
// IsDirectorySyntactically returns true if the given GCPURLParts
// points to a directory or not based on the path.
func (gUrl *GCPURLParts) IsDirectorySyntactically() bool {
if gUrl.IsObjectSyntactically() && strings.HasSuffix(gUrl.ObjectKey, "/") {
return true
}
return false
}