浏览代码

add put/get symlink and test

dengwu12 8 年之前
父节点
当前提交
39c9d09a43
共有 5 个文件被更改,包括 119 次插入3 次删除
  1. 44 0
      oss/bucket.go
  2. 66 0
      oss/bucket_test.go
  3. 1 0
      oss/const.go
  4. 5 0
      oss/option.go
  5. 3 3
      oss/type.go

+ 44 - 0
oss/bucket.go

@@ -597,6 +597,50 @@ func (bucket Bucket) GetObjectACL(objectKey string) (GetObjectACLResult, error)
 	return out, err
 }
 
+//
+// PutSymlink 创建符号链接。
+//
+// 符号链接的目标文件类型不能为符号链接。
+// 创建符号链接时: 不检查目标文件是否存在, 不检查目标文件类型是否合法, 不检查目标文件是否有权限访问。
+// 以上检查,都推迟到GetObject等需要访问目标文件的API。
+// 如果试图添加的文件已经存在,并且有访问权限。新添加的文件将覆盖原来的文件。
+// 如果在PutSymlink的时候,携带以x-oss-meta-为前缀的参数,则视为user meta。
+//
+// error 操作无错误为nil,非nil为错误信息。
+//
+func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error {
+	options = append(options, SymlinkTarget(url.QueryEscape(targetObjectKey)))
+	resp, err := bucket.do("PUT", symObjectKey, "symlink", "symlink", options, nil, nil)
+	if err != nil {
+		return err
+	}
+	defer resp.Body.Close()
+	return checkRespCode(resp.StatusCode, []int{http.StatusOK})
+}
+
+//
+// GetSymlink 获取符号链接的目标文件。
+// 如果符号链接不存在返回404。
+//
+// objectKey 获取目标文件的符号链接object。
+//
+// error 操作无错误为nil,非nil为错误信息。当error为nil时,返回的string为目标文件,否则该值无效。
+//
+func (bucket Bucket) GetSymlink(objectKey string) (string, error) {
+	resp, err := bucket.do("GET", objectKey, "symlink", "symlink", nil, nil, nil)
+	if err != nil {
+		return "", err
+	}
+	defer resp.Body.Close()
+
+	targetObjectKey := resp.Headers.Get(HTTPHeaderOSSSymlinkTarget)
+	targetObjectKey, err = url.QueryUnescape(targetObjectKey)
+	if err != nil {
+		return "", err
+	}
+	return targetObjectKey, err
+}
+
 // Private
 func (bucket Bucket) do(method, objectName, urlParams, subResource string, options []Option,
 	data io.Reader, listener ProgressListener) (*Response, error) {

+ 66 - 0
oss/bucket_test.go

@@ -1512,6 +1512,72 @@ func (s *OssBucketSuite) TestUploadBigFile(c *C) {
 	c.Assert(err, IsNil)
 }
 
+func (s *OssBucketSuite) TestSymlink(c *C) {
+	objectName := objectNamePrefix + "符号链接"
+	targetObjectName := objectNamePrefix + "符号链接目标文件"
+
+	err := s.bucket.DeleteObject(objectName)
+	c.Assert(err, IsNil)
+
+	err = s.bucket.DeleteObject(targetObjectName)
+	c.Assert(err, IsNil)
+
+	target, err := s.bucket.GetSymlink(objectName)
+	c.Assert(err, NotNil)
+
+	// Put
+	err = s.bucket.PutSymlink(objectName, targetObjectName)
+	c.Assert(err, IsNil)
+
+	err = s.bucket.PutObject(targetObjectName, strings.NewReader("target"))
+	c.Assert(err, IsNil)
+
+	err = s.bucket.PutSymlink(objectName, targetObjectName)
+	c.Assert(err, IsNil)
+
+	target, err = s.bucket.GetSymlink(objectName)
+	c.Assert(err, IsNil)
+	c.Assert(target, Equals, targetObjectName)
+
+	body, err := s.bucket.GetObject(objectName)
+	c.Assert(err, IsNil)
+	str, err := readBody(body)
+	c.Assert(err, IsNil)
+	c.Assert(str, Equals, "target")
+
+	target, err = s.bucket.GetSymlink(targetObjectName)
+	c.Assert(err, NotNil)
+
+	err = s.bucket.PutObject(objectName, strings.NewReader("src"))
+	c.Assert(err, IsNil)
+
+	body, err = s.bucket.GetObject(objectName)
+	c.Assert(err, IsNil)
+	str, err = readBody(body)
+	c.Assert(err, IsNil)
+	c.Assert(str, Equals, "src")
+
+	// put symlink again
+	err = s.bucket.PutSymlink(objectName, targetObjectName)
+	c.Assert(err, IsNil)
+
+	target, err = s.bucket.GetSymlink(objectName)
+	c.Assert(err, IsNil)
+	c.Assert(target, Equals, targetObjectName)
+
+	body, err = s.bucket.GetObject(objectName)
+	c.Assert(err, IsNil)
+	str, err = readBody(body)
+	c.Assert(err, IsNil)
+	c.Assert(str, Equals, "target")
+
+	err = s.bucket.DeleteObject(objectName)
+	c.Assert(err, IsNil)
+
+	err = s.bucket.DeleteObject(targetObjectName)
+	c.Assert(err, IsNil)
+}
+
 // private
 func createFileAndWrite(fileName string, data []byte) error {
 	os.Remove(fileName)

+ 1 - 0
oss/const.go

@@ -71,6 +71,7 @@ const (
 	HTTPHeaderOssNextAppendPosition          = "X-Oss-Next-Append-Position"
 	HTTPHeaderOssRequestID                   = "X-Oss-Request-Id"
 	HTTPHeaderOssCRC64                       = "X-Oss-Hash-Crc64ecma"
+	HTTPHeaderOSSSymlinkTarget               = "X-Oss-Symlink-Target"
 )
 
 // 其它常量

+ 5 - 0
oss/option.go

@@ -164,6 +164,11 @@ func ObjectACL(acl ACLType) Option {
 	return setHeader(HTTPHeaderOssObjectACL, string(acl))
 }
 
+// SymlinkTarget is an option to set X-Oss-Symlink-Target
+func SymlinkTarget(targetObjectKey string) Option {
+	return setHeader(HTTPHeaderOSSSymlinkTarget, targetObjectKey)
+}
+
 // Origin is an option to set Origin header
 func Origin(value string) Option {
 	return setHeader(HTTPHeaderOrigin, value)

+ 3 - 3
oss/type.go

@@ -190,8 +190,8 @@ type GetBucketCORSResult CORSXML
 
 // GetBucketInfoResult GetBucketInfo请求返回结果
 type GetBucketInfoResult struct {
-	XMLName        xml.Name `xml:"BucketInfo"`
-	BucketInfo     BucketInfo   `xml:"Bucket"`
+	XMLName    xml.Name   `xml:"BucketInfo"`
+	BucketInfo BucketInfo `xml:"Bucket"`
 }
 
 // BucketInfo Bucket信息
@@ -200,7 +200,7 @@ type BucketInfo struct {
 	Name             string    `xml:"Name"`                    // Bucket名称
 	Location         string    `xml:"Location"`                // Bucket所在的数据中心
 	CreationDate     time.Time `xml:"CreationDate"`            // Bucket创建时间
-	ExtranetEndpoint string    `xml:"ExtranetEndpoint"`        // Bucket访问的外网域名 
+	ExtranetEndpoint string    `xml:"ExtranetEndpoint"`        // Bucket访问的外网域名
 	IntranetEndpoint string    `xml:"IntranetEndpoint"`        // Bucket访问的内网域名
 	ACL              string    `xml:"AccessControlList>Grant"` // Bucket权限
 	Owner            Owner     `xml:"Owner"`                   // Bucket拥有者信息