common/gcpURLParts.go (99 lines of code) (raw):
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
}