bucket.go 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289
  1. package oss
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "encoding/base64"
  6. "encoding/xml"
  7. "fmt"
  8. "hash"
  9. "hash/crc64"
  10. "io"
  11. "net/http"
  12. "net/url"
  13. "os"
  14. "strconv"
  15. "strings"
  16. "time"
  17. )
  18. // Bucket implements the operations of object.
  19. type Bucket struct {
  20. Client Client
  21. BucketName string
  22. }
  23. // PutObject creates a new object and it will overwrite the original one if it exists already.
  24. //
  25. // objectKey the object key in UTF-8 encoding. The length must be between 1 and 1023, and cannot start with "/" or "\".
  26. // reader io.Reader instance for reading the data for uploading
  27. // options the options for uploading the object. The valid options here are CacheControl, ContentDisposition, ContentEncoding
  28. // Expires, ServerSideEncryption, ObjectACL and Meta. Refer to the link below for more details.
  29. // https://help.aliyun.com/document_detail/oss/api-reference/object/PutObject.html
  30. //
  31. // error it's nil if no error, otherwise it's an error object.
  32. //
  33. func (bucket Bucket) PutObject(objectKey string, reader io.Reader, options ...Option) error {
  34. opts := AddContentType(options, objectKey)
  35. request := &PutObjectRequest{
  36. ObjectKey: objectKey,
  37. Reader: reader,
  38. }
  39. resp, err := bucket.DoPutObject(request, opts)
  40. if err != nil {
  41. return err
  42. }
  43. defer resp.Body.Close()
  44. return err
  45. }
  46. // PutObjectFromFile creates a new object from the local file.
  47. //
  48. // objectKey object key.
  49. // filePath the local file path to upload.
  50. // options the options for uploading the object. Refer to the parameter options in PutObject for more details.
  51. //
  52. // error it's nil if no error, otherwise it's an error object.
  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. // DoPutObject does the actual upload work.
  73. //
  74. // request the request instance for uploading an object.
  75. // options the options for uploading an object.
  76. //
  77. // Response the response from OSS.
  78. // error it's nil if no error, otherwise it's an error object.
  79. //
  80. func (bucket Bucket) DoPutObject(request *PutObjectRequest, options []Option) (*Response, error) {
  81. isOptSet, _, _ := IsOptionSet(options, HTTPHeaderContentType)
  82. if !isOptSet {
  83. options = AddContentType(options, request.ObjectKey)
  84. }
  85. listener := GetProgressListener(options)
  86. params := map[string]interface{}{}
  87. resp, err := bucket.do("PUT", request.ObjectKey, params, 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. // GetObject downloads the object.
  101. //
  102. // objectKey the object key.
  103. // options the options for downloading the object. The valid values are: Range, IfModifiedSince, IfUnmodifiedSince, IfMatch,
  104. // IfNoneMatch, AcceptEncoding. For more details, please check out:
  105. // https://help.aliyun.com/document_detail/oss/api-reference/object/GetObject.html
  106. //
  107. // io.ReadCloser reader instance for reading data from response. It must be called close() after the usage and only valid when error is nil.
  108. // error it's nil if no error, otherwise it's an error object.
  109. //
  110. func (bucket Bucket) GetObject(objectKey string, options ...Option) (io.ReadCloser, error) {
  111. result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options)
  112. if err != nil {
  113. return nil, err
  114. }
  115. return result.Response, nil
  116. }
  117. // GetObjectToFile downloads the data to a local file.
  118. //
  119. // objectKey the object key to download.
  120. // filePath the local file to store the object data.
  121. // options the options for downloading the object. Refer to the parameter options in method GetObject for more details.
  122. //
  123. // error it's nil if no error, otherwise it's an error object.
  124. //
  125. func (bucket Bucket) GetObjectToFile(objectKey, filePath string, options ...Option) error {
  126. tempFilePath := filePath + TempFileSuffix
  127. // Calls the API to actually download the object. Returns the result instance.
  128. result, err := bucket.DoGetObject(&GetObjectRequest{objectKey}, options)
  129. if err != nil {
  130. return err
  131. }
  132. defer result.Response.Close()
  133. // If the local file does not exist, create a new one. If it exists, overwrite it.
  134. fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode)
  135. if err != nil {
  136. return err
  137. }
  138. // Copy the data to the local file path.
  139. _, err = io.Copy(fd, result.Response.Body)
  140. fd.Close()
  141. if err != nil {
  142. return err
  143. }
  144. // Compares the CRC value
  145. hasRange, _, _ := IsOptionSet(options, HTTPHeaderRange)
  146. encodeOpt, _ := FindOption(options, HTTPHeaderAcceptEncoding, nil)
  147. acceptEncoding := ""
  148. if encodeOpt != nil {
  149. acceptEncoding = encodeOpt.(string)
  150. }
  151. if bucket.GetConfig().IsEnableCRC && !hasRange && acceptEncoding != "gzip" {
  152. result.Response.ClientCRC = result.ClientCRC.Sum64()
  153. err = CheckCRC(result.Response, "GetObjectToFile")
  154. if err != nil {
  155. os.Remove(tempFilePath)
  156. return err
  157. }
  158. }
  159. return os.Rename(tempFilePath, filePath)
  160. }
  161. // DoGetObject is the actual API that gets the object. It's the internal function called by other public APIs.
  162. //
  163. // request the request to download the object.
  164. // options the options for downloading the file. Checks out the parameter options in method GetObject.
  165. //
  166. // GetObjectResult the result instance of getting the object.
  167. // error it's nil if no error, otherwise it's an error object.
  168. //
  169. func (bucket Bucket) DoGetObject(request *GetObjectRequest, options []Option) (*GetObjectResult, error) {
  170. params, _ := GetRawParams(options)
  171. resp, err := bucket.do("GET", request.ObjectKey, params, options, nil, nil)
  172. if err != nil {
  173. return nil, err
  174. }
  175. result := &GetObjectResult{
  176. Response: resp,
  177. }
  178. // CRC
  179. var crcCalc hash.Hash64
  180. hasRange, _, _ := IsOptionSet(options, HTTPHeaderRange)
  181. if bucket.GetConfig().IsEnableCRC && !hasRange {
  182. crcCalc = crc64.New(CrcTable())
  183. result.ServerCRC = resp.ServerCRC
  184. result.ClientCRC = crcCalc
  185. }
  186. // Progress
  187. listener := GetProgressListener(options)
  188. contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64)
  189. resp.Body = TeeReader(resp.Body, crcCalc, contentLen, listener, nil)
  190. return result, nil
  191. }
  192. // CopyObject copies the object inside the bucket.
  193. //
  194. // srcObjectKey the source object to copy.
  195. // destObjectKey the target object to copy.
  196. // options options for copying an object. You can specify the conditions of copy. The valid conditions are CopySourceIfMatch,
  197. // CopySourceIfNoneMatch, CopySourceIfModifiedSince, CopySourceIfUnmodifiedSince, MetadataDirective.
  198. // Also you can specify the target object's attributes, such as CacheControl, ContentDisposition, ContentEncoding, Expires,
  199. // ServerSideEncryption, ObjectACL, Meta. Refer to the link below for more details :
  200. // https://help.aliyun.com/document_detail/oss/api-reference/object/CopyObject.html
  201. //
  202. // error it's nil if no error, otherwise it's an error object.
  203. //
  204. func (bucket Bucket) CopyObject(srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) {
  205. var out CopyObjectResult
  206. //first find version id
  207. versionIdKey := "versionId"
  208. versionId, _ := FindOption(options, versionIdKey, nil)
  209. if versionId == nil {
  210. options = append(options, CopySource(bucket.BucketName, url.QueryEscape(srcObjectKey)))
  211. } else {
  212. options = DeleteOption(options, versionIdKey)
  213. options = append(options, CopySourceVersion(bucket.BucketName, url.QueryEscape(srcObjectKey), versionId.(string)))
  214. }
  215. params := map[string]interface{}{}
  216. resp, err := bucket.do("PUT", destObjectKey, params, options, nil, nil)
  217. if err != nil {
  218. return out, err
  219. }
  220. defer resp.Body.Close()
  221. err = xmlUnmarshal(resp.Body, &out)
  222. return out, err
  223. }
  224. // CopyObjectTo copies the object to another bucket.
  225. //
  226. // srcObjectKey source object key. The source bucket is Bucket.BucketName .
  227. // destBucketName target bucket name.
  228. // destObjectKey target object name.
  229. // options copy options, check out parameter options in function CopyObject for more details.
  230. //
  231. // error it's nil if no error, otherwise it's an error object.
  232. //
  233. func (bucket Bucket) CopyObjectTo(destBucketName, destObjectKey, srcObjectKey string, options ...Option) (CopyObjectResult, error) {
  234. return bucket.copy(srcObjectKey, destBucketName, destObjectKey, options...)
  235. }
  236. //
  237. // CopyObjectFrom copies the object to another bucket.
  238. //
  239. // srcBucketName source bucket name.
  240. // srcObjectKey source object name.
  241. // destObjectKey target object name. The target bucket name is Bucket.BucketName.
  242. // options copy options. Check out parameter options in function CopyObject.
  243. //
  244. // error it's nil if no error, otherwise it's an error object.
  245. //
  246. func (bucket Bucket) CopyObjectFrom(srcBucketName, srcObjectKey, destObjectKey string, options ...Option) (CopyObjectResult, error) {
  247. destBucketName := bucket.BucketName
  248. var out CopyObjectResult
  249. srcBucket, err := bucket.Client.Bucket(srcBucketName)
  250. if err != nil {
  251. return out, err
  252. }
  253. return srcBucket.copy(srcObjectKey, destBucketName, destObjectKey, options...)
  254. }
  255. func (bucket Bucket) copy(srcObjectKey, destBucketName, destObjectKey string, options ...Option) (CopyObjectResult, error) {
  256. var out CopyObjectResult
  257. //first find version id
  258. versionIdKey := "versionId"
  259. versionId, _ := FindOption(options, versionIdKey, nil)
  260. if versionId == nil {
  261. options = append(options, CopySource(bucket.BucketName, url.QueryEscape(srcObjectKey)))
  262. } else {
  263. options = DeleteOption(options, versionIdKey)
  264. options = append(options, CopySourceVersion(bucket.BucketName, url.QueryEscape(srcObjectKey), versionId.(string)))
  265. }
  266. headers := make(map[string]string)
  267. err := handleOptions(headers, options)
  268. if err != nil {
  269. return out, err
  270. }
  271. params := map[string]interface{}{}
  272. resp, err := bucket.Client.Conn.Do("PUT", destBucketName, destObjectKey, params, headers, nil, 0, nil)
  273. // get response header
  274. respHeader, _ := FindOption(options, responseHeader, nil)
  275. if respHeader != nil {
  276. pRespHeader := respHeader.(*http.Header)
  277. *pRespHeader = resp.Headers
  278. }
  279. if err != nil {
  280. return out, err
  281. }
  282. defer resp.Body.Close()
  283. err = xmlUnmarshal(resp.Body, &out)
  284. return out, err
  285. }
  286. // AppendObject uploads the data in the way of appending an existing or new object.
  287. //
  288. // AppendObject the parameter appendPosition specifies which postion (in the target object) to append. For the first append (to a non-existing file),
  289. // the appendPosition should be 0. The appendPosition in the subsequent calls will be the current object length.
  290. // For example, the first appendObject's appendPosition is 0 and it uploaded 65536 bytes data, then the second call's position is 65536.
  291. // The response header x-oss-next-append-position after each successful request also specifies the next call's append position (so the caller need not to maintain this information).
  292. //
  293. // objectKey the target object to append to.
  294. // reader io.Reader. The read instance for reading the data to append.
  295. // appendPosition the start position to append.
  296. // destObjectProperties the options for the first appending, such as CacheControl, ContentDisposition, ContentEncoding,
  297. // Expires, ServerSideEncryption, ObjectACL.
  298. //
  299. // int64 the next append position, it's valid when error is nil.
  300. // error it's nil if no error, otherwise it's an error object.
  301. //
  302. func (bucket Bucket) AppendObject(objectKey string, reader io.Reader, appendPosition int64, options ...Option) (int64, error) {
  303. request := &AppendObjectRequest{
  304. ObjectKey: objectKey,
  305. Reader: reader,
  306. Position: appendPosition,
  307. }
  308. result, err := bucket.DoAppendObject(request, options)
  309. if err != nil {
  310. return appendPosition, err
  311. }
  312. return result.NextPosition, err
  313. }
  314. // DoAppendObject is the actual API that does the object append.
  315. //
  316. // request the request object for appending object.
  317. // options the options for appending object.
  318. //
  319. // AppendObjectResult the result object for appending object.
  320. // error it's nil if no error, otherwise it's an error object.
  321. //
  322. func (bucket Bucket) DoAppendObject(request *AppendObjectRequest, options []Option) (*AppendObjectResult, error) {
  323. params := map[string]interface{}{}
  324. params["append"] = nil
  325. params["position"] = strconv.FormatInt(request.Position, 10)
  326. headers := make(map[string]string)
  327. opts := AddContentType(options, request.ObjectKey)
  328. handleOptions(headers, opts)
  329. var initCRC uint64
  330. isCRCSet, initCRCOpt, _ := IsOptionSet(options, initCRC64)
  331. if isCRCSet {
  332. initCRC = initCRCOpt.(uint64)
  333. }
  334. listener := GetProgressListener(options)
  335. handleOptions(headers, opts)
  336. resp, err := bucket.Client.Conn.Do("POST", bucket.BucketName, request.ObjectKey, params, headers,
  337. request.Reader, initCRC, listener)
  338. // get response header
  339. respHeader, _ := FindOption(options, responseHeader, nil)
  340. if respHeader != nil {
  341. pRespHeader := respHeader.(*http.Header)
  342. *pRespHeader = resp.Headers
  343. }
  344. if err != nil {
  345. return nil, err
  346. }
  347. defer resp.Body.Close()
  348. nextPosition, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderOssNextAppendPosition), 10, 64)
  349. result := &AppendObjectResult{
  350. NextPosition: nextPosition,
  351. CRC: resp.ServerCRC,
  352. }
  353. if bucket.GetConfig().IsEnableCRC && isCRCSet {
  354. err = CheckCRC(resp, "AppendObject")
  355. if err != nil {
  356. return result, err
  357. }
  358. }
  359. return result, nil
  360. }
  361. // DeleteObject deletes the object.
  362. //
  363. // objectKey the object key to delete.
  364. //
  365. // error it's nil if no error, otherwise it's an error object.
  366. //
  367. func (bucket Bucket) DeleteObject(objectKey string, options ...Option) error {
  368. params, _ := GetRawParams(options)
  369. resp, err := bucket.do("DELETE", objectKey, params, options, nil, nil)
  370. if err != nil {
  371. return err
  372. }
  373. defer resp.Body.Close()
  374. return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent})
  375. }
  376. // DeleteObjects deletes multiple objects.
  377. //
  378. // objectKeys the object keys to delete.
  379. // options the options for deleting objects.
  380. // Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used.
  381. //
  382. // DeleteObjectsResult the result object.
  383. // error it's nil if no error, otherwise it's an error object.
  384. //
  385. func (bucket Bucket) DeleteObjects(objectKeys []string, options ...Option) (DeleteObjectsResult, error) {
  386. out := DeleteObjectsResult{}
  387. dxml := deleteXML{}
  388. for _, key := range objectKeys {
  389. dxml.Objects = append(dxml.Objects, DeleteObject{Key: key})
  390. }
  391. isQuiet, _ := FindOption(options, deleteObjectsQuiet, false)
  392. dxml.Quiet = isQuiet.(bool)
  393. bs, err := xml.Marshal(dxml)
  394. if err != nil {
  395. return out, err
  396. }
  397. buffer := new(bytes.Buffer)
  398. buffer.Write(bs)
  399. contentType := http.DetectContentType(buffer.Bytes())
  400. options = append(options, ContentType(contentType))
  401. sum := md5.Sum(bs)
  402. b64 := base64.StdEncoding.EncodeToString(sum[:])
  403. options = append(options, ContentMD5(b64))
  404. params := map[string]interface{}{}
  405. params["delete"] = nil
  406. params["encoding-type"] = "url"
  407. resp, err := bucket.do("POST", "", params, options, buffer, nil)
  408. if err != nil {
  409. return out, err
  410. }
  411. defer resp.Body.Close()
  412. deletedResult := DeleteObjectVersionsResult{}
  413. if !dxml.Quiet {
  414. if err = xmlUnmarshal(resp.Body, &deletedResult); err == nil {
  415. err = decodeDeleteObjectsResult(&deletedResult)
  416. }
  417. }
  418. // Keep compatibility:need convert to struct DeleteObjectsResult
  419. out.XMLName = deletedResult.XMLName
  420. for _, v := range deletedResult.DeletedObjectsDetail {
  421. out.DeletedObjects = append(out.DeletedObjects, v.Key)
  422. }
  423. return out, err
  424. }
  425. // DeleteObjectVersions deletes multiple object versions.
  426. //
  427. // objectVersions the object keys and versions to delete.
  428. // options the options for deleting objects.
  429. // Supported option is DeleteObjectsQuiet which means it will not return error even deletion failed (not recommended). By default it's not used.
  430. //
  431. // DeleteObjectVersionsResult the result object.
  432. // error it's nil if no error, otherwise it's an error object.
  433. //
  434. func (bucket Bucket) DeleteObjectVersions(objectVersions []DeleteObject, options ...Option) (DeleteObjectVersionsResult, error) {
  435. out := DeleteObjectVersionsResult{}
  436. dxml := deleteXML{}
  437. dxml.Objects = objectVersions
  438. isQuiet, _ := FindOption(options, deleteObjectsQuiet, false)
  439. dxml.Quiet = isQuiet.(bool)
  440. bs, err := xml.Marshal(dxml)
  441. if err != nil {
  442. return out, err
  443. }
  444. buffer := new(bytes.Buffer)
  445. buffer.Write(bs)
  446. contentType := http.DetectContentType(buffer.Bytes())
  447. options = append(options, ContentType(contentType))
  448. sum := md5.Sum(bs)
  449. b64 := base64.StdEncoding.EncodeToString(sum[:])
  450. options = append(options, ContentMD5(b64))
  451. params := map[string]interface{}{}
  452. params["delete"] = nil
  453. params["encoding-type"] = "url"
  454. resp, err := bucket.do("POST", "", params, options, buffer, nil)
  455. if err != nil {
  456. return out, err
  457. }
  458. defer resp.Body.Close()
  459. if !dxml.Quiet {
  460. if err = xmlUnmarshal(resp.Body, &out); err == nil {
  461. err = decodeDeleteObjectsResult(&out)
  462. }
  463. }
  464. return out, err
  465. }
  466. // IsObjectExist checks if the object exists.
  467. //
  468. // bool flag of object's existence (true:exists; false:non-exist) when error is nil.
  469. //
  470. // error it's nil if no error, otherwise it's an error object.
  471. //
  472. func (bucket Bucket) IsObjectExist(objectKey string, options ...Option) (bool, error) {
  473. _, err := bucket.GetObjectMeta(objectKey, options...)
  474. if err == nil {
  475. return true, nil
  476. }
  477. switch err.(type) {
  478. case ServiceError:
  479. if err.(ServiceError).StatusCode == 404 {
  480. return false, nil
  481. }
  482. }
  483. return false, err
  484. }
  485. // ListObjects lists the objects under the current bucket.
  486. //
  487. // options it contains all the filters for listing objects.
  488. // It could specify a prefix filter on object keys, the max keys count to return and the object key marker and the delimiter for grouping object names.
  489. // The key marker means the returned objects' key must be greater than it in lexicographic order.
  490. //
  491. // For example, if the bucket has 8 objects, my-object-1, my-object-11, my-object-2, my-object-21,
  492. // my-object-22, my-object-3, my-object-31, my-object-32. If the prefix is my-object-2 (no other filters), then it returns
  493. // my-object-2, my-object-21, my-object-22 three objects. If the marker is my-object-22 (no other filters), then it returns
  494. // my-object-3, my-object-31, my-object-32 three objects. If the max keys is 5, then it returns 5 objects.
  495. // The three filters could be used together to achieve filter and paging functionality.
  496. // If the prefix is the folder name, then it could list all files under this folder (including the files under its subfolders).
  497. // But if the delimiter is specified with '/', then it only returns that folder's files (no subfolder's files). The direct subfolders are in the commonPrefixes properties.
  498. // For example, if the bucket has three objects fun/test.jpg, fun/movie/001.avi, fun/movie/007.avi. And if the prefix is "fun/", then it returns all three objects.
  499. // But if the delimiter is '/', then only "fun/test.jpg" is returned as files and fun/movie/ is returned as common prefix.
  500. //
  501. // For common usage scenario, check out sample/list_object.go.
  502. //
  503. // ListObjectsResult the return value after operation succeeds (only valid when error is nil).
  504. //
  505. func (bucket Bucket) ListObjects(options ...Option) (ListObjectsResult, error) {
  506. var out ListObjectsResult
  507. options = append(options, EncodingType("url"))
  508. params, err := GetRawParams(options)
  509. if err != nil {
  510. return out, err
  511. }
  512. resp, err := bucket.do("GET", "", params, options, nil, nil)
  513. if err != nil {
  514. return out, err
  515. }
  516. defer resp.Body.Close()
  517. err = xmlUnmarshal(resp.Body, &out)
  518. if err != nil {
  519. return out, err
  520. }
  521. err = decodeListObjectsResult(&out)
  522. return out, err
  523. }
  524. // Recommend to use ListObjectsV2 to replace ListObjects
  525. // ListOListObjectsV2bjects lists the objects under the current bucket.
  526. // ListObjectsResultV2 the return value after operation succeeds (only valid when error is nil).
  527. func (bucket Bucket) ListObjectsV2(options ...Option) (ListObjectsResultV2, error) {
  528. var out ListObjectsResultV2
  529. options = append(options, EncodingType("url"))
  530. options = append(options, ListType(2))
  531. params, err := GetRawParams(options)
  532. if err != nil {
  533. return out, err
  534. }
  535. resp, err := bucket.do("GET", "", params, options, nil, nil)
  536. if err != nil {
  537. return out, err
  538. }
  539. defer resp.Body.Close()
  540. err = xmlUnmarshal(resp.Body, &out)
  541. if err != nil {
  542. return out, err
  543. }
  544. err = decodeListObjectsResultV2(&out)
  545. return out, err
  546. }
  547. // ListObjectVersions lists objects of all versions under the current bucket.
  548. func (bucket Bucket) ListObjectVersions(options ...Option) (ListObjectVersionsResult, error) {
  549. var out ListObjectVersionsResult
  550. options = append(options, EncodingType("url"))
  551. params, err := GetRawParams(options)
  552. if err != nil {
  553. return out, err
  554. }
  555. params["versions"] = nil
  556. resp, err := bucket.do("GET", "", params, options, nil, nil)
  557. if err != nil {
  558. return out, err
  559. }
  560. defer resp.Body.Close()
  561. err = xmlUnmarshal(resp.Body, &out)
  562. if err != nil {
  563. return out, err
  564. }
  565. err = decodeListObjectVersionsResult(&out)
  566. return out, err
  567. }
  568. // SetObjectMeta sets the metadata of the Object.
  569. //
  570. // objectKey object
  571. // options options for setting the metadata. The valid options are CacheControl, ContentDisposition, ContentEncoding, Expires,
  572. // ServerSideEncryption, and custom metadata.
  573. //
  574. // error it's nil if no error, otherwise it's an error object.
  575. //
  576. func (bucket Bucket) SetObjectMeta(objectKey string, options ...Option) error {
  577. options = append(options, MetadataDirective(MetaReplace))
  578. _, err := bucket.CopyObject(objectKey, objectKey, options...)
  579. return err
  580. }
  581. // GetObjectDetailedMeta gets the object's detailed metadata
  582. //
  583. // objectKey object key.
  584. // options the constraints of the object. Only when the object meets the requirements this method will return the metadata. Otherwise returns error. Valid options are IfModifiedSince, IfUnmodifiedSince,
  585. // IfMatch, IfNoneMatch. For more details check out https://help.aliyun.com/document_detail/oss/api-reference/object/HeadObject.html
  586. //
  587. // http.Header object meta when error is nil.
  588. // error it's nil if no error, otherwise it's an error object.
  589. //
  590. func (bucket Bucket) GetObjectDetailedMeta(objectKey string, options ...Option) (http.Header, error) {
  591. params, _ := GetRawParams(options)
  592. resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil)
  593. if err != nil {
  594. return nil, err
  595. }
  596. defer resp.Body.Close()
  597. return resp.Headers, nil
  598. }
  599. // GetObjectMeta gets object metadata.
  600. //
  601. // GetObjectMeta is more lightweight than GetObjectDetailedMeta as it only returns basic metadata including ETag
  602. // size, LastModified. The size information is in the HTTP header Content-Length.
  603. //
  604. // objectKey object key
  605. //
  606. // http.Header the object's metadata, valid when error is nil.
  607. // error it's nil if no error, otherwise it's an error object.
  608. //
  609. func (bucket Bucket) GetObjectMeta(objectKey string, options ...Option) (http.Header, error) {
  610. params, _ := GetRawParams(options)
  611. params["objectMeta"] = nil
  612. //resp, err := bucket.do("GET", objectKey, "?objectMeta", "", nil, nil, nil)
  613. resp, err := bucket.do("HEAD", objectKey, params, options, nil, nil)
  614. if err != nil {
  615. return nil, err
  616. }
  617. defer resp.Body.Close()
  618. return resp.Headers, nil
  619. }
  620. // SetObjectACL updates the object's ACL.
  621. //
  622. // Only the bucket's owner could update object's ACL which priority is higher than bucket's ACL.
  623. // For example, if the bucket ACL is private and object's ACL is public-read-write.
  624. // Then object's ACL is used and it means all users could read or write that object.
  625. // When the object's ACL is not set, then bucket's ACL is used as the object's ACL.
  626. //
  627. // Object read operations include GetObject, HeadObject, CopyObject and UploadPartCopy on the source object;
  628. // Object write operations include PutObject, PostObject, AppendObject, DeleteObject, DeleteMultipleObjects,
  629. // CompleteMultipartUpload and CopyObject on target object.
  630. //
  631. // objectKey the target object key (to set the ACL on)
  632. // objectAcl object ACL. Valid options are PrivateACL, PublicReadACL, PublicReadWriteACL.
  633. //
  634. // error it's nil if no error, otherwise it's an error object.
  635. //
  636. func (bucket Bucket) SetObjectACL(objectKey string, objectACL ACLType, options ...Option) error {
  637. options = append(options, ObjectACL(objectACL))
  638. params, _ := GetRawParams(options)
  639. params["acl"] = nil
  640. resp, err := bucket.do("PUT", objectKey, params, options, nil, nil)
  641. if err != nil {
  642. return err
  643. }
  644. defer resp.Body.Close()
  645. return CheckRespCode(resp.StatusCode, []int{http.StatusOK})
  646. }
  647. // GetObjectACL gets object's ACL
  648. //
  649. // objectKey the object to get ACL from.
  650. //
  651. // GetObjectACLResult the result object when error is nil. GetObjectACLResult.Acl is the object ACL.
  652. // error it's nil if no error, otherwise it's an error object.
  653. //
  654. func (bucket Bucket) GetObjectACL(objectKey string, options ...Option) (GetObjectACLResult, error) {
  655. var out GetObjectACLResult
  656. params, _ := GetRawParams(options)
  657. params["acl"] = nil
  658. resp, err := bucket.do("GET", objectKey, params, options, nil, nil)
  659. if err != nil {
  660. return out, err
  661. }
  662. defer resp.Body.Close()
  663. err = xmlUnmarshal(resp.Body, &out)
  664. return out, err
  665. }
  666. // PutSymlink creates a symlink (to point to an existing object)
  667. //
  668. // Symlink cannot point to another symlink.
  669. // When creating a symlink, it does not check the existence of the target file, and does not check if the target file is symlink.
  670. // Neither it checks the caller's permission on the target file. All these checks are deferred to the actual GetObject call via this symlink.
  671. // If trying to add an existing file, as long as the caller has the write permission, the existing one will be overwritten.
  672. // If the x-oss-meta- is specified, it will be added as the metadata of the symlink file.
  673. //
  674. // symObjectKey the symlink object's key.
  675. // targetObjectKey the target object key to point to.
  676. //
  677. // error it's nil if no error, otherwise it's an error object.
  678. //
  679. func (bucket Bucket) PutSymlink(symObjectKey string, targetObjectKey string, options ...Option) error {
  680. options = append(options, symlinkTarget(url.QueryEscape(targetObjectKey)))
  681. params, _ := GetRawParams(options)
  682. params["symlink"] = nil
  683. resp, err := bucket.do("PUT", symObjectKey, params, options, nil, nil)
  684. if err != nil {
  685. return err
  686. }
  687. defer resp.Body.Close()
  688. return CheckRespCode(resp.StatusCode, []int{http.StatusOK})
  689. }
  690. // GetSymlink gets the symlink object with the specified key.
  691. // If the symlink object does not exist, returns 404.
  692. //
  693. // objectKey the symlink object's key.
  694. //
  695. // error it's nil if no error, otherwise it's an error object.
  696. // When error is nil, the target file key is in the X-Oss-Symlink-Target header of the returned object.
  697. //
  698. func (bucket Bucket) GetSymlink(objectKey string, options ...Option) (http.Header, error) {
  699. params, _ := GetRawParams(options)
  700. params["symlink"] = nil
  701. resp, err := bucket.do("GET", objectKey, params, options, nil, nil)
  702. if err != nil {
  703. return nil, err
  704. }
  705. defer resp.Body.Close()
  706. targetObjectKey := resp.Headers.Get(HTTPHeaderOssSymlinkTarget)
  707. targetObjectKey, err = url.QueryUnescape(targetObjectKey)
  708. if err != nil {
  709. return resp.Headers, err
  710. }
  711. resp.Headers.Set(HTTPHeaderOssSymlinkTarget, targetObjectKey)
  712. return resp.Headers, err
  713. }
  714. // RestoreObject restores the object from the archive storage.
  715. //
  716. // An archive object is in cold status by default and it cannot be accessed.
  717. // When restore is called on the cold object, it will become available for access after some time.
  718. // If multiple restores are called on the same file when the object is being restored, server side does nothing for additional calls but returns success.
  719. // By default, the restored object is available for access for one day. After that it will be unavailable again.
  720. // But if another RestoreObject are called after the file is restored, then it will extend one day's access time of that object, up to 7 days.
  721. //
  722. // objectKey object key to restore.
  723. //
  724. // error it's nil if no error, otherwise it's an error object.
  725. //
  726. func (bucket Bucket) RestoreObject(objectKey string, options ...Option) error {
  727. params, _ := GetRawParams(options)
  728. params["restore"] = nil
  729. resp, err := bucket.do("POST", objectKey, params, options, nil, nil)
  730. if err != nil {
  731. return err
  732. }
  733. defer resp.Body.Close()
  734. return CheckRespCode(resp.StatusCode, []int{http.StatusOK, http.StatusAccepted})
  735. }
  736. // RestoreObjectDetail support more features than RestoreObject
  737. func (bucket Bucket) RestoreObjectDetail(objectKey string, restoreConfig RestoreConfiguration, options ...Option) error {
  738. if restoreConfig.Tier == "" {
  739. // Expedited, Standard, Bulk
  740. restoreConfig.Tier = string(RestoreStandard)
  741. }
  742. if restoreConfig.Days == 0 {
  743. restoreConfig.Days = 1
  744. }
  745. bs, err := xml.Marshal(restoreConfig)
  746. if err != nil {
  747. return err
  748. }
  749. buffer := new(bytes.Buffer)
  750. buffer.Write(bs)
  751. contentType := http.DetectContentType(buffer.Bytes())
  752. options = append(options, ContentType(contentType))
  753. params, _ := GetRawParams(options)
  754. params["restore"] = nil
  755. resp, err := bucket.do("POST", objectKey, params, options, buffer, nil)
  756. if err != nil {
  757. return err
  758. }
  759. defer resp.Body.Close()
  760. return CheckRespCode(resp.StatusCode, []int{http.StatusOK, http.StatusAccepted})
  761. }
  762. // RestoreObjectXML support more features than RestoreObject
  763. func (bucket Bucket) RestoreObjectXML(objectKey, configXML string, options ...Option) error {
  764. buffer := new(bytes.Buffer)
  765. buffer.Write([]byte(configXML))
  766. contentType := http.DetectContentType(buffer.Bytes())
  767. options = append(options, ContentType(contentType))
  768. params, _ := GetRawParams(options)
  769. params["restore"] = nil
  770. resp, err := bucket.do("POST", objectKey, params, options, buffer, nil)
  771. if err != nil {
  772. return err
  773. }
  774. defer resp.Body.Close()
  775. return CheckRespCode(resp.StatusCode, []int{http.StatusOK, http.StatusAccepted})
  776. }
  777. // SignURL signs the URL. Users could access the object directly with this URL without getting the AK.
  778. //
  779. // objectKey the target object to sign.
  780. // signURLConfig the configuration for the signed URL
  781. //
  782. // string returns the signed URL, when error is nil.
  783. // error it's nil if no error, otherwise it's an error object.
  784. //
  785. func (bucket Bucket) SignURL(objectKey string, method HTTPMethod, expiredInSec int64, options ...Option) (string, error) {
  786. if expiredInSec < 0 {
  787. return "", fmt.Errorf("invalid expires: %d, expires must bigger than 0", expiredInSec)
  788. }
  789. expiration := time.Now().Unix() + expiredInSec
  790. params, err := GetRawParams(options)
  791. if err != nil {
  792. return "", err
  793. }
  794. headers := make(map[string]string)
  795. err = handleOptions(headers, options)
  796. if err != nil {
  797. return "", err
  798. }
  799. return bucket.Client.Conn.signURL(method, bucket.BucketName, objectKey, expiration, params, headers), nil
  800. }
  801. // PutObjectWithURL uploads an object with the URL. If the object exists, it will be overwritten.
  802. // PutObjectWithURL It will not generate minetype according to the key name.
  803. //
  804. // signedURL signed URL.
  805. // reader io.Reader the read instance for reading the data for the upload.
  806. // options the options for uploading the data. The valid options are CacheControl, ContentDisposition, ContentEncoding,
  807. // Expires, ServerSideEncryption, ObjectACL and custom metadata. Check out the following link for details:
  808. // https://help.aliyun.com/document_detail/oss/api-reference/object/PutObject.html
  809. //
  810. // error it's nil if no error, otherwise it's an error object.
  811. //
  812. func (bucket Bucket) PutObjectWithURL(signedURL string, reader io.Reader, options ...Option) error {
  813. resp, err := bucket.DoPutObjectWithURL(signedURL, reader, options)
  814. if err != nil {
  815. return err
  816. }
  817. defer resp.Body.Close()
  818. return err
  819. }
  820. // PutObjectFromFileWithURL uploads an object from a local file with the signed URL.
  821. // PutObjectFromFileWithURL It does not generate mimetype according to object key's name or the local file name.
  822. //
  823. // signedURL the signed URL.
  824. // filePath local file path, such as dirfile.txt, for uploading.
  825. // options options for uploading, same as the options in PutObject function.
  826. //
  827. // error it's nil if no error, otherwise it's an error object.
  828. //
  829. func (bucket Bucket) PutObjectFromFileWithURL(signedURL, filePath string, options ...Option) error {
  830. fd, err := os.Open(filePath)
  831. if err != nil {
  832. return err
  833. }
  834. defer fd.Close()
  835. resp, err := bucket.DoPutObjectWithURL(signedURL, fd, options)
  836. if err != nil {
  837. return err
  838. }
  839. defer resp.Body.Close()
  840. return err
  841. }
  842. // DoPutObjectWithURL is the actual API that does the upload with URL work(internal for SDK)
  843. //
  844. // signedURL the signed URL.
  845. // reader io.Reader the read instance for getting the data to upload.
  846. // options options for uploading.
  847. //
  848. // Response the response object which contains the HTTP response.
  849. // error it's nil if no error, otherwise it's an error object.
  850. //
  851. func (bucket Bucket) DoPutObjectWithURL(signedURL string, reader io.Reader, options []Option) (*Response, error) {
  852. listener := GetProgressListener(options)
  853. params := map[string]interface{}{}
  854. resp, err := bucket.doURL("PUT", signedURL, params, options, reader, listener)
  855. if err != nil {
  856. return nil, err
  857. }
  858. if bucket.GetConfig().IsEnableCRC {
  859. err = CheckCRC(resp, "DoPutObjectWithURL")
  860. if err != nil {
  861. return resp, err
  862. }
  863. }
  864. err = CheckRespCode(resp.StatusCode, []int{http.StatusOK})
  865. return resp, err
  866. }
  867. // GetObjectWithURL downloads the object and returns the reader instance, with the signed URL.
  868. //
  869. // signedURL the signed URL.
  870. // options options for downloading the object. Valid options are IfModifiedSince, IfUnmodifiedSince, IfMatch,
  871. // IfNoneMatch, AcceptEncoding. For more information, check out the following link:
  872. // https://help.aliyun.com/document_detail/oss/api-reference/object/GetObject.html
  873. //
  874. // io.ReadCloser the reader object for getting the data from response. It needs be closed after the usage. It's only valid when error is nil.
  875. // error it's nil if no error, otherwise it's an error object.
  876. //
  877. func (bucket Bucket) GetObjectWithURL(signedURL string, options ...Option) (io.ReadCloser, error) {
  878. result, err := bucket.DoGetObjectWithURL(signedURL, options)
  879. if err != nil {
  880. return nil, err
  881. }
  882. return result.Response, nil
  883. }
  884. // GetObjectToFileWithURL downloads the object into a local file with the signed URL.
  885. //
  886. // signedURL the signed URL
  887. // filePath the local file path to download to.
  888. // options the options for downloading object. Check out the parameter options in function GetObject for the reference.
  889. //
  890. // error it's nil if no error, otherwise it's an error object.
  891. //
  892. func (bucket Bucket) GetObjectToFileWithURL(signedURL, filePath string, options ...Option) error {
  893. tempFilePath := filePath + TempFileSuffix
  894. // Get the object's content
  895. result, err := bucket.DoGetObjectWithURL(signedURL, options)
  896. if err != nil {
  897. return err
  898. }
  899. defer result.Response.Close()
  900. // If the file does not exist, create one. If exists, then overwrite it.
  901. fd, err := os.OpenFile(tempFilePath, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, FilePermMode)
  902. if err != nil {
  903. return err
  904. }
  905. // Save the data to the file.
  906. _, err = io.Copy(fd, result.Response.Body)
  907. fd.Close()
  908. if err != nil {
  909. return err
  910. }
  911. // Compare the CRC value. If CRC values do not match, return error.
  912. hasRange, _, _ := IsOptionSet(options, HTTPHeaderRange)
  913. encodeOpt, _ := FindOption(options, HTTPHeaderAcceptEncoding, nil)
  914. acceptEncoding := ""
  915. if encodeOpt != nil {
  916. acceptEncoding = encodeOpt.(string)
  917. }
  918. if bucket.GetConfig().IsEnableCRC && !hasRange && acceptEncoding != "gzip" {
  919. result.Response.ClientCRC = result.ClientCRC.Sum64()
  920. err = CheckCRC(result.Response, "GetObjectToFileWithURL")
  921. if err != nil {
  922. os.Remove(tempFilePath)
  923. return err
  924. }
  925. }
  926. return os.Rename(tempFilePath, filePath)
  927. }
  928. // DoGetObjectWithURL is the actual API that downloads the file with the signed URL.
  929. //
  930. // signedURL the signed URL.
  931. // options the options for getting object. Check out parameter options in GetObject for the reference.
  932. //
  933. // GetObjectResult the result object when the error is nil.
  934. // error it's nil if no error, otherwise it's an error object.
  935. //
  936. func (bucket Bucket) DoGetObjectWithURL(signedURL string, options []Option) (*GetObjectResult, error) {
  937. params, _ := GetRawParams(options)
  938. resp, err := bucket.doURL("GET", signedURL, params, options, nil, nil)
  939. if err != nil {
  940. return nil, err
  941. }
  942. result := &GetObjectResult{
  943. Response: resp,
  944. }
  945. // CRC
  946. var crcCalc hash.Hash64
  947. hasRange, _, _ := IsOptionSet(options, HTTPHeaderRange)
  948. if bucket.GetConfig().IsEnableCRC && !hasRange {
  949. crcCalc = crc64.New(CrcTable())
  950. result.ServerCRC = resp.ServerCRC
  951. result.ClientCRC = crcCalc
  952. }
  953. // Progress
  954. listener := GetProgressListener(options)
  955. contentLen, _ := strconv.ParseInt(resp.Headers.Get(HTTPHeaderContentLength), 10, 64)
  956. resp.Body = TeeReader(resp.Body, crcCalc, contentLen, listener, nil)
  957. return result, nil
  958. }
  959. //
  960. // ProcessObject apply process on the specified image file.
  961. //
  962. // The supported process includes resize, rotate, crop, watermark, format,
  963. // udf, customized style, etc.
  964. //
  965. //
  966. // objectKey object key to process.
  967. // process process string, such as "image/resize,w_100|sys/saveas,o_dGVzdC5qcGc,b_dGVzdA"
  968. //
  969. // error it's nil if no error, otherwise it's an error object.
  970. //
  971. func (bucket Bucket) ProcessObject(objectKey string, process string, options ...Option) (ProcessObjectResult, error) {
  972. var out ProcessObjectResult
  973. params, _ := GetRawParams(options)
  974. params["x-oss-process"] = nil
  975. processData := fmt.Sprintf("%v=%v", "x-oss-process", process)
  976. data := strings.NewReader(processData)
  977. resp, err := bucket.do("POST", objectKey, params, nil, data, nil)
  978. if err != nil {
  979. return out, err
  980. }
  981. defer resp.Body.Close()
  982. err = jsonUnmarshal(resp.Body, &out)
  983. return out, err
  984. }
  985. //
  986. // PutObjectTagging add tagging to object
  987. //
  988. // objectKey object key to add tagging
  989. // tagging tagging to be added
  990. //
  991. // error nil if success, otherwise error
  992. //
  993. func (bucket Bucket) PutObjectTagging(objectKey string, tagging Tagging, options ...Option) error {
  994. bs, err := xml.Marshal(tagging)
  995. if err != nil {
  996. return err
  997. }
  998. buffer := new(bytes.Buffer)
  999. buffer.Write(bs)
  1000. params, _ := GetRawParams(options)
  1001. params["tagging"] = nil
  1002. resp, err := bucket.do("PUT", objectKey, params, options, buffer, nil)
  1003. if err != nil {
  1004. return err
  1005. }
  1006. defer resp.Body.Close()
  1007. return nil
  1008. }
  1009. //
  1010. // GetObjectTagging get tagging of the object
  1011. //
  1012. // objectKey object key to get tagging
  1013. //
  1014. // Tagging
  1015. // error nil if success, otherwise error
  1016. func (bucket Bucket) GetObjectTagging(objectKey string, options ...Option) (GetObjectTaggingResult, error) {
  1017. var out GetObjectTaggingResult
  1018. params, _ := GetRawParams(options)
  1019. params["tagging"] = nil
  1020. resp, err := bucket.do("GET", objectKey, params, options, nil, nil)
  1021. if err != nil {
  1022. return out, err
  1023. }
  1024. defer resp.Body.Close()
  1025. err = xmlUnmarshal(resp.Body, &out)
  1026. return out, err
  1027. }
  1028. //
  1029. // DeleteObjectTagging delete object taggging
  1030. //
  1031. // objectKey object key to delete tagging
  1032. //
  1033. // error nil if success, otherwise error
  1034. //
  1035. func (bucket Bucket) DeleteObjectTagging(objectKey string, options ...Option) error {
  1036. params, _ := GetRawParams(options)
  1037. params["tagging"] = nil
  1038. if objectKey == "" {
  1039. return fmt.Errorf("invalid argument: object name is empty")
  1040. }
  1041. resp, err := bucket.do("DELETE", objectKey, params, options, nil, nil)
  1042. if err != nil {
  1043. return err
  1044. }
  1045. defer resp.Body.Close()
  1046. return CheckRespCode(resp.StatusCode, []int{http.StatusNoContent})
  1047. }
  1048. func (bucket Bucket) OptionsMethod(objectKey string, options ...Option) (http.Header, error) {
  1049. var out http.Header
  1050. resp, err := bucket.do("OPTIONS", objectKey, nil, options, nil, nil)
  1051. if err != nil {
  1052. return out, err
  1053. }
  1054. defer resp.Body.Close()
  1055. out = resp.Headers
  1056. return out, nil
  1057. }
  1058. // public
  1059. func (bucket Bucket) Do(method, objectName string, params map[string]interface{}, options []Option,
  1060. data io.Reader, listener ProgressListener) (*Response, error) {
  1061. return bucket.do(method, objectName, params, options, data, listener)
  1062. }
  1063. // Private
  1064. func (bucket Bucket) do(method, objectName string, params map[string]interface{}, options []Option,
  1065. data io.Reader, listener ProgressListener) (*Response, error) {
  1066. headers := make(map[string]string)
  1067. err := handleOptions(headers, options)
  1068. if err != nil {
  1069. return nil, err
  1070. }
  1071. err = CheckBucketName(bucket.BucketName)
  1072. if len(bucket.BucketName) > 0 && err != nil {
  1073. return nil, err
  1074. }
  1075. resp, err := bucket.Client.Conn.Do(method, bucket.BucketName, objectName,
  1076. params, headers, data, 0, listener)
  1077. // get response header
  1078. respHeader, _ := FindOption(options, responseHeader, nil)
  1079. if respHeader != nil && resp != nil {
  1080. pRespHeader := respHeader.(*http.Header)
  1081. *pRespHeader = resp.Headers
  1082. }
  1083. return resp, err
  1084. }
  1085. func (bucket Bucket) doURL(method HTTPMethod, signedURL string, params map[string]interface{}, options []Option,
  1086. data io.Reader, listener ProgressListener) (*Response, error) {
  1087. headers := make(map[string]string)
  1088. err := handleOptions(headers, options)
  1089. if err != nil {
  1090. return nil, err
  1091. }
  1092. resp, err := bucket.Client.Conn.DoURL(method, signedURL, headers, data, 0, listener)
  1093. // get response header
  1094. respHeader, _ := FindOption(options, responseHeader, nil)
  1095. if respHeader != nil {
  1096. pRespHeader := respHeader.(*http.Header)
  1097. *pRespHeader = resp.Headers
  1098. }
  1099. return resp, err
  1100. }
  1101. func (bucket Bucket) GetConfig() *Config {
  1102. return bucket.Client.Config
  1103. }
  1104. func AddContentType(options []Option, keys ...string) []Option {
  1105. typ := TypeByExtension("")
  1106. for _, key := range keys {
  1107. typ = TypeByExtension(key)
  1108. if typ != "" {
  1109. break
  1110. }
  1111. }
  1112. if typ == "" {
  1113. typ = "application/octet-stream"
  1114. }
  1115. opts := []Option{ContentType(typ)}
  1116. opts = append(opts, options...)
  1117. return opts
  1118. }