Skip to content

Commit

Permalink
Add signurl feature and cases
Browse files Browse the repository at this point in the history
  • Loading branch information
佐钊 committed Aug 16, 2017
1 parent ab58892 commit 254e0fc
Show file tree
Hide file tree
Showing 10 changed files with 453 additions and 34 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
> - 当前版本未提供Bucket管理功能功能,相关功能会在后续版本中开发。
## 版本
> - 当前版本:1.1.1
> - 当前版本:1.2.0
## 运行环境
> - linux, windows
Expand Down
17 changes: 17 additions & 0 deletions lib/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,22 @@ func (cmd *Command) filterError(err error, option *batchOptionType) bool {
return true
}

func (cmd *Command) getOSSOptions(hopMap map[string]interface{}, headers map[string]string) ([]oss.Option, error) {
options := []oss.Option{}
for name, value := range headers {
if strings.HasPrefix(strings.ToLower(name), strings.ToLower(oss.HTTPHeaderOssMetaPrefix)) {
options = append(options, oss.Meta(name[len(oss.HTTPHeaderOssMetaPrefix):], value))
} else {
option, err := getOSSOption(hopMap, name, value)
if err != nil {
return nil, err
}
options = append(options, option)
}
}
return options, nil
}

// GetAllCommands returns all commands list
func GetAllCommands() []interface{} {
return []interface{}{
Expand All @@ -494,6 +510,7 @@ func GetAllCommands() []interface{} {
&restoreCommand,
&createSymlinkCommand,
&readSymlinkCommand,
&signURLCommand,
&hashCommand,
&updateCommand,
}
Expand Down
70 changes: 70 additions & 0 deletions lib/command_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,76 @@ func (s *OssutilCommandSuite) initReadSymlink(cmdline string) error {
return err
}

func (s *OssutilCommandSuite) initSignURL(cmdline string, timeout int64) error {
encodingType := ""
if pos := strings.Index(cmdline, "--encoding-type"); pos != -1 {
subcmdline := cmdline[pos+len("--encoding-type")+1:]
pos2 := strings.Index(subcmdline, " ")
if pos2 != -1 {
encodingType = subcmdline[:pos2]
} else {
encodingType = subcmdline
}
} else {
encodingType = URLEncodingType
}

stimeout := ""
if pos := strings.Index(cmdline, "--timeout"); pos != -1 {
subcmdline := cmdline[pos+len("--timeout")+1:]
pos2 := strings.Index(subcmdline, " ")
if pos2 != -1 {
stimeout = subcmdline[:pos2]
} else {
stimeout = subcmdline
}

itimeout, err := strconv.ParseInt(stimeout, 10, 64)
if err != nil {
return err
}
timeout = itimeout
}

cmds := strings.Split(cmdline, " ")
args := []string{}
for _, cmd := range cmds {
cmd = strings.TrimSpace(cmd)
if cmd != "" {
args = append(args, cmd)
}
}

str := ""
t := strconv.FormatInt(timeout, 10)
options := OptionMapType{
"endpoint": &str,
"accessKeyID": &str,
"accessKeySecret": &str,
"stsToken": &str,
"configFile": &configFile,
"encodingType": &encodingType,
"timeout": &t,
}
err := signURLCommand.Init(args, options)
return err
}

func (s *OssutilCommandSuite) signURL(cmdline string, timeout int64, c *C) string {
out := os.Stdout
testResultFile, _ = os.OpenFile(resultPath, os.O_RDWR|os.O_TRUNC|os.O_CREATE, 0664)
os.Stdout = testResultFile
err := s.initSignURL(cmdline, timeout)
c.Assert(err, IsNil)
err = signURLCommand.RunCommand()
c.Assert(err, IsNil)
os.Stdout = out

results := s.getResult(c)
c.Assert(len(results) >= 1, Equals, true)
return results[0]
}

func (s *OssutilCommandSuite) getFileList(dpath string) ([]string, error) {
fileList := []string{}
err := filepath.Walk(dpath, func(fpath string, f os.FileInfo, err error) error {
Expand Down
11 changes: 11 additions & 0 deletions lib/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ const (
OptionVersion = "version"
OptionPartSize = "partSize"
OptionDisableCRC64 = "disableCRC64"
OptionMethod = "method"
OptionTimeout = "timeout"
)

// the elements show in stat object
Expand Down Expand Up @@ -127,6 +129,15 @@ const (
StorageIA = string(oss.StorageIA)
StorageArchive = string(oss.StorageArchive)
DefaultStorageClass = StorageStandard
DefaultMethod = string(oss.HTTPGet)
MethodPut = string(oss.HTTPPut)
MethodGet = string(oss.HTTPGet)
MethodHead = string(oss.HTTPHead)
MethodPost = string(oss.HTTPPost)
MethodDelete = string(oss.HTTPDelete)
DefaultTimeout = 60
MinTimeout = 0
MaxTimeout = MaxInt64
)

const (
Expand Down
2 changes: 1 addition & 1 deletion lib/help_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ type helpCommandTestCase struct {
err error
}

var subCommands = []string{"help", "config", "update", "mb", "ls", "rm", "stat", "set-acl", "set-meta", "cp"}
var subCommands = []string{"help", "config", "hash", "update", "mb", "ls", "rm", "stat", "set-acl", "set-meta", "cp", "restore", "create-symlink", "read-symlink"}

func (s *OssutilHelpSuite) TestHelpCommand(c *C) {
command := "help"
Expand Down
10 changes: 8 additions & 2 deletions lib/option.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,8 @@ var OptionMap = map[string]Option{
fmt.Sprintf("开启大文件断点续传的文件大小阀值,默认值:%dM,取值范围:%dB-%dB", DefaultBigFileThreshold/1048576, MinBigFileThreshold, MaxBigFileThreshold),
fmt.Sprintf("the threshold of file size, the file size larger than the threshold will use resume upload or download(default: %d), value range is: %d-%d", DefaultBigFileThreshold, MinBigFileThreshold, MaxBigFileThreshold)},
OptionPartSize: Option{"", "--part-size", strconv.FormatInt(DefaultPartSize, 10), OptionTypeInt64, strconv.FormatInt(MinPartSize, 10), strconv.FormatInt(MaxPartSize, 10),
fmt.Sprintf("分片大小,默认情况下ossutil根据文件大小自行计算合适的分片大小值。如果有特殊需求或者需要性能调优,可以设置该值,取值范围:%dB-%dB", DefaultPartSize/1048576, MinPartSize, MaxPartSize),
fmt.Sprintf("Part size, in default situation, ossutil will calculate the suitable part size according to file size. The option is useful when user has special needs or user need to performance tuning, the value range is: %d-%d", DefaultPartSize/1048576, MinPartSize, MaxPartSize)},
fmt.Sprintf("分片大小,单位为Byte,默认情况下ossutil根据文件大小自行计算合适的分片大小值。如果有特殊需求或者需要性能调优,可以设置该值,取值范围:%d-%d(Byte)", MinPartSize, MaxPartSize),
fmt.Sprintf("Part size, the unit is: Byte, in default situation, ossutil will calculate the suitable part size according to file size. The option is useful when user has special needs or user need to performance tuning, the value range is: %d-%d(Byte)", MinPartSize, MaxPartSize)},
OptionDisableCRC64: Option{"", "--disable-crc64", "", OptionTypeFlagTrue, "", "", "该选项关闭crc64,默认情况下,ossutil进行数据传输都打开crc64校验。", "Disable crc64, in default situation, ossutil open crc64 check when transmit data."},
OptionCheckpointDir: Option{"", "--checkpoint-dir", CheckpointDir, OptionTypeString, "", "",
fmt.Sprintf("checkpoint目录的路径(默认值为:%s),断点续传时,操作失败ossutil会自动创建该目录,并在该目录下记录checkpoint信息,操作成功会删除该目录。如果指定了该选项,请确保所指定的目录可以被删除。", CheckpointDir),
Expand All @@ -89,6 +89,12 @@ var OptionMap = map[string]Option{
OptionEncodingType: Option{"", "--encoding-type", "", OptionTypeAlternative, URLEncodingType, "",
fmt.Sprintf("输入的object名或文件名的编码方式,目前只支持url encode,即指定该选项时,取值范围为:%s,如果不指定该选项,则表示object名或文件名未经过编码。bucket名不支持url encode。注意,如果指定了该选项,则形如oss://bucket/object的cloud_url,输入形式为:oss://bucket/url_encode(object),其中oss://bucket/字符串不需要编码。", URLEncodingType),
fmt.Sprintf("the encoding type of object name or file name that user inputs, currently ossutil only supports url encode, which means the value range of the option is: %s, if you do not specify the option, it means the object name or file name that user inputed was not encoded. bucket name does not support url encode. Note, if the option is specified, the cloud_url like: oss://bucket/object should be inputted as: oss://bucket/url_encode(object), the string: oss://bucket/ should not be url encoded.", URLEncodingType)},
OptionMethod: Option{"", "--method", DefaultMethod, OptionTypeAlternative, fmt.Sprintf("%s/%s/%s/%s/%s", MethodPut, MethodGet, MethodHead, MethodPost, MethodDelete), "",
fmt.Sprintf("设置signurl的method,默认值:%s,取值范围:%s/%s/%s/%s/%s。", DefaultMethod, MethodPut, MethodGet, MethodHead, MethodPost, MethodDelete),
fmt.Sprintf("set the method of signurl(default: %s), value range is: %s/%s/%s/%s/%s.", DefaultMethod, MethodPut, MethodGet, MethodHead, MethodPost, MethodDelete)},
OptionTimeout: Option{"", "--timeout", strconv.FormatInt(DefaultTimeout, 10), OptionTypeInt64, strconv.FormatInt(MinTimeout, 10), strconv.FormatInt(MaxTimeout, 10),
fmt.Sprintf("签名url的超时时间,单位为秒,默认值为:%d,取值范围:%d-%d", DefaultTimeout, MinTimeout, MaxTimeout),
fmt.Sprintf("time out of signurl, the unit is: s, default value is %d, the value range is: %d-%d", DefaultTimeout, MinTimeout, MaxTimeout)},
OptionLanguage: Option{"-L", "--language", DefaultLanguage, OptionTypeAlternative, fmt.Sprintf("%s/%s", ChineseLanguage, EnglishLanguage), "",
fmt.Sprintf("设置ossutil工具的语言,默认值:%s,取值范围:%s/%s,若设置成\"%s\",请确保您的系统编码为UTF-8。", DefaultLanguage, ChineseLanguage, EnglishLanguage, ChineseLanguage),
fmt.Sprintf("set the language of ossutil(default: %s), value range is: %s/%s, if you set it to \"%s\", please make sure your system language is UTF-8.", DefaultLanguage, ChineseLanguage, EnglishLanguage, ChineseLanguage)},
Expand Down
42 changes: 13 additions & 29 deletions lib/set_meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ var headerOptionMap = map[string]interface{}{
oss.HTTPHeaderOrigin: oss.Origin,
}

func formatHeaderString(sep string) string {
func formatHeaderString(hopMap map[string]interface{}, sep string) string {
str := ""
for header := range headerOptionMap {
for header := range hopMap {
if header == oss.HTTPHeaderExpires {
str += header + fmt.Sprintf("(time.RFC3339: %s)", time.RFC3339) + sep
} else {
Expand All @@ -35,17 +35,17 @@ func formatHeaderString(sep string) string {
return str
}

func fetchHeaderOptionMap(name string) (interface{}, error) {
for header, f := range headerOptionMap {
func fetchHeaderOptionMap(hopMap map[string]interface{}, name string) (interface{}, error) {
for header, f := range hopMap {
if strings.ToLower(name) == strings.ToLower(header) {
return f, nil
}
}
return nil, fmt.Errorf("unsupported header: %s, please check", name)
}

func getOSSOption(name string, param string) (oss.Option, error) {
if f, err := fetchHeaderOptionMap(name); err == nil {
func getOSSOption(hopMap map[string]interface{}, name string, param string) (oss.Option, error) {
if f, err := fetchHeaderOptionMap(hopMap, name); err == nil {
switch f.(type) {
case func(string) oss.Option:
return f.(func(string) oss.Option)(param), nil
Expand Down Expand Up @@ -101,7 +101,7 @@ var specChineseSetMeta = SpecText{
Headers:
可选的header列表如下:
` + formatHeaderString("\n ") + `
` + formatHeaderString(headerOptionMap, "\n ") + `
以及以` + oss.HTTPHeaderOssMetaPrefix + `开头的header
注意:header不区分大小写,但value区分大小写。
Expand Down Expand Up @@ -185,7 +185,7 @@ var specEnglishSetMeta = SpecText{
Headers:
ossutil supports following headers:
` + formatHeaderString("\n ") + `
` + formatHeaderString(headerOptionMap, "\n ") + `
and headers starts with: ` + oss.HTTPHeaderOssMetaPrefix + `
Warning: headers are case-insensitive, but value are case-sensitive.
Expand Down Expand Up @@ -392,9 +392,9 @@ func (sc *SetMetaCommand) getMetaData(force bool, language string) (string, erro
}

if language == LEnglishLanguage {
fmt.Printf("\nSupported headers:\n %s\n And the headers start with: \"%s\"\n\nPlease enter the header:value#header:value... pair you want to set: ", formatHeaderString("\n "), oss.HTTPHeaderOssMetaPrefix)
fmt.Printf("\nSupported headers:\n %s\n And the headers start with: \"%s\"\n\nPlease enter the header:value#header:value... pair you want to set: ", formatHeaderString(headerOptionMap, "\n "), oss.HTTPHeaderOssMetaPrefix)
} else {
fmt.Printf("\n支持的headers:\n %s\n 以及以\"%s\"开头的headers\n\n请输入你想设置的header:value#header:value...:", formatHeaderString("\n "), oss.HTTPHeaderOssMetaPrefix)
fmt.Printf("\n支持的headers:\n %s\n 以及以\"%s\"开头的headers\n\n请输入你想设置的header:value#header:value...:", formatHeaderString(headerOptionMap, "\n "), oss.HTTPHeaderOssMetaPrefix)
}
if _, err := fmt.Scanln(&str); err != nil {
return "", fmt.Errorf("meta empty, please check, operation is canceled")
Expand All @@ -419,7 +419,7 @@ func (sc *SetMetaCommand) parseHeaders(str string, isDelete bool) (map[string]st
if isDelete && value != "" {
return nil, fmt.Errorf("delete meta for object do no support value for header:%s, please set value:%s to empty", name, value)
}
if _, err := fetchHeaderOptionMap(name); err != nil && !strings.HasPrefix(strings.ToLower(name), strings.ToLower(oss.HTTPHeaderOssMetaPrefix)) {
if _, err := fetchHeaderOptionMap(headerOptionMap, name); err != nil && !strings.HasPrefix(strings.ToLower(name), strings.ToLower(oss.HTTPHeaderOssMetaPrefix)) {
return nil, fmt.Errorf("unsupported header:%s, please try \"help %s\" to see supported headers", name, sc.command.name)
}
headers[name] = value
Expand All @@ -437,7 +437,7 @@ func (sc *SetMetaCommand) setObjectMeta(bucket *oss.Bucket, object string, heade
allheaders = sc.mergeHeader(props, headers, isUpdate, isDelete)
}

options, err := sc.getOSSOptions(allheaders)
options, err := sc.command.getOSSOptions(headerOptionMap, allheaders)
if err != nil {
return err
}
Expand All @@ -448,7 +448,7 @@ func (sc *SetMetaCommand) setObjectMeta(bucket *oss.Bucket, object string, heade
func (sc *SetMetaCommand) mergeHeader(props http.Header, headers map[string]string, isUpdate, isDelete bool) map[string]string {
allheaders := map[string]string{}
for name := range props {
if _, err := fetchHeaderOptionMap(name); err == nil || strings.HasPrefix(strings.ToLower(name), strings.ToLower(oss.HTTPHeaderOssMetaPrefix)) {
if _, err := fetchHeaderOptionMap(headerOptionMap, name); err == nil || strings.HasPrefix(strings.ToLower(name), strings.ToLower(oss.HTTPHeaderOssMetaPrefix)) {
allheaders[strings.ToLower(name)] = props.Get(name)
}
if name == StatACL {
Expand All @@ -468,22 +468,6 @@ func (sc *SetMetaCommand) mergeHeader(props http.Header, headers map[string]stri
return allheaders
}

func (sc *SetMetaCommand) getOSSOptions(headers map[string]string) ([]oss.Option, error) {
options := []oss.Option{}
for name, value := range headers {
if strings.HasPrefix(strings.ToLower(name), strings.ToLower(oss.HTTPHeaderOssMetaPrefix)) {
options = append(options, oss.Meta(name[len(oss.HTTPHeaderOssMetaPrefix):], value))
} else {
option, err := getOSSOption(name, value)
if err != nil {
return nil, err
}
options = append(options, option)
}
}
return options, nil
}

func (sc *SetMetaCommand) ossSetObjectMetaRetry(bucket *oss.Bucket, object string, options ...oss.Option) error {
retryTimes, _ := GetInt(OptionRetryTimes, sc.command.options)
for i := 1; ; i++ {
Expand Down
2 changes: 1 addition & 1 deletion lib/set_meta_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ func (s *OssutilCommandSuite) TestErrSetMeta(c *C) {
}

func (s *OssutilCommandSuite) TestGetOSSOption(c *C) {
_, err := getOSSOption("unknown", "a")
_, err := getOSSOption(headerOptionMap, "unknown", "a")
c.Assert(err, NotNil)
}

Expand Down

0 comments on commit 254e0fc

Please sign in to comment.