utils.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504
  1. package oss
  2. import (
  3. "bytes"
  4. "errors"
  5. "fmt"
  6. "hash/crc32"
  7. "hash/crc64"
  8. "io"
  9. "net/http"
  10. "os"
  11. "os/exec"
  12. "runtime"
  13. "strconv"
  14. "strings"
  15. "time"
  16. )
  17. // userAgent gets user agent
  18. // It has the SDK version information, OS information and GO version
  19. func userAgent() string {
  20. sys := getSysInfo()
  21. return fmt.Sprintf("aliyun-sdk-go/%s (%s/%s/%s;%s)", Version, sys.name,
  22. sys.release, sys.machine, runtime.Version())
  23. }
  24. type sysInfo struct {
  25. name string // OS name such as windows/Linux
  26. release string // OS version 2.6.32-220.23.2.ali1089.el5.x86_64 etc
  27. machine string // CPU type amd64/x86_64
  28. }
  29. // getSysInfo gets system info
  30. // gets the OS information and CPU type
  31. func getSysInfo() sysInfo {
  32. name := runtime.GOOS
  33. release := "-"
  34. machine := runtime.GOARCH
  35. if out, err := exec.Command("uname", "-s").CombinedOutput(); err == nil {
  36. name = string(bytes.TrimSpace(out))
  37. }
  38. if out, err := exec.Command("uname", "-r").CombinedOutput(); err == nil {
  39. release = string(bytes.TrimSpace(out))
  40. }
  41. if out, err := exec.Command("uname", "-m").CombinedOutput(); err == nil {
  42. machine = string(bytes.TrimSpace(out))
  43. }
  44. return sysInfo{name: name, release: release, machine: machine}
  45. }
  46. // GetRangeConfig gets the download range from the options.
  47. func GetRangeConfig(options []Option) (*UnpackedRange, error) {
  48. rangeOpt, err := FindOption(options, HTTPHeaderRange, nil)
  49. if err != nil || rangeOpt == nil {
  50. return nil, err
  51. }
  52. return ParseRange(rangeOpt.(string))
  53. }
  54. // UnpackedRange
  55. type UnpackedRange struct {
  56. HasStart bool // Flag indicates if the start point is specified
  57. HasEnd bool // Flag indicates if the end point is specified
  58. Start int64 // Start point
  59. End int64 // End point
  60. }
  61. // InvalidRangeError returns invalid range error
  62. func InvalidRangeError(r string) error {
  63. return fmt.Errorf("InvalidRange %s", r)
  64. }
  65. func GetRangeString(unpackRange UnpackedRange) string {
  66. var strRange string
  67. if unpackRange.HasStart && unpackRange.HasEnd {
  68. strRange = fmt.Sprintf("%d-%d", unpackRange.Start, unpackRange.End)
  69. } else if unpackRange.HasStart {
  70. strRange = fmt.Sprintf("%d-", unpackRange.Start)
  71. } else if unpackRange.HasEnd {
  72. strRange = fmt.Sprintf("-%d", unpackRange.End)
  73. }
  74. return strRange
  75. }
  76. // ParseRange parse various styles of range such as bytes=M-N
  77. func ParseRange(normalizedRange string) (*UnpackedRange, error) {
  78. var err error
  79. hasStart := false
  80. hasEnd := false
  81. var start int64
  82. var end int64
  83. // Bytes==M-N or ranges=M-N
  84. nrSlice := strings.Split(normalizedRange, "=")
  85. if len(nrSlice) != 2 || nrSlice[0] != "bytes" {
  86. return nil, InvalidRangeError(normalizedRange)
  87. }
  88. // Bytes=M-N,X-Y
  89. rSlice := strings.Split(nrSlice[1], ",")
  90. rStr := rSlice[0]
  91. if strings.HasSuffix(rStr, "-") { // M-
  92. startStr := rStr[:len(rStr)-1]
  93. start, err = strconv.ParseInt(startStr, 10, 64)
  94. if err != nil {
  95. return nil, InvalidRangeError(normalizedRange)
  96. }
  97. hasStart = true
  98. } else if strings.HasPrefix(rStr, "-") { // -N
  99. len := rStr[1:]
  100. end, err = strconv.ParseInt(len, 10, 64)
  101. if err != nil {
  102. return nil, InvalidRangeError(normalizedRange)
  103. }
  104. if end == 0 { // -0
  105. return nil, InvalidRangeError(normalizedRange)
  106. }
  107. hasEnd = true
  108. } else { // M-N
  109. valSlice := strings.Split(rStr, "-")
  110. if len(valSlice) != 2 {
  111. return nil, InvalidRangeError(normalizedRange)
  112. }
  113. start, err = strconv.ParseInt(valSlice[0], 10, 64)
  114. if err != nil {
  115. return nil, InvalidRangeError(normalizedRange)
  116. }
  117. hasStart = true
  118. end, err = strconv.ParseInt(valSlice[1], 10, 64)
  119. if err != nil {
  120. return nil, InvalidRangeError(normalizedRange)
  121. }
  122. hasEnd = true
  123. }
  124. return &UnpackedRange{hasStart, hasEnd, start, end}, nil
  125. }
  126. // AdjustRange returns adjusted range, adjust the range according to the length of the file
  127. func AdjustRange(ur *UnpackedRange, size int64) (start, end int64) {
  128. if ur == nil {
  129. return 0, size
  130. }
  131. if ur.HasStart && ur.HasEnd {
  132. start = ur.Start
  133. end = ur.End + 1
  134. if ur.Start < 0 || ur.Start >= size || ur.End > size || ur.Start > ur.End {
  135. start = 0
  136. end = size
  137. }
  138. } else if ur.HasStart {
  139. start = ur.Start
  140. end = size
  141. if ur.Start < 0 || ur.Start >= size {
  142. start = 0
  143. }
  144. } else if ur.HasEnd {
  145. start = size - ur.End
  146. end = size
  147. if ur.End < 0 || ur.End > size {
  148. start = 0
  149. end = size
  150. }
  151. }
  152. return
  153. }
  154. // GetNowSec returns Unix time, the number of seconds elapsed since January 1, 1970 UTC.
  155. // gets the current time in Unix time, in seconds.
  156. func GetNowSec() int64 {
  157. return time.Now().Unix()
  158. }
  159. // GetNowNanoSec returns t as a Unix time, the number of nanoseconds elapsed
  160. // since January 1, 1970 UTC. The result is undefined if the Unix time
  161. // in nanoseconds cannot be represented by an int64. Note that this
  162. // means the result of calling UnixNano on the zero Time is undefined.
  163. // gets the current time in Unix time, in nanoseconds.
  164. func GetNowNanoSec() int64 {
  165. return time.Now().UnixNano()
  166. }
  167. // GetNowGMT gets the current time in GMT format.
  168. func GetNowGMT() string {
  169. return time.Now().UTC().Format(http.TimeFormat)
  170. }
  171. // FileChunk is the file chunk definition
  172. type FileChunk struct {
  173. Number int // Chunk number
  174. Offset int64 // Chunk offset
  175. Size int64 // Chunk size.
  176. }
  177. // SplitFileByPartNum splits big file into parts by the num of parts.
  178. // Split the file with specified parts count, returns the split result when error is nil.
  179. func SplitFileByPartNum(fileName string, chunkNum int) ([]FileChunk, error) {
  180. if chunkNum <= 0 || chunkNum > 10000 {
  181. return nil, errors.New("chunkNum invalid")
  182. }
  183. file, err := os.Open(fileName)
  184. if err != nil {
  185. return nil, err
  186. }
  187. defer file.Close()
  188. stat, err := file.Stat()
  189. if err != nil {
  190. return nil, err
  191. }
  192. if int64(chunkNum) > stat.Size() {
  193. return nil, errors.New("oss: chunkNum invalid")
  194. }
  195. var chunks []FileChunk
  196. var chunk = FileChunk{}
  197. var chunkN = (int64)(chunkNum)
  198. for i := int64(0); i < chunkN; i++ {
  199. chunk.Number = int(i + 1)
  200. chunk.Offset = i * (stat.Size() / chunkN)
  201. if i == chunkN-1 {
  202. chunk.Size = stat.Size()/chunkN + stat.Size()%chunkN
  203. } else {
  204. chunk.Size = stat.Size() / chunkN
  205. }
  206. chunks = append(chunks, chunk)
  207. }
  208. return chunks, nil
  209. }
  210. // SplitFileByPartSize splits big file into parts by the size of parts.
  211. // Splits the file by the part size. Returns the FileChunk when error is nil.
  212. func SplitFileByPartSize(fileName string, chunkSize int64) ([]FileChunk, error) {
  213. if chunkSize <= 0 {
  214. return nil, errors.New("chunkSize invalid")
  215. }
  216. file, err := os.Open(fileName)
  217. if err != nil {
  218. return nil, err
  219. }
  220. defer file.Close()
  221. stat, err := file.Stat()
  222. if err != nil {
  223. return nil, err
  224. }
  225. var chunkN = stat.Size() / chunkSize
  226. if chunkN >= 10000 {
  227. return nil, errors.New("Too many parts, please increase part size")
  228. }
  229. var chunks []FileChunk
  230. var chunk = FileChunk{}
  231. for i := int64(0); i < chunkN; i++ {
  232. chunk.Number = int(i + 1)
  233. chunk.Offset = i * chunkSize
  234. chunk.Size = chunkSize
  235. chunks = append(chunks, chunk)
  236. }
  237. if stat.Size()%chunkSize > 0 {
  238. chunk.Number = len(chunks) + 1
  239. chunk.Offset = int64(len(chunks)) * chunkSize
  240. chunk.Size = stat.Size() % chunkSize
  241. chunks = append(chunks, chunk)
  242. }
  243. return chunks, nil
  244. }
  245. // GetPartEnd calculates the end position
  246. func GetPartEnd(begin int64, total int64, per int64) int64 {
  247. if begin+per > total {
  248. return total - 1
  249. }
  250. return begin + per - 1
  251. }
  252. // CrcTable returns the table constructed from the specified polynomial
  253. var CrcTable = func() *crc64.Table {
  254. return crc64.MakeTable(crc64.ECMA)
  255. }
  256. // CrcTable returns the table constructed from the specified polynomial
  257. var crc32Table = func() *crc32.Table {
  258. return crc32.MakeTable(crc32.IEEE)
  259. }
  260. // choiceTransferPartOption choices valid option supported by Uploadpart or DownloadPart
  261. func ChoiceTransferPartOption(options []Option) []Option {
  262. var outOption []Option
  263. listener, _ := FindOption(options, progressListener, nil)
  264. if listener != nil {
  265. outOption = append(outOption, Progress(listener.(ProgressListener)))
  266. }
  267. payer, _ := FindOption(options, HTTPHeaderOssRequester, nil)
  268. if payer != nil {
  269. outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
  270. }
  271. versionId, _ := FindOption(options, "versionId", nil)
  272. if versionId != nil {
  273. outOption = append(outOption, VersionId(versionId.(string)))
  274. }
  275. trafficLimit, _ := FindOption(options, HTTPHeaderOssTrafficLimit, nil)
  276. if trafficLimit != nil {
  277. speed, _ := strconv.ParseInt(trafficLimit.(string), 10, 64)
  278. outOption = append(outOption, TrafficLimitHeader(speed))
  279. }
  280. respHeader, _ := FindOption(options, responseHeader, nil)
  281. if respHeader != nil {
  282. outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
  283. }
  284. return outOption
  285. }
  286. // ChoiceCompletePartOption choices valid option supported by CompleteMulitiPart
  287. func ChoiceCompletePartOption(options []Option) []Option {
  288. var outOption []Option
  289. listener, _ := FindOption(options, progressListener, nil)
  290. if listener != nil {
  291. outOption = append(outOption, Progress(listener.(ProgressListener)))
  292. }
  293. payer, _ := FindOption(options, HTTPHeaderOssRequester, nil)
  294. if payer != nil {
  295. outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
  296. }
  297. acl, _ := FindOption(options, HTTPHeaderOssObjectACL, nil)
  298. if acl != nil {
  299. outOption = append(outOption, ObjectACL(ACLType(acl.(string))))
  300. }
  301. callback, _ := FindOption(options, HTTPHeaderOssCallback, nil)
  302. if callback != nil {
  303. outOption = append(outOption, Callback(callback.(string)))
  304. }
  305. callbackVar, _ := FindOption(options, HTTPHeaderOssCallbackVar, nil)
  306. if callbackVar != nil {
  307. outOption = append(outOption, CallbackVar(callbackVar.(string)))
  308. }
  309. respHeader, _ := FindOption(options, responseHeader, nil)
  310. if respHeader != nil {
  311. outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
  312. }
  313. forbidOverWrite, _ := FindOption(options, HTTPHeaderOssForbidOverWrite, nil)
  314. if forbidOverWrite != nil {
  315. if forbidOverWrite.(string) == "true" {
  316. outOption = append(outOption, ForbidOverWrite(true))
  317. } else {
  318. outOption = append(outOption, ForbidOverWrite(false))
  319. }
  320. }
  321. return outOption
  322. }
  323. // ChoiceAbortPartOption choices valid option supported by AbortMultipartUpload
  324. func ChoiceAbortPartOption(options []Option) []Option {
  325. var outOption []Option
  326. payer, _ := FindOption(options, HTTPHeaderOssRequester, nil)
  327. if payer != nil {
  328. outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
  329. }
  330. respHeader, _ := FindOption(options, responseHeader, nil)
  331. if respHeader != nil {
  332. outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
  333. }
  334. return outOption
  335. }
  336. // ChoiceHeadObjectOption choices valid option supported by HeadObject
  337. func ChoiceHeadObjectOption(options []Option) []Option {
  338. var outOption []Option
  339. // not select HTTPHeaderRange to get whole object length
  340. payer, _ := FindOption(options, HTTPHeaderOssRequester, nil)
  341. if payer != nil {
  342. outOption = append(outOption, RequestPayer(PayerType(payer.(string))))
  343. }
  344. versionId, _ := FindOption(options, "versionId", nil)
  345. if versionId != nil {
  346. outOption = append(outOption, VersionId(versionId.(string)))
  347. }
  348. respHeader, _ := FindOption(options, responseHeader, nil)
  349. if respHeader != nil {
  350. outOption = append(outOption, GetResponseHeader(respHeader.(*http.Header)))
  351. }
  352. return outOption
  353. }
  354. func CheckBucketName(bucketName string) error {
  355. nameLen := len(bucketName)
  356. if nameLen < 3 || nameLen > 63 {
  357. return fmt.Errorf("bucket name %s len is between [3-63],now is %d", bucketName, nameLen)
  358. }
  359. for _, v := range bucketName {
  360. if !(('a' <= v && v <= 'z') || ('0' <= v && v <= '9') || v == '-') {
  361. return fmt.Errorf("bucket name %s can only include lowercase letters, numbers, and -", bucketName)
  362. }
  363. }
  364. if bucketName[0] == '-' || bucketName[nameLen-1] == '-' {
  365. return fmt.Errorf("bucket name %s must start and end with a lowercase letter or number", bucketName)
  366. }
  367. return nil
  368. }
  369. func GetReaderLen(reader io.Reader) (int64, error) {
  370. var contentLength int64
  371. var err error
  372. switch v := reader.(type) {
  373. case *bytes.Buffer:
  374. contentLength = int64(v.Len())
  375. case *bytes.Reader:
  376. contentLength = int64(v.Len())
  377. case *strings.Reader:
  378. contentLength = int64(v.Len())
  379. case *os.File:
  380. fInfo, fError := v.Stat()
  381. if fError != nil {
  382. err = fmt.Errorf("can't get reader content length,%s", fError.Error())
  383. } else {
  384. contentLength = fInfo.Size()
  385. }
  386. case *io.LimitedReader:
  387. contentLength = int64(v.N)
  388. case *LimitedReadCloser:
  389. contentLength = int64(v.N)
  390. default:
  391. err = fmt.Errorf("can't get reader content length,unkown reader type")
  392. }
  393. return contentLength, err
  394. }
  395. func LimitReadCloser(r io.Reader, n int64) io.Reader {
  396. var lc LimitedReadCloser
  397. lc.R = r
  398. lc.N = n
  399. return &lc
  400. }
  401. // LimitedRC support Close()
  402. type LimitedReadCloser struct {
  403. io.LimitedReader
  404. }
  405. func (lc *LimitedReadCloser) Close() error {
  406. if closer, ok := lc.R.(io.ReadCloser); ok {
  407. return closer.Close()
  408. }
  409. return nil
  410. }
  411. type DiscardReadCloser struct {
  412. RC io.ReadCloser
  413. Discard int
  414. }
  415. func (drc *DiscardReadCloser) Read(b []byte) (int, error) {
  416. n, err := drc.RC.Read(b)
  417. if drc.Discard == 0 || n <= 0 {
  418. return n, err
  419. }
  420. if n <= drc.Discard {
  421. drc.Discard -= n
  422. return 0, err
  423. }
  424. realLen := n - drc.Discard
  425. copy(b[0:realLen], b[drc.Discard:n])
  426. drc.Discard = 0
  427. return realLen, err
  428. }
  429. func (drc *DiscardReadCloser) Close() error {
  430. closer, ok := drc.RC.(io.ReadCloser)
  431. if ok {
  432. return closer.Close()
  433. }
  434. return nil
  435. }