appendblob.go 3.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. package storage
  2. // Copyright 2017 Microsoft Corporation
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. import (
  16. "bytes"
  17. "crypto/md5"
  18. "encoding/base64"
  19. "fmt"
  20. "net/http"
  21. "net/url"
  22. "time"
  23. )
  24. // PutAppendBlob initializes an empty append blob with specified name. An
  25. // append blob must be created using this method before appending blocks.
  26. //
  27. // See CreateBlockBlobFromReader for more info on creating blobs.
  28. //
  29. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Blob
  30. func (b *Blob) PutAppendBlob(options *PutBlobOptions) error {
  31. params := url.Values{}
  32. headers := b.Container.bsc.client.getStandardHeaders()
  33. headers["x-ms-blob-type"] = string(BlobTypeAppend)
  34. headers = mergeHeaders(headers, headersFromStruct(b.Properties))
  35. headers = b.Container.bsc.client.addMetadataToHeaders(headers, b.Metadata)
  36. if options != nil {
  37. params = addTimeout(params, options.Timeout)
  38. headers = mergeHeaders(headers, headersFromStruct(*options))
  39. }
  40. uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
  41. resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, nil, b.Container.bsc.auth)
  42. if err != nil {
  43. return err
  44. }
  45. return b.respondCreation(resp, BlobTypeAppend)
  46. }
  47. // AppendBlockOptions includes the options for an append block operation
  48. type AppendBlockOptions struct {
  49. Timeout uint
  50. LeaseID string `header:"x-ms-lease-id"`
  51. MaxSize *uint `header:"x-ms-blob-condition-maxsize"`
  52. AppendPosition *uint `header:"x-ms-blob-condition-appendpos"`
  53. IfModifiedSince *time.Time `header:"If-Modified-Since"`
  54. IfUnmodifiedSince *time.Time `header:"If-Unmodified-Since"`
  55. IfMatch string `header:"If-Match"`
  56. IfNoneMatch string `header:"If-None-Match"`
  57. RequestID string `header:"x-ms-client-request-id"`
  58. ContentMD5 bool
  59. }
  60. // AppendBlock appends a block to an append blob.
  61. //
  62. // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Append-Block
  63. func (b *Blob) AppendBlock(chunk []byte, options *AppendBlockOptions) error {
  64. params := url.Values{"comp": {"appendblock"}}
  65. headers := b.Container.bsc.client.getStandardHeaders()
  66. headers["x-ms-blob-type"] = string(BlobTypeAppend)
  67. headers["Content-Length"] = fmt.Sprintf("%v", len(chunk))
  68. if options != nil {
  69. params = addTimeout(params, options.Timeout)
  70. headers = mergeHeaders(headers, headersFromStruct(*options))
  71. if options.ContentMD5 {
  72. md5sum := md5.Sum(chunk)
  73. headers[headerContentMD5] = base64.StdEncoding.EncodeToString(md5sum[:])
  74. }
  75. }
  76. uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
  77. resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, bytes.NewReader(chunk), b.Container.bsc.auth)
  78. if err != nil {
  79. return err
  80. }
  81. return b.respondCreation(resp, BlobTypeAppend)
  82. }