package storage import ( "context" "errors" "fmt" "io" "regexp" "strings" ) var ErrNotExist = errors.New("storage: object does not exist") type Storage interface { Get(ctx context.Context, key string) (io.ReadCloser, error) Put(ctx context.Context, key string, r io.Reader) error Delete(ctx context.Context, key string) error } // StatStorage provides the exact stored object size without downloading it. type StatStorage interface { Stat(ctx context.Context, key string) (int64, error) } // ConditionalStorage writes only when key does not already exist. type ConditionalStorage interface { Storage PutIfAbsent(ctx context.Context, key string, r io.Reader) error } var keyRe = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._:/@%+=-]{0,511}$`) func ValidateKey(key string) error { if !keyRe.MatchString(key) { return fmt.Errorf("storage: invalid key %q", key) } for _, seg := range strings.Split(key, "/") { if seg == "" || seg == "." || seg == ".." { return fmt.Errorf("storage: invalid key %q", key) } } return nil }