| 
									
										
										
										
											2015-12-28 15:51:24 +01:00
										 |  |  | package s3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-12-28 18:23:02 +01:00
										 |  |  | 	"net/url" | 
					
						
							| 
									
										
										
										
											2016-02-14 11:26:46 -08:00
										 |  |  | 	"path" | 
					
						
							| 
									
										
										
										
											2015-12-28 15:51:24 +01:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2016-08-21 17:46:23 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-23 14:21:03 +02:00
										 |  |  | 	"github.com/restic/restic/internal/errors" | 
					
						
							|  |  |  | 	"github.com/restic/restic/internal/options" | 
					
						
							| 
									
										
										
										
											2015-12-28 15:51:24 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Config contains all configuration necessary to connect to an s3 compatible | 
					
						
							|  |  |  | // server. | 
					
						
							|  |  |  | type Config struct { | 
					
						
							| 
									
										
										
										
											2015-12-29 00:27:29 +01:00
										 |  |  | 	Endpoint      string | 
					
						
							|  |  |  | 	UseHTTP       bool | 
					
						
							| 
									
										
										
										
											2015-12-28 15:51:24 +01:00
										 |  |  | 	KeyID, Secret string | 
					
						
							|  |  |  | 	Bucket        string | 
					
						
							| 
									
										
										
										
											2016-02-07 11:28:29 -08:00
										 |  |  | 	Prefix        string | 
					
						
							| 
									
										
										
										
											2017-05-15 23:37:02 +02:00
										 |  |  | 	Layout        string `option:"layout" help:"use this backend layout (default: auto-detect)"` | 
					
						
							| 
									
										
										
										
											2019-03-26 16:37:07 +01:00
										 |  |  | 	StorageClass  string `option:"storage-class" help:"set S3 storage class (STANDARD, STANDARD_IA, ONEZONE_IA, INTELLIGENT_TIERING or REDUCED_REDUNDANCY)"` | 
					
						
							| 
									
										
										
										
											2017-06-06 00:17:39 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-11 11:48:57 +01:00
										 |  |  | 	Connections   uint   `option:"connections" help:"set a limit for the number of concurrent connections (default: 5)"` | 
					
						
							|  |  |  | 	MaxRetries    uint   `option:"retries" help:"set the number of retries attempted"` | 
					
						
							|  |  |  | 	Region        string `option:"region" help:"set region"` | 
					
						
							|  |  |  | 	BucketLookup  string `option:"bucket-lookup" help:"bucket lookup style: 'auto', 'dns', or 'path'."` | 
					
						
							|  |  |  | 	ListObjectsV1 bool   `option:"list-objects-v1" help:"use deprecated V1 api for ListObjects calls."` | 
					
						
							| 
									
										
										
										
											2017-06-06 00:17:39 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NewConfig returns a new Config with the default values filled in. | 
					
						
							|  |  |  | func NewConfig() Config { | 
					
						
							|  |  |  | 	return Config{ | 
					
						
							| 
									
										
										
										
											2020-11-11 11:48:57 +01:00
										 |  |  | 		Connections:   5, | 
					
						
							|  |  |  | 		ListObjectsV1: false, | 
					
						
							| 
									
										
										
										
											2017-06-06 00:17:39 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-05-15 23:37:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func init() { | 
					
						
							|  |  |  | 	options.Register("s3", Config{}) | 
					
						
							| 
									
										
										
										
											2015-12-28 15:51:24 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ParseConfig parses the string s and extracts the s3 config. The two | 
					
						
							| 
									
										
										
										
											2016-02-07 11:28:29 -08:00
										 |  |  | // supported configuration formats are s3://host/bucketname/prefix and | 
					
						
							| 
									
										
										
										
											2017-11-20 22:21:39 +01:00
										 |  |  | // s3:host/bucketname/prefix. The host can also be a valid s3 region | 
					
						
							| 
									
										
										
										
											2016-02-07 11:28:29 -08:00
										 |  |  | // name. If no prefix is given the prefix "restic" will be used. | 
					
						
							| 
									
										
										
										
											2015-12-28 15:51:24 +01:00
										 |  |  | func ParseConfig(s string) (interface{}, error) { | 
					
						
							| 
									
										
										
										
											2016-02-14 07:01:14 -08:00
										 |  |  | 	switch { | 
					
						
							|  |  |  | 	case strings.HasPrefix(s, "s3:http"): | 
					
						
							| 
									
										
										
										
											2016-02-07 11:28:29 -08: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 09:10:45 -08:00
										 |  |  | 		url, err := url.Parse(s[3:]) | 
					
						
							| 
									
										
										
										
											2015-12-28 18:23:02 +01:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2016-08-29 21:54:50 +02:00
										 |  |  | 			return nil, errors.Wrap(err, "url.Parse") | 
					
						
							| 
									
										
										
										
											2015-12-28 18:23:02 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if url.Path == "" { | 
					
						
							|  |  |  | 			return nil, errors.New("s3: bucket name not found") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-14 09:10:45 -08:00
										 |  |  | 		path := strings.SplitN(url.Path[1:], "/", 2) | 
					
						
							|  |  |  | 		return createConfig(url.Host, path, url.Scheme == "http") | 
					
						
							| 
									
										
										
										
											2016-02-14 09:45:58 -08:00
										 |  |  | 	case strings.HasPrefix(s, "s3://"): | 
					
						
							|  |  |  | 		s = s[5:] | 
					
						
							| 
									
										
										
										
											2016-02-14 07:01:14 -08:00
										 |  |  | 	case strings.HasPrefix(s, "s3:"): | 
					
						
							| 
									
										
										
										
											2016-02-07 11:28:29 -08:00
										 |  |  | 		s = s[3:] | 
					
						
							| 
									
										
										
										
											2016-02-14 07:01:14 -08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2016-02-07 11:28:29 -08:00
										 |  |  | 		return nil, errors.New("s3: invalid format") | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-14 09:45:58 -08:00
										 |  |  | 	// use the first entry of the path as the endpoint and the | 
					
						
							|  |  |  | 	// remainder as bucket name and prefix | 
					
						
							|  |  |  | 	path := strings.SplitN(s, "/", 3) | 
					
						
							|  |  |  | 	return createConfig(path[0], path[1:], false) | 
					
						
							| 
									
										
										
										
											2016-02-14 09:10:45 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-14 11:26:46 -08:00
										 |  |  | func createConfig(endpoint string, p []string, useHTTP bool) (interface{}, error) { | 
					
						
							| 
									
										
										
										
											2017-11-20 22:29:15 +01:00
										 |  |  | 	if len(p) < 1 { | 
					
						
							| 
									
										
										
										
											2016-02-07 11:28:29 -08:00
										 |  |  | 		return nil, errors.New("s3: invalid format, host/region or bucket name not found") | 
					
						
							| 
									
										
										
										
											2017-11-20 22:29:15 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var prefix string | 
					
						
							|  |  |  | 	if len(p) > 1 && p[1] != "" { | 
					
						
							| 
									
										
										
										
											2016-02-14 11:26:46 -08:00
										 |  |  | 		prefix = path.Clean(p[1]) | 
					
						
							| 
									
										
										
										
											2016-02-07 11:28:29 -08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-20 22:29:15 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-06-06 00:17:39 +02:00
										 |  |  | 	cfg := NewConfig() | 
					
						
							|  |  |  | 	cfg.Endpoint = endpoint | 
					
						
							|  |  |  | 	cfg.UseHTTP = useHTTP | 
					
						
							|  |  |  | 	cfg.Bucket = p[0] | 
					
						
							|  |  |  | 	cfg.Prefix = prefix | 
					
						
							|  |  |  | 	return cfg, nil | 
					
						
							| 
									
										
										
										
											2015-12-28 15:51:24 +01:00
										 |  |  | } |