Marvin Preuss
1d4ae27878
All checks were successful
continuous-integration/drone/push Build is passing
106 lines
3.1 KiB
Go
106 lines
3.1 KiB
Go
// Copyright 2019 The Go Cloud Development Kit Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
// Package openurl provides helpers for URLMux and URLOpeners in portable APIs.
|
|
package openurl // import "gocloud.dev/internal/openurl"
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// SchemeMap maps URL schemes to values. The zero value is an empty map, ready for use.
|
|
type SchemeMap struct {
|
|
api string
|
|
m map[string]interface{}
|
|
}
|
|
|
|
// Register registers scheme for value; subsequent calls to FromString or
|
|
// FromURL with scheme will return value.
|
|
// api is the portable API name (e.g., "blob"); the same value should always
|
|
// be passed. It should be in all lowercase.
|
|
// typ is the portable type (e.g., "Bucket").
|
|
// Register panics if scheme has already been registered.
|
|
func (m *SchemeMap) Register(api, typ, scheme string, value interface{}) {
|
|
if m.m == nil {
|
|
m.m = map[string]interface{}{}
|
|
}
|
|
if api != strings.ToLower(api) {
|
|
panic(fmt.Errorf("api should be lowercase: %q", api))
|
|
}
|
|
if m.api == "" {
|
|
m.api = api
|
|
} else if m.api != api {
|
|
panic(fmt.Errorf("previously registered using api %q (now %q)", m.api, api))
|
|
}
|
|
if _, exists := m.m[scheme]; exists {
|
|
panic(fmt.Errorf("scheme %q already registered for %s.%s", scheme, api, typ))
|
|
}
|
|
m.m[scheme] = value
|
|
}
|
|
|
|
// FromString parses urlstr as an URL and looks up the value for the URL's scheme.
|
|
func (m *SchemeMap) FromString(typ, urlstr string) (interface{}, *url.URL, error) {
|
|
u, err := url.Parse(urlstr)
|
|
if err != nil {
|
|
return nil, nil, fmt.Errorf("open %s.%s: %v", m.api, typ, err)
|
|
}
|
|
val, err := m.FromURL(typ, u)
|
|
if err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return val, u, nil
|
|
}
|
|
|
|
// FromURL looks up the value for u's scheme.
|
|
func (m *SchemeMap) FromURL(typ string, u *url.URL) (interface{}, error) {
|
|
scheme := u.Scheme
|
|
if scheme == "" {
|
|
return nil, fmt.Errorf("open %s.%s: no scheme in URL %q", m.api, typ, u)
|
|
}
|
|
for _, prefix := range []string{
|
|
fmt.Sprintf("%s+%s+", m.api, strings.ToLower(typ)),
|
|
fmt.Sprintf("%s+", m.api),
|
|
} {
|
|
scheme = strings.TrimPrefix(scheme, prefix)
|
|
}
|
|
v, ok := m.m[scheme]
|
|
if !ok {
|
|
return nil, fmt.Errorf("open %s.%s: no driver registered for %q for URL %q; available schemes: %v", m.api, typ, scheme, u, strings.Join(m.Schemes(), ", "))
|
|
}
|
|
return v, nil
|
|
}
|
|
|
|
// Schemes returns a sorted slice of the registered schemes.
|
|
func (m *SchemeMap) Schemes() []string {
|
|
var schemes []string
|
|
for s := range m.m {
|
|
schemes = append(schemes, s)
|
|
}
|
|
sort.Strings(schemes)
|
|
return schemes
|
|
}
|
|
|
|
// ValidScheme returns true iff scheme has been registered.
|
|
func (m *SchemeMap) ValidScheme(scheme string) bool {
|
|
for s := range m.m {
|
|
if scheme == s {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|