pkg/blobutil/url.go (51 lines of code) (raw):

package blobutil import ( "fmt" "net/url" "strings" "github.com/pkg/errors" ) // AzureBlobRef contains information parsed from an Azure Blob Storage URL. type AzureBlobRef struct { // StorageBase describes the storage endpoint for the blob (without "blob." prefix) // e.g. "core.windows.net" StorageBase string // Container is the container name for the blob Container string // Blob is the name for the blob (i.e. the rest of the URL after container name) and // may contain slashes (/). e.g. "a.txt", "a/b.txt" Blob string // Scheme contains http or https Scheme string } // ParseBlobURL recognizes a given Azure Blob Storage URL and extracts the information // of the blob such as storage API endpoint, container and blob name, or returns error if the // URL is unrecognized. func ParseBlobURL(blobURL string) (v AzureBlobRef, err error) { u, err := url.Parse(blobURL) if err != nil { return v, errors.Wrapf(err, "cannot parse URL: %q", blobURL) } v.Scheme = strings.ToLower(u.Scheme) if v.Scheme != "http" && v.Scheme != "https" { return v, fmt.Errorf("unsupported scheme in URL: %q", blobURL) } hostParts := strings.Split(u.Host, ".") // {account}.blob.{storageBase} if len(hostParts) < 3 { return v, fmt.Errorf("cannot parse azure blob URL: %q", blobURL) } if strings.ToLower(hostParts[1]) != "blob" { return v, fmt.Errorf("blob host not in *.blob.* format: %q", blobURL) } v.StorageBase = strings.Join(hostParts[2:], ".") // glue them back if v.StorageBase == "" { return v, fmt.Errorf("cannot parse azure storage endpoint in blob URL: %q", blobURL) } var ok bool v.Container, v.Blob, ok = parseAzureContainerBlobNameFromPath(u.Path) if !ok { return v, fmt.Errorf("cannot extract Azure container/blob name from: %q", blobURL) } return v, nil } // parseAzureContainerBlobNameFromPath parses Azure Container and blob name from // path like "/a/b.txt" or "a/b.txt" and can infer the $root container. If it fails // to parse, returns false. func parseAzureContainerBlobNameFromPath(path string) (container string, blob string, parsed bool) { path = strings.TrimPrefix(path, "/") // remove preceeding / if path == "" { return "", "", false } parts := strings.Split(path, "/") if len(parts) == 1 { return "$root", parts[0], true } return parts[0], strings.Join(parts[1:], "/"), true }