2015-12-28 14:51:24 +00:00
|
|
|
package s3
|
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
2015-12-28 17:23:02 +00:00
|
|
|
"net/url"
|
2015-12-28 14:51:24 +00:00
|
|
|
"strings"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Config contains all configuration necessary to connect to an s3 compatible
|
|
|
|
// server.
|
|
|
|
type Config struct {
|
2015-12-28 23:27:29 +00:00
|
|
|
Endpoint string
|
|
|
|
UseHTTP bool
|
2015-12-28 14:51:24 +00:00
|
|
|
KeyID, Secret string
|
|
|
|
Bucket string
|
2016-02-07 19:28:29 +00:00
|
|
|
Prefix string
|
2015-12-28 14:51:24 +00:00
|
|
|
}
|
|
|
|
|
2016-02-07 19:28:29 +00:00
|
|
|
const defaultPrefix = "restic"
|
|
|
|
|
2015-12-28 14:51:24 +00:00
|
|
|
// ParseConfig parses the string s and extracts the s3 config. The two
|
2016-02-07 19:28:29 +00:00
|
|
|
// supported configuration formats are s3://host/bucketname/prefix and
|
|
|
|
// s3:host:bucketname/prefix. The host can also be a valid s3 region
|
|
|
|
// name. If no prefix is given the prefix "restic" will be used.
|
2015-12-28 14:51:24 +00:00
|
|
|
func ParseConfig(s string) (interface{}, error) {
|
2016-02-14 15:01:14 +00:00
|
|
|
switch {
|
|
|
|
case strings.HasPrefix(s, "s3:http"):
|
2016-02-07 19:28:29 +00:00
|
|
|
// assume that a URL has been specified, parse it and
|
|
|
|
// use the host as the endpoint and the path as the
|
|
|
|
// bucket name and prefix
|
2016-02-14 17:10:45 +00:00
|
|
|
url, err := url.Parse(s[3:])
|
2015-12-28 17:23:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if url.Path == "" {
|
|
|
|
return nil, errors.New("s3: bucket name not found")
|
|
|
|
}
|
|
|
|
|
2016-02-14 17:10:45 +00:00
|
|
|
path := strings.SplitN(url.Path[1:], "/", 2)
|
|
|
|
return createConfig(url.Host, path, url.Scheme == "http")
|
2016-02-14 15:01:14 +00:00
|
|
|
case strings.HasPrefix(s, "s3:"):
|
2016-02-14 17:10:45 +00:00
|
|
|
// use the first entry of the path as the endpoint and the
|
|
|
|
// remainder as bucket name and prefix
|
2016-02-07 19:28:29 +00:00
|
|
|
s = s[3:]
|
2016-02-14 17:10:45 +00:00
|
|
|
if strings.HasPrefix(s, "//") {
|
|
|
|
s = s[2:]
|
|
|
|
}
|
|
|
|
path := strings.SplitN(s, "/", 3)
|
|
|
|
return createConfig(path[0], path[1:], false)
|
2016-02-14 15:01:14 +00:00
|
|
|
default:
|
2016-02-07 19:28:29 +00:00
|
|
|
return nil, errors.New("s3: invalid format")
|
|
|
|
}
|
2016-02-14 17:10:45 +00:00
|
|
|
}
|
|
|
|
|
2016-02-14 17:27:00 +00:00
|
|
|
func createConfig(endpoint string, path []string, useHTTP bool) (interface{}, error) {
|
2016-02-14 17:10:45 +00:00
|
|
|
var prefix string
|
|
|
|
switch {
|
|
|
|
case len(path) < 1:
|
2016-02-07 19:28:29 +00:00
|
|
|
return nil, errors.New("s3: invalid format, host/region or bucket name not found")
|
2016-02-14 17:10:45 +00:00
|
|
|
case len(path) == 1:
|
|
|
|
prefix = defaultPrefix
|
|
|
|
default:
|
|
|
|
prefix = strings.TrimRight(path[1], "/")
|
2016-02-07 19:28:29 +00:00
|
|
|
}
|
2016-02-14 17:10:45 +00:00
|
|
|
return Config{
|
|
|
|
Endpoint: endpoint,
|
2016-02-14 17:27:00 +00:00
|
|
|
UseHTTP: useHTTP,
|
2016-02-14 17:10:45 +00:00
|
|
|
Bucket: path[0],
|
|
|
|
Prefix: prefix,
|
|
|
|
}, nil
|
2015-12-28 14:51:24 +00:00
|
|
|
}
|