bucket.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. package oss
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "encoding/base64"
  6. "encoding/xml"
  7. "hash"
  8. "hash/crc64"
  9. "io"
  10. "io/ioutil"
  11. "net/http"
  12. "net/url"
  13. "os"
  14. "strconv"
  15. )
  16. // Bucket implements the operations of object.
  17. type Bucket struct {
  18. Client Client
  19. BucketName string
  20. }
  21. //
  22. // PutObject 新建Object,如果Object已存在,覆盖原有Object。
  23. //
  24. // objectKey 上传对象的名称,使用UTF-8编码、长度必须在1-1023字节之间、不能以“/”或者“\”字符开头。
  25. // reader io.Reader读取object的数据。
  26. // options 上传对象时可以指定对象的属性,可用选项有CacheControl、ContentDisposition、ContentEncoding、
  27. // Expires、ServerSideEncryption、ObjectACL、Meta,具体含义请参看
  28. // https://help.aliyun.com/document_detail/oss/api-reference/object/PutObject.html
  29. //
  30. // error 操作无错误为nil,非nil为错误信息。
  31. //
  32. func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Option) error {
  33. opts := addContentType(options, objectKey)
  34. request := &PutObjectRequest{
  35. ObjectKey: objectKey,
  36. Reader: reader,
  37. }
  38. resp, err := bucket.DoPutObject(request, opts)
  39. if err != nil {
  40. return err
  41. }
  42. defer resp.Body.Close()
  43. return err
  44. }
  45. //
  46. // PutObjectFromFile 新建Object,内容从本地文件中读取。
  47. //
  48. // objectKey 上传对象的名称。
  49. // filePath 本地文件,上传对象的值为该文件内容。
  50. // options 上传对象时可以指定对象的属性。详见PutObject的options。
  51. //
  52. // error 操作无错误为nil,非nil为错误信息。
  53. //
  54. func (bucket Bucket) PutObjectFromFile(objectKey, filePath string, options ...Option) error {
  55. fd, err := os.Open(filePath)
  56. if err != nil {
  57. return err
  58. }
  59. defer fd.Close()
  60. opts := addContentType(options, filePath, objectKey)
  61. request := &PutObjectRequest{
  62. ObjectKey: objectKey,
  63. Reader: fd,
  64. }
  65. resp, err := bucket.DoPutObject(request, opts)
  66. if err != nil {
  67. return err
  68. }
  69. defer resp.Body.Close()
  70. return err
  71. }
  72. //
  73. // DoPutObject 上传文件。
  74. //
  75. // request 上传请求。
  76. // options 上传选项。
  77. //
  78. // Response 上传请求返回值。
  79. // error 操作无错误为nil,非nil为错误信息。
  80. //
  81. func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*Response, error) {
  82. isOptSet, _, _ := isOptionSet(options, HTTPHeaderContentType)
  83. if !isOptSet {
  84. options = addContentType(options, request.ObjectKey)
  85. }
  86. listener := getProgressListener(options)
  87. resp, err := bucket.do("PUT", request.ObjectKey, "", "", options, request.Reader, listener)
  88. if err != nil {
  89. return nil, err
  90. }
  91. if bucket.getConfig().IsEnableCRC {
  92. err = checkCRC(resp, "DoPutObject")
  93. if err != nil {
  94. return resp, err
  95. }
  96. }
  97. err = checkRespCode(resp.StatusCode, []int{http.StatusOK})
  98. return resp, err
  99. }
  100. //
  101. // GetObject 下载文件。
  102. //
  103. // objectKey 下载的文件名称。
  104. // options 对象的属性限制项,可选值有Range、IfModifiedSince、IfUnmodifiedSince、IfMatch、
  105. // IfNoneMatch、AcceptEncoding,详细请参考
  106. // https://help.aliyun.com/document_detail/oss/api-reference/object/GetObject.html
  107. //
  108. // io.ReadCloser reader,读取数据后需要close。error为nil时有效。
  109. // error 操作无错误为nil,非nil为错误信息。
  110. //
  111. func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadCloser, error) {
  112. result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options)
  113. if err != nil {
  114. return nil, err
  115. }
  116. return result.Response.Body, nil
  117. }
  118. //
  119. // GetObjectToFile 下载文件。
  120. //
  121. // objectKey 下载的文件名称。
  122. // filePath 下载对象的内容写到该本地文件。
  123. // options 对象的属性限制项。详见GetObject的options。
  124. //
  125. // error 操作无错误时返回error为nil,非nil为错误说明。
  126. //
  127. func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Option) error {
  128. tempFilePath := filePath + TempFileSuffix
  129. // 读取Object内容
  130. result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options)
  131. if err != nil {
  132. return err
  133. }
  134. defer result.Response.Body.Close()
  135. // 如果文件不存在则创建,存在则清空
  136. fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode)
  137. if err != nil {
  138. return err
  139. }
  140. // 存储数据到文件
  141. _, err = io.Copy(fd, result.Response.Body)
  142. fd.Close()
  143. if err != nil {
  144. return err
  145. }
  146. // 比较CRC值
  147. hasRange, _, _ := isOptionSet(options, HTTPHeaderRange)
  148. if bucket.getConfig().IsEnableCRC && !hasRange {
  149. result.Response.ClientCRC = result.ClientCRC.Sum64()
  150. err = checkCRC(result.Response, "GetObjectToFile")
  151. if err != nil {
  152. os.Remove(tempFilePath)
  153. return err
  154. }
  155. }
  156. return os.Rename(tempFilePath, filePath)
  157. }
  158. //
  159. // DoGetObject 下载文件
  160. //
  161. // request 下载请求
  162. // options 对象的属性限制项。详见GetObject的options。
  163. //
  164. // GetObjectResult 下载请求返回值。
  165. // error 操作无错误为nil,非nil为错误信息。
  166. //
  167. func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) {
  168. resp, err := bucket.do("GET", request.ObjectKey, "", "", options, nil, nil)
  169. if err != nil {
  170. return nil, err
  171. }
  172. result := &GetObjectResult{
  173. Response: resp,
  174. }
  175. // crc
  176. var crcCalc hash.Hash64
  177. hasRange, _, _ := isOptionSet(options, HTTPHeaderRange)
  178. if bucket.getConfig().IsEnableCRC && !hasRange {
  179. crcCalc = crc64.New(crcTable())
  180. result.ServerCRC = resp.ServerCRC
  181. result.ClientCRC = crcCalc
  182. }
  183. // progress
  184. listener := getProgressListener(options)
  185. contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64)
  186. resp.Body = ioutil.NopCloser(TeeReader(resp.Body, crcCalc, contentLen, listener, nil))
  187. return result, nil
  188. }
  189. //
  190. // CopyObject 同一个bucket内拷贝Object。
  191. //
  192. // srcObjectKey Copy的源对象。
  193. // destObjectKey Copy的目标对象。
  194. // options Copy对象时,您可以指定源对象的限制条件,满足限制条件时copy,不满足时返回错误,您可以选择如下选项CopySourceIfMatch、
  195. // CopySourceIfNoneMatch、CopySourceIfModifiedSince、CopySourceIfUnmodifiedSince、MetadataDirective。
  196. // Copy对象时,您可以指定目标对象的属性,如CacheControl、ContentDisposition、ContentEncoding、Expires、
  197. // ServerSideEncryption、ObjectACL、Meta,选项的含义请参看
  198. // https://help.aliyun.com/document_detail/oss/api-reference/object/CopyObject.html
  199. //
  200. // error 操作无错误为nil,非nil为错误信息。
  201. //
  202. func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) {
  203. var out CopyObjectResult
  204. options = append(options, CopySource(bucket.BucketName, url.QueryEscape(srcObjectKey)))
  205. resp, err := bucket.do("PUT", destObjectKey, "", "", options, nil, nil)
  206. if err != nil {
  207. return out, err
  208. }
  209. defer resp.Body.Close()
  210. err = xmlUnmarshal(resp.Body, &out)
  211. return out, err
  212. }
  213. //
  214. // CopyObjectTo bucket间拷贝object。
  215. //
  216. // srcObjectKey 源Object名称。源Bucket名称为Bucket.BucketName。
  217. // destBucketName 目标Bucket名称。
  218. // destObjectKey 目标Object名称。
  219. // options Copy选项,详见CopyObject的options。
  220. //
  221. // error 操作无错误为nil,非nil为错误信息。
  222. //
  223. func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey string, options ...Option) (CopyObjectResult, error) {
  224. return bucket.copy(srcObjectKey, destBucketName, destObjectKey, options...)
  225. }
  226. //
  227. // CopyObjectFrom bucket间拷贝object。
  228. //
  229. // srcBucketName 源Bucket名称。
  230. // srcObjectKey 源Object名称。
  231. // destObjectKey 目标Object名称。目标Bucket名称为Bucket.BucketName。
  232. // options Copy选项,详见CopyObject的options。
  233. //
  234. // error 操作无错误为nil,非nil为错误信息。
  235. //
  236. func (bucket Bucket) CopyObjectFrom(srcBucketName, srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) {
  237. destBucketName := bucket.BucketName
  238. var out CopyObjectResult
  239. srcBucket, err := bucket.Client.Bucket(srcBucketName)
  240. if err != nil {
  241. return out, err
  242. }
  243. return srcBucket.copy(srcObjectKey, destBucketName, destObjectKey, options...)
  244. }
  245. func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, options ...Option) (CopyObjectResult, error) {
  246. var out CopyObjectResult
  247. options = append(options, CopySource(bucket.BucketName, url.QueryEscape(srcObjectKey)))
  248. headers := make(map[string]string)
  249. err := handleOptions(headers, options)
  250. if err != nil {
  251. return out, err
  252. }
  253. resp, err := bucket.Client.Conn.Do("PUT", destBucketName, destObjectKey, "", "", headers, nil, 0, nil)
  254. if err != nil {
  255. return out, err
  256. }
  257. defer resp.Body.Close()
  258. err = xmlUnmarshal(resp.Body, &out)
  259. return out, err
  260. }
  261. //
  262. // AppendObject 追加方式上传。
  263. //
  264. // AppendObject参数必须包含position,其值指定从何处进行追加。首次追加操作的position必须为0,
  265. // 后续追加操作的position是Object的当前长度。例如,第一次Append Object请求指定position值为0,
  266. // content-length是65536;那么,第二次Append Object需要指定position为65536。
  267. // 每次操作成功后,响应头部x-oss-next-append-position也会标明下一次追加的position。
  268. //
  269. // objectKey 需要追加的Object。
  270. // reader io.Reader,读取追的内容。
  271. // appendPosition object追加的起始位置。
  272. // destObjectProperties 第一次追加时指定新对象的属性,如CacheControl、ContentDisposition、ContentEncoding、
  273. // Expires、ServerSideEncryption、ObjectACL。
  274. //
  275. // int64 下次追加的开始位置,error为nil空时有效。
  276. // error 操作无错误为nil,非nil为错误信息。
  277. //
  278. func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosition int64, options ...Option) (int64, error) {
  279. request := &AppendObjectRequest{
  280. ObjectKey: objectKey,
  281. Reader: reader,
  282. Position: appendPosition,
  283. }
  284. result, err := bucket.DoAppendObject(request, options)
  285. return result.NextPosition, err
  286. }
  287. //
  288. // DoAppendObject 追加上传。
  289. //
  290. // request 追加上传请求。
  291. // options 追加上传选项。
  292. //
  293. // AppendObjectResult 追加上传请求返回值。
  294. // error 操作无错误为nil,非nil为错误信息。
  295. //
  296. func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Option) (*AppendObjectResult, error) {
  297. params := "append&position=" + strconv.FormatInt(request.Position, 10)
  298. headers := make(map[string]string)
  299. opts := addContentType(options, request.ObjectKey)
  300. handleOptions(headers, opts)
  301. var initCRC uint64
  302. isCRCSet, initCRCOpt, _ := isOptionSet(options, initCRC64)
  303. if isCRCSet {
  304. initCRC = initCRCOpt.(uint64)
  305. }
  306. listener := getProgressListener(options)
  307. handleOptions(headers, opts)
  308. resp, err := bucket.Client.Conn.Do("POST", bucket.BucketName, request.ObjectKey, params, params, headers,
  309. request.Reader, initCRC, listener)
  310. if err != nil {
  311. return nil, err
  312. }
  313. defer resp.Body.Close()
  314. nextPosition, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderOssNextAppendPosition), 10, 64)
  315. result := &AppendObjectResult{
  316. NextPosition: nextPosition,
  317. CRC: resp.ServerCRC,
  318. }
  319. if bucket.getConfig().IsEnableCRC && isCRCSet {
  320. err = checkCRC(resp, "AppendObject")
  321. if err != nil {
  322. return result, err
  323. }
  324. }
  325. return result, nil
  326. }
  327. //
  328. // DeleteObject 删除Object。
  329. //
  330. // objectKey 待删除Object。
  331. //
  332. // error 操作无错误为nil,非nil为错误信息。
  333. //
  334. func (bucket Bucket) DeleteObject(objectKey string) error {
  335. resp, err := bucket.do("DELETE", objectKey, "", "", nil, nil, nil)
  336. if err != nil {
  337. return err
  338. }
  339. defer resp.Body.Close()
  340. return checkRespCode(resp.StatusCode, []int{http.StatusNoContent})
  341. }
  342. //
  343. // DeleteObjects 批量删除object。
  344. //
  345. // objectKeys 待删除object类表。
  346. // options 删除选项,DeleteObjectsQuiet,是否是安静模式,默认不使用。
  347. //
  348. // DeleteObjectsResult 非安静模式的的返回值。
  349. // error 操作无错误为nil,非nil为错误信息。
  350. //
  351. func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (DeleteObjectsResult, error) {
  352. out := DeleteObjectsResult{}
  353. dxml := deleteXML{}
  354. for _, key := range objectKeys {
  355. dxml.Objects = append(dxml.Objects, DeleteObject{Key: key})
  356. }
  357. isQuiet, _ := findOption(options, deleteObjectsQuiet, false)
  358. dxml.Quiet = isQuiet.(bool)
  359. encode := "&encoding-type=url"
  360. bs, err := xml.Marshal(dxml)
  361. if err != nil {
  362. return out, err
  363. }
  364. buffer := new(bytes.Buffer)
  365. buffer.Write(bs)
  366. contentType := http.DetectContentType(buffer.Bytes())
  367. options = append(options, ContentType(contentType))
  368. sum := md5.Sum(bs)
  369. b64 := base64.StdEncoding.EncodeToString(sum[:])
  370. options = append(options, ContentMD5(b64))
  371. resp, err := bucket.do("POST", "", "delete"+encode, "delete", options, buffer, nil)
  372. if err != nil {
  373. return out, err
  374. }
  375. defer resp.Body.Close()
  376. if !dxml.Quiet {
  377. if err = xmlUnmarshal(resp.Body, &out); err == nil {
  378. err = decodeDeleteObjectsResult(&out)
  379. }
  380. }
  381. return out, err
  382. }
  383. //
  384. // IsObjectExist object是否存在。
  385. //
  386. // bool object是否存在,true存在,false不存在。error为nil时有效。
  387. //
  388. // error 操作无错误为nil,非nil为错误信息。
  389. //
  390. func (bucket Bucket) IsObjectExist(objectKey string) (bool, error) {
  391. _, err := bucket.GetObjectMeta(objectKey)
  392. if err == nil {
  393. return true, nil
  394. }
  395. switch err.(type) {
  396. case ServiceError:
  397. if err.(ServiceError).StatusCode == 404 && err.(ServiceError).Code == "NoSuchKey" {
  398. return false, nil
  399. }
  400. }
  401. return false, err
  402. }
  403. //
  404. // ListObjects 获得Bucket下筛选后所有的object的列表。
  405. //
  406. // options ListObject的筛选行为。Prefix指定的前缀、MaxKeys最大数目、Marker第一个开始、Delimiter对Object名字进行分组的字符。
  407. //
  408. // 您有如下8个object,my-object-1, my-object-11, my-object-2, my-object-21,
  409. // my-object-22, my-object-3, my-object-31, my-object-32。如果您指定了Prefix为my-object-2,
  410. // 则返回my-object-2, my-object-21, my-object-22三个object。如果您指定了Marker为my-object-22,
  411. // 则返回my-object-3, my-object-31, my-object-32三个object。如果您指定MaxKeys则每次最多返回MaxKeys个,
  412. // 最后一次可能不足。这三个参数可以组合使用,实现分页等功能。如果把prefix设为某个文件夹名,就可以罗列以此prefix开头的文件,
  413. // 即该文件夹下递归的所有的文件和子文件夹。如果再把delimiter设置为"/"时,返回值就只罗列该文件夹下的文件,该文件夹下的子文件名
  414. // 返回在CommonPrefixes部分,子文件夹下递归的文件和文件夹不被显示。例如一个bucket存在三个object,fun/test.jpg、
  415. // fun/movie/001.avi、fun/movie/007.avi。若设定prefix为"fun/",则返回三个object;如果增加设定
  416. // delimiter为"/",则返回文件"fun/test.jpg"和前缀"fun/movie/",即实现了文件夹的逻辑。
  417. //
  418. // 常用场景,请参数示例sample/list_object.go。
  419. //
  420. // ListObjectsResponse 操作成功后的返回值,成员Objects为bucket中对象列表。error为nil时该返回值有效。
  421. //
  422. func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) {
  423. var out ListObjectsResult
  424. options = append(options, EncodingType("url"))
  425. params, err := handleParams(options)
  426. if err != nil {
  427. return out, err
  428. }
  429. resp, err := bucket.do("GET", "", params, "", nil, nil, nil)
  430. if err != nil {
  431. return out, err
  432. }
  433. defer resp.Body.Close()
  434. err = xmlUnmarshal(resp.Body, &out)
  435. if err != nil {
  436. return out, err
  437. }
  438. err = decodeListObjectsResult(&out)
  439. return out, err
  440. }
  441. //
  442. // SetObjectMeta 设置Object的Meta。
  443. //
  444. // objectKey object
  445. // options 指定对象的属性,有以下可选项CacheControl、ContentDisposition、ContentEncoding、Expires、
  446. // ServerSideEncryption、Meta。
  447. //
  448. // error 操作无错误时error为nil,非nil为错误信息。
  449. //
  450. func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error {
  451. options = append(options, MetadataDirective(MetaReplace))
  452. _, err := bucket.CopyObject(objectKey, objectKey, options...)
  453. return err
  454. }
  455. //
  456. // GetObjectDetailedMeta 查询Object的头信息。
  457. //
  458. // objectKey object名称。
  459. // objectPropertyConstraints 对象的属性限制项,满足时正常返回,不满足时返回错误。现在项有IfModifiedSince、IfUnmodifiedSince、
  460. // IfMatch、IfNoneMatch。具体含义请参看 https://help.aliyun.com/document_detail/oss/api-reference/object/HeadObject.html
  461. //
  462. // http.Header 对象的meta,error为nil时有效。
  463. // error 操作无错误为nil,非nil为错误信息。
  464. //
  465. func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) (http.Header, error) {
  466. resp, err := bucket.do("HEAD", objectKey, "", "", options, nil, nil)
  467. if err != nil {
  468. return nil, err
  469. }
  470. defer resp.Body.Close()
  471. return resp.Headers, nil
  472. }
  473. //
  474. // GetObjectMeta 查询Object的头信息。
  475. //
  476. // GetObjectMeta相比GetObjectDetailedMeta更轻量,仅返回指定Object的少量基本meta信息,
  477. // 包括该Object的ETag、Size(对象大小)、LastModified,其中Size由响应头Content-Length的数值表示。
  478. //
  479. // objectKey object名称。
  480. //
  481. // http.Header 对象的meta,error为nil时有效。
  482. // error 操作无错误为nil,非nil为错误信息。
  483. //
  484. func (bucket Bucket) GetObjectMeta(objectKey string) (http.Header, error) {
  485. resp, err := bucket.do("GET", objectKey, "?objectMeta", "", nil, nil, nil)
  486. if err != nil {
  487. return nil, err
  488. }
  489. defer resp.Body.Close()
  490. return resp.Headers, nil
  491. }
  492. //
  493. // SetObjectACL 修改Object的ACL权限。
  494. //
  495. // 只有Bucket Owner才有权限调用PutObjectACL来修改Object的ACL。Object ACL优先级高于Bucket ACL。
  496. // 例如Bucket ACL是private的,而Object ACL是public-read-write的,则访问这个Object时,
  497. // 先判断Object的ACL,所以所有用户都拥有这个Object的访问权限,即使这个Bucket是private bucket。
  498. // 如果某个Object从来没设置过ACL,则访问权限遵循Bucket ACL。
  499. //
  500. // Object的读操作包括GetObject,HeadObject,CopyObject和UploadPartCopy中的对source object的读;
  501. // Object的写操作包括:PutObject,PostObject,AppendObject,DeleteObject,
  502. // DeleteMultipleObjects,CompleteMultipartUpload以及CopyObject对新的Object的写。
  503. //
  504. // objectKey 设置权限的object。
  505. // objectAcl 对象权限。可选值PrivateACL(私有读写)、PublicReadACL(公共读私有写)、PublicReadWriteACL(公共读写)。
  506. //
  507. // error 操作无错误为nil,非nil为错误信息。
  508. //
  509. func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType) error {
  510. options := []Option{ObjectACL(objectACL)}
  511. resp, err := bucket.do("PUT", objectKey, "acl", "acl", options, nil, nil)
  512. if err != nil {
  513. return err
  514. }
  515. defer resp.Body.Close()
  516. return checkRespCode(resp.StatusCode, []int{http.StatusOK})
  517. }
  518. //
  519. // GetObjectACL 获取对象的ACL权限。
  520. //
  521. // objectKey 获取权限的object。
  522. //
  523. // GetObjectAclResponse 获取权限操作返回值,error为nil时有效。GetObjectAclResponse.Acl为对象的权限。
  524. // error 操作无错误为nil,非nil为错误信息。
  525. //
  526. func (bucket Bucket) GetObjectACL(objectKey string) (GetObjectACLResult, error) {
  527. var out GetObjectACLResult
  528. resp, err := bucket.do("GET", objectKey, "acl", "acl", nil, nil, nil)
  529. if err != nil {
  530. return out, err
  531. }
  532. defer resp.Body.Close()
  533. err = xmlUnmarshal(resp.Body, &out)
  534. return out, err
  535. }
  536. //
  537. // PutSymlink 创建符号链接。
  538. //
  539. // 符号链接的目标文件类型不能为符号链接。
  540. // 创建符号链接时: 不检查目标文件是否存在, 不检查目标文件类型是否合法, 不检查目标文件是否有权限访问。
  541. // 以上检查,都推迟到GetObject等需要访问目标文件的API。
  542. // 如果试图添加的文件已经存在,并且有访问权限。新添加的文件将覆盖原来的文件。
  543. // 如果在PutSymlink的时候,携带以x-oss-meta-为前缀的参数,则视为user meta。
  544. //
  545. // symObjectKey 要创建的符号链接文件。
  546. // targetObjectKey 目标文件。
  547. //
  548. // error 操作无错误为nil,非nil为错误信息。
  549. //
  550. func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error {
  551. options = append(options, symlinkTarget(url.QueryEscape(targetObjectKey)))
  552. resp, err := bucket.do("PUT", symObjectKey, "symlink", "symlink", options, nil, nil)
  553. if err != nil {
  554. return err
  555. }
  556. defer resp.Body.Close()
  557. return checkRespCode(resp.StatusCode, []int{http.StatusOK})
  558. }
  559. //
  560. // GetSymlink 获取符号链接的目标文件。
  561. // 如果符号链接不存在返回404。
  562. //
  563. // objectKey 获取目标文件的符号链接object。
  564. //
  565. // error 操作无错误为nil,非nil为错误信息。当error为nil时,返回的string为目标文件,否则该值无效。
  566. //
  567. func (bucket Bucket) GetSymlink(objectKey string) (http.Header, error) {
  568. resp, err := bucket.do("GET", objectKey, "symlink", "symlink", nil, nil, nil)
  569. if err != nil {
  570. return nil, err
  571. }
  572. defer resp.Body.Close()
  573. targetObjectKey := resp.Headers.Get(HTTPHeaderOssSymlinkTarget)
  574. targetObjectKey, err = url.QueryUnescape(targetObjectKey)
  575. if err != nil {
  576. return resp.Headers, err
  577. }
  578. resp.Headers.Set(HTTPHeaderOssSymlinkTarget, targetObjectKey)
  579. return resp.Headers, err
  580. }
  581. //
  582. // RestoreObject 恢复处于冷冻状态的归档类型Object进入读就绪状态。
  583. //
  584. // 如果是针对该Object第一次调用restore接口,则返回成功。
  585. // 如果已经成功调用过restore接口,且restore没有完全完成,再次调用时返回409,错误码:RestoreAlreadyInProgress。
  586. // 如果已经成功调用过restore接口,且restore已经完成,再次调用时返回成功,且会将object的可下载时间延长一天,最多延长7天。
  587. //
  588. // objectKey 需要恢复状态的object名称。
  589. //
  590. // error 操作无错误为nil,非nil为错误信息。
  591. //
  592. func (bucket Bucket) RestoreObject(objectKey string) error {
  593. resp, err := bucket.do("POST", objectKey, "restore", "restore", nil, nil, nil)
  594. if err != nil {
  595. return err
  596. }
  597. defer resp.Body.Close()
  598. return checkRespCode(resp.StatusCode, []int{http.StatusOK, http.StatusAccepted})
  599. }
  600. // Private
  601. func (bucket Bucket) do(method, objectName, urlParams, subResource string, options []Option,
  602. data io.Reader, listener ProgressListener) (*Response, error) {
  603. headers := make(map[string]string)
  604. err := handleOptions(headers, options)
  605. if err != nil {
  606. return nil, err
  607. }
  608. return bucket.Client.Conn.Do(method, bucket.BucketName, objectName,
  609. urlParams, subResource, headers, data, 0, listener)
  610. }
  611. func (bucket Bucket) getConfig() *Config {
  612. return bucket.Client.Config
  613. }
  614. func addContentType(options []Option, keys ...string) []Option {
  615. typ := TypeByExtension("")
  616. for _, key := range keys {
  617. typ = TypeByExtension(key)
  618. if typ != "" {
  619. break
  620. }
  621. }
  622. if typ == "" {
  623. typ = "application/octet-stream"
  624. }
  625. opts := []Option{ContentType(typ)}
  626. opts = append(opts, options...)
  627. return opts
  628. }