package storage // Copyright 2017 Microsoft Corporation // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. import ( "bytes" "crypto/md5" "encoding/base64" "fmt" "net/http" "net/url" "time" ) // PutAppendBlob initializes an empty append blob with specified name. An // append blob must be created using this method before appending blocks. // // See CreateBlockBlobFromReader for more info on creating blobs. // // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Blob func (b *Blob) PutAppendBlob(options *PutBlobOptions) error { params := url.Values{} headers := b.Container.bsc.client.getStandardHeaders() headers["x-ms-blob-type"] = string(BlobTypeAppend) headers = mergeHeaders(headers, headersFromStruct(b.Properties)) headers = b.Container.bsc.client.addMetadataToHeaders(headers, b.Metadata) if options != nil { params = addTimeout(params, options.Timeout) headers = mergeHeaders(headers, headersFromStruct(*options)) } uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params) resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, nil, b.Container.bsc.auth) if err != nil { return err } return b.respondCreation(resp, BlobTypeAppend) } // AppendBlockOptions includes the options for an append block operation type AppendBlockOptions struct { Timeout uint LeaseID string `header:"x-ms-lease-id"` MaxSize *uint `header:"x-ms-blob-condition-maxsize"` AppendPosition *uint `header:"x-ms-blob-condition-appendpos"` IfModifiedSince *time.Time `header:"If-Modified-Since"` IfUnmodifiedSince *time.Time `header:"If-Unmodified-Since"` IfMatch string `header:"If-Match"` IfNoneMatch string `header:"If-None-Match"` RequestID string `header:"x-ms-client-request-id"` ContentMD5 bool } // AppendBlock appends a block to an append blob. // // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Append-Block func (b *Blob) AppendBlock(chunk []byte, options *AppendBlockOptions) error { params := url.Values{"comp": {"appendblock"}} headers := b.Container.bsc.client.getStandardHeaders() headers["x-ms-blob-type"] = string(BlobTypeAppend) headers["Content-Length"] = fmt.Sprintf("%v", len(chunk)) if options != nil { params = addTimeout(params, options.Timeout) headers = mergeHeaders(headers, headersFromStruct(*options)) if options.ContentMD5 { md5sum := md5.Sum(chunk) headers[headerContentMD5] = base64.StdEncoding.EncodeToString(md5sum[:]) } } uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params) resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, bytes.NewReader(chunk), b.Container.bsc.auth) if err != nil { return err } return b.respondCreation(resp, BlobTypeAppend) }