bump azure-storage-blob-go dependency to 0.3.0 release

This commit is contained in:
Alexander van der Meij 2018-10-23 17:39:43 +02:00 committed by Péter Szilágyi
parent 4f56790efc
commit 141410e74c
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
46 changed files with 1397 additions and 881 deletions

View file

@ -1,3 +0,0 @@
package azblob
const serviceLibVersion = "0.1"

View file

@ -4,8 +4,8 @@ import (
"time" "time"
) )
// HTTPAccessConditions identifies standard HTTP access conditions which you optionally set. // ModifiedAccessConditions identifies standard HTTP access conditions which you optionally set.
type HTTPAccessConditions struct { type ModifiedAccessConditions struct {
IfModifiedSince time.Time IfModifiedSince time.Time
IfUnmodifiedSince time.Time IfUnmodifiedSince time.Time
IfMatch ETag IfMatch ETag
@ -13,7 +13,7 @@ type HTTPAccessConditions struct {
} }
// pointers is for internal infrastructure. It returns the fields as pointers. // pointers is for internal infrastructure. It returns the fields as pointers.
func (ac HTTPAccessConditions) pointers() (ims *time.Time, ius *time.Time, ime *ETag, inme *ETag) { func (ac ModifiedAccessConditions) pointers() (ims *time.Time, ius *time.Time, ime *ETag, inme *ETag) {
if !ac.IfModifiedSince.IsZero() { if !ac.IfModifiedSince.IsZero() {
ims = &ac.IfModifiedSince ims = &ac.IfModifiedSince
} }
@ -31,16 +31,14 @@ func (ac HTTPAccessConditions) pointers() (ims *time.Time, ius *time.Time, ime *
// ContainerAccessConditions identifies container-specific access conditions which you optionally set. // ContainerAccessConditions identifies container-specific access conditions which you optionally set.
type ContainerAccessConditions struct { type ContainerAccessConditions struct {
HTTPAccessConditions ModifiedAccessConditions
LeaseAccessConditions LeaseAccessConditions
} }
// BlobAccessConditions identifies blob-specific access conditions which you optionally set. // BlobAccessConditions identifies blob-specific access conditions which you optionally set.
type BlobAccessConditions struct { type BlobAccessConditions struct {
HTTPAccessConditions ModifiedAccessConditions
LeaseAccessConditions LeaseAccessConditions
AppendBlobAccessConditions
PageBlobAccessConditions
} }
// LeaseAccessConditions identifies lease access conditions for a container or blob which you optionally set. // LeaseAccessConditions identifies lease access conditions for a container or blob which you optionally set.

View file

@ -5,13 +5,12 @@ import "sync/atomic"
// AtomicMorpherInt32 identifies a method passed to and invoked by the AtomicMorphInt32 function. // AtomicMorpherInt32 identifies a method passed to and invoked by the AtomicMorphInt32 function.
// The AtomicMorpher callback is passed a startValue and based on this value it returns // The AtomicMorpher callback is passed a startValue and based on this value it returns
// what the new value should be and the result that AtomicMorph should return to its caller. // what the new value should be and the result that AtomicMorph should return to its caller.
type AtomicMorpherInt32 func(startVal int32) (val int32, morphResult interface{}) type atomicMorpherInt32 func(startVal int32) (val int32, morphResult interface{})
const targetAndMorpherMustNotBeNil = "target and morpher must not be nil"
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function. // AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
func AtomicMorphInt32(target *int32, morpher AtomicMorpherInt32) interface{} { func atomicMorphInt32(target *int32, morpher atomicMorpherInt32) interface{} {
if target == nil || morpher == nil {
panic("target and morpher mut not be nil")
}
for { for {
currentVal := atomic.LoadInt32(target) currentVal := atomic.LoadInt32(target)
desiredVal, morphResult := morpher(currentVal) desiredVal, morphResult := morpher(currentVal)
@ -24,13 +23,10 @@ func AtomicMorphInt32(target *int32, morpher AtomicMorpherInt32) interface{} {
// AtomicMorpherUint32 identifies a method passed to and invoked by the AtomicMorph function. // AtomicMorpherUint32 identifies a method passed to and invoked by the AtomicMorph function.
// The AtomicMorpher callback is passed a startValue and based on this value it returns // The AtomicMorpher callback is passed a startValue and based on this value it returns
// what the new value should be and the result that AtomicMorph should return to its caller. // what the new value should be and the result that AtomicMorph should return to its caller.
type AtomicMorpherUint32 func(startVal uint32) (val uint32, morphResult interface{}) type atomicMorpherUint32 func(startVal uint32) (val uint32, morphResult interface{})
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function. // AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
func AtomicMorphUint32(target *uint32, morpher AtomicMorpherUint32) interface{} { func atomicMorphUint32(target *uint32, morpher atomicMorpherUint32) interface{} {
if target == nil || morpher == nil {
panic("target and morpher mut not be nil")
}
for { for {
currentVal := atomic.LoadUint32(target) currentVal := atomic.LoadUint32(target)
desiredVal, morphResult := morpher(currentVal) desiredVal, morphResult := morpher(currentVal)
@ -43,13 +39,10 @@ func AtomicMorphUint32(target *uint32, morpher AtomicMorpherUint32) interface{}
// AtomicMorpherUint64 identifies a method passed to and invoked by the AtomicMorphUint64 function. // AtomicMorpherUint64 identifies a method passed to and invoked by the AtomicMorphUint64 function.
// The AtomicMorpher callback is passed a startValue and based on this value it returns // The AtomicMorpher callback is passed a startValue and based on this value it returns
// what the new value should be and the result that AtomicMorph should return to its caller. // what the new value should be and the result that AtomicMorph should return to its caller.
type AtomicMorpherInt64 func(startVal int64) (val int64, morphResult interface{}) type atomicMorpherInt64 func(startVal int64) (val int64, morphResult interface{})
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function. // AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
func AtomicMorphInt64(target *int64, morpher AtomicMorpherInt64) interface{} { func atomicMorphInt64(target *int64, morpher atomicMorpherInt64) interface{} {
if target == nil || morpher == nil {
panic("target and morpher mut not be nil")
}
for { for {
currentVal := atomic.LoadInt64(target) currentVal := atomic.LoadInt64(target)
desiredVal, morphResult := morpher(currentVal) desiredVal, morphResult := morpher(currentVal)
@ -62,13 +55,10 @@ func AtomicMorphInt64(target *int64, morpher AtomicMorpherInt64) interface{} {
// AtomicMorpherUint64 identifies a method passed to and invoked by the AtomicMorphUint64 function. // AtomicMorpherUint64 identifies a method passed to and invoked by the AtomicMorphUint64 function.
// The AtomicMorpher callback is passed a startValue and based on this value it returns // The AtomicMorpher callback is passed a startValue and based on this value it returns
// what the new value should be and the result that AtomicMorph should return to its caller. // what the new value should be and the result that AtomicMorph should return to its caller.
type AtomicMorpherUint64 func(startVal uint64) (val uint64, morphResult interface{}) type atomicMorpherUint64 func(startVal uint64) (val uint64, morphResult interface{})
// AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function. // AtomicMorph atomically morphs target in to new value (and result) as indicated bythe AtomicMorpher callback function.
func AtomicMorphUint64(target *uint64, morpher AtomicMorpherUint64) interface{} { func atomicMorphUint64(target *uint64, morpher atomicMorpherUint64) interface{} {
if target == nil || morpher == nil {
panic("target and morpher mut not be nil")
}
for { for {
currentVal := atomic.LoadUint64(target) currentVal := atomic.LoadUint64(target)
desiredVal, morphResult := morpher(currentVal) desiredVal, morphResult := morpher(currentVal)

View file

@ -3,7 +3,6 @@ package azblob
import ( import (
"context" "context"
"encoding/base64" "encoding/base64"
"fmt"
"io" "io"
"net/http" "net/http"
@ -12,10 +11,12 @@ import (
"sync" "sync"
"time" "time"
"errors"
"github.com/Azure/azure-pipeline-go/pipeline" "github.com/Azure/azure-pipeline-go/pipeline"
) )
// CommonResponseHeaders returns the headers common to all blob REST API responses. // CommonResponse returns the headers common to all blob REST API responses.
type CommonResponse interface { type CommonResponse interface {
// ETag returns the value for header ETag. // ETag returns the value for header ETag.
ETag() ETag ETag() ETag
@ -42,6 +43,7 @@ type UploadToBlockBlobOptions struct {
BlockSize int64 BlockSize int64
// Progress is a function that is invoked periodically as bytes are sent to the BlockBlobURL. // Progress is a function that is invoked periodically as bytes are sent to the BlockBlobURL.
// Note that the progress reporting is not always increasing; it can go down when retrying a request.
Progress pipeline.ProgressReceiver Progress pipeline.ProgressReceiver
// BlobHTTPHeaders indicates the HTTP headers to be associated with the blob. // BlobHTTPHeaders indicates the HTTP headers to be associated with the blob.
@ -60,17 +62,25 @@ type UploadToBlockBlobOptions struct {
// UploadBufferToBlockBlob uploads a buffer in blocks to a block blob. // UploadBufferToBlockBlob uploads a buffer in blocks to a block blob.
func UploadBufferToBlockBlob(ctx context.Context, b []byte, func UploadBufferToBlockBlob(ctx context.Context, b []byte,
blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) { blockBlobURL BlockBlobURL, o UploadToBlockBlobOptions) (CommonResponse, error) {
bufferSize := int64(len(b))
// Validate parameters and set defaults
if o.BlockSize < 0 || o.BlockSize > BlockBlobMaxUploadBlobBytes {
panic(fmt.Sprintf("BlockSize option must be > 0 and <= %d", BlockBlobMaxUploadBlobBytes))
}
if o.BlockSize == 0 { if o.BlockSize == 0 {
o.BlockSize = BlockBlobMaxUploadBlobBytes // Default if unspecified // If bufferSize > (BlockBlobMaxStageBlockBytes * BlockBlobMaxBlocks), then error
if bufferSize > BlockBlobMaxStageBlockBytes*BlockBlobMaxBlocks {
return nil, errors.New("Buffer is too large to upload to a block blob")
}
// If bufferSize <= BlockBlobMaxUploadBlobBytes, then Upload should be used with just 1 I/O request
if bufferSize <= BlockBlobMaxUploadBlobBytes {
o.BlockSize = BlockBlobMaxUploadBlobBytes // Default if unspecified
} else {
o.BlockSize = bufferSize / BlockBlobMaxBlocks // buffer / max blocks = block size to use all 50,000 blocks
if o.BlockSize < BlobDefaultDownloadBlockSize { // If the block size is smaller than 4MB, round up to 4MB
o.BlockSize = BlobDefaultDownloadBlockSize
}
// StageBlock will be called with blockSize blocks and a parallelism of (BufferSize / BlockSize).
}
} }
size := int64(len(b))
if size <= BlockBlobMaxUploadBlobBytes { if bufferSize <= BlockBlobMaxUploadBlobBytes {
// If the size can fit in 1 Upload call, do it this way // If the size can fit in 1 Upload call, do it this way
var body io.ReadSeeker = bytes.NewReader(b) var body io.ReadSeeker = bytes.NewReader(b)
if o.Progress != nil { if o.Progress != nil {
@ -79,10 +89,7 @@ func UploadBufferToBlockBlob(ctx context.Context, b []byte,
return blockBlobURL.Upload(ctx, body, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions) return blockBlobURL.Upload(ctx, body, o.BlobHTTPHeaders, o.Metadata, o.AccessConditions)
} }
var numBlocks = uint16(((size - 1) / o.BlockSize) + 1) var numBlocks = uint16(((bufferSize - 1) / o.BlockSize) + 1)
if numBlocks > BlockBlobMaxBlocks {
panic(fmt.Sprintf("The buffer's size is too big or the BlockSize is too small; the number of blocks must be <= %d", BlockBlobMaxBlocks))
}
blockIDList := make([]string, numBlocks) // Base-64 encoded block IDs blockIDList := make([]string, numBlocks) // Base-64 encoded block IDs
progress := int64(0) progress := int64(0)
@ -90,7 +97,7 @@ func UploadBufferToBlockBlob(ctx context.Context, b []byte,
err := doBatchTransfer(ctx, batchTransferOptions{ err := doBatchTransfer(ctx, batchTransferOptions{
operationName: "UploadBufferToBlockBlob", operationName: "UploadBufferToBlockBlob",
transferSize: size, transferSize: bufferSize,
chunkSize: o.BlockSize, chunkSize: o.BlockSize,
parallelism: o.Parallelism, parallelism: o.Parallelism,
operation: func(offset int64, count int64) error { operation: func(offset int64, count int64) error {
@ -115,7 +122,7 @@ func UploadBufferToBlockBlob(ctx context.Context, b []byte,
// Block IDs are unique values to avoid issue if 2+ clients are uploading blocks // Block IDs are unique values to avoid issue if 2+ clients are uploading blocks
// at the same time causing PutBlockList to get a mix of blocks from all the clients. // at the same time causing PutBlockList to get a mix of blocks from all the clients.
blockIDList[blockNum] = base64.StdEncoding.EncodeToString(newUUID().bytes()) blockIDList[blockNum] = base64.StdEncoding.EncodeToString(newUUID().bytes())
_, err := blockBlobURL.StageBlock(ctx, blockIDList[blockNum], body, o.AccessConditions.LeaseAccessConditions) _, err := blockBlobURL.StageBlock(ctx, blockIDList[blockNum], body, o.AccessConditions.LeaseAccessConditions, nil)
return err return err
}, },
}) })
@ -147,10 +154,9 @@ func UploadFileToBlockBlob(ctx context.Context, file *os.File,
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
const BlobDefaultDownloadBlockSize = int64(4 * 1024 * 1024) // 4MB const BlobDefaultDownloadBlockSize = int64(4 * 1024 * 1024) // 4MB
// DownloadFromAzureFileOptions identifies options used by the DownloadAzureFileToBuffer and DownloadAzureFileToFile functions. // DownloadFromBlobOptions identifies options used by the DownloadBlobToBuffer and DownloadBlobToFile functions.
type DownloadFromBlobOptions struct { type DownloadFromBlobOptions struct {
// BlockSize specifies the block size to use for each parallel download; the default size is BlobDefaultDownloadBlockSize. // BlockSize specifies the block size to use for each parallel download; the default size is BlobDefaultDownloadBlockSize.
BlockSize int64 BlockSize int64
@ -168,32 +174,19 @@ type DownloadFromBlobOptions struct {
RetryReaderOptionsPerBlock RetryReaderOptions RetryReaderOptionsPerBlock RetryReaderOptions
} }
// downloadAzureFileToBuffer downloads an Azure file to a buffer with parallel. // downloadBlobToBuffer downloads an Azure blob to a buffer with parallel.
func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64, func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64,
ac BlobAccessConditions, b []byte, o DownloadFromBlobOptions, b []byte, o DownloadFromBlobOptions, initialDownloadResponse *DownloadResponse) error {
initialDownloadResponse *DownloadResponse) error {
// Validate parameters, and set defaults.
if o.BlockSize < 0 {
panic("BlockSize option must be >= 0")
}
if o.BlockSize == 0 { if o.BlockSize == 0 {
o.BlockSize = BlobDefaultDownloadBlockSize o.BlockSize = BlobDefaultDownloadBlockSize
} }
if offset < 0 {
panic("offset option must be >= 0")
}
if count < 0 {
panic("count option must be >= 0")
}
if count == CountToEnd { // If size not specified, calculate it if count == CountToEnd { // If size not specified, calculate it
if initialDownloadResponse != nil { if initialDownloadResponse != nil {
count = initialDownloadResponse.ContentLength() - offset // if we have the length, use it count = initialDownloadResponse.ContentLength() - offset // if we have the length, use it
} else { } else {
// If we don't have the length at all, get it // If we don't have the length at all, get it
dr, err := blobURL.Download(ctx, 0, CountToEnd, ac, false) dr, err := blobURL.Download(ctx, 0, CountToEnd, o.AccessConditions, false)
if err != nil { if err != nil {
return err return err
} }
@ -201,10 +194,6 @@ func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, co
} }
} }
if int64(len(b)) < count {
panic(fmt.Errorf("the buffer's size should be equal to or larger than the request count of bytes: %d", count))
}
// Prepare and do parallel download. // Prepare and do parallel download.
progress := int64(0) progress := int64(0)
progressLock := &sync.Mutex{} progressLock := &sync.Mutex{}
@ -215,7 +204,7 @@ func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, co
chunkSize: o.BlockSize, chunkSize: o.BlockSize,
parallelism: o.Parallelism, parallelism: o.Parallelism,
operation: func(chunkStart int64, count int64) error { operation: func(chunkStart int64, count int64) error {
dr, err := blobURL.Download(ctx, chunkStart+ offset, count, ac, false) dr, err := blobURL.Download(ctx, chunkStart+offset, count, o.AccessConditions, false)
body := dr.Body(o.RetryReaderOptionsPerBlock) body := dr.Body(o.RetryReaderOptionsPerBlock)
if o.Progress != nil { if o.Progress != nil {
rangeProgress := int64(0) rangeProgress := int64(0)
@ -241,29 +230,24 @@ func downloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, co
return nil return nil
} }
// DownloadAzureFileToBuffer downloads an Azure file to a buffer with parallel. // DownloadBlobToBuffer downloads an Azure blob to a buffer with parallel.
// Offset and count are optional, pass 0 for both to download the entire blob. // Offset and count are optional, pass 0 for both to download the entire blob.
func DownloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64, func DownloadBlobToBuffer(ctx context.Context, blobURL BlobURL, offset int64, count int64,
ac BlobAccessConditions, b []byte, o DownloadFromBlobOptions) error { b []byte, o DownloadFromBlobOptions) error {
return downloadBlobToBuffer(ctx, blobURL, offset, count, ac, b, o, nil) return downloadBlobToBuffer(ctx, blobURL, offset, count, b, o, nil)
} }
// DownloadBlobToFile downloads an Azure file to a local file. // DownloadBlobToFile downloads an Azure blob to a local file.
// The file would be truncated if the size doesn't match. // The file would be truncated if the size doesn't match.
// Offset and count are optional, pass 0 for both to download the entire blob. // Offset and count are optional, pass 0 for both to download the entire blob.
func DownloadBlobToFile(ctx context.Context, blobURL BlobURL, offset int64, count int64, func DownloadBlobToFile(ctx context.Context, blobURL BlobURL, offset int64, count int64,
ac BlobAccessConditions, file *os.File, o DownloadFromBlobOptions) error { file *os.File, o DownloadFromBlobOptions) error {
// 1. Validate parameters. // 1. Calculate the size of the destination file
if file == nil {
panic("file must not be nil")
}
// 2. Calculate the size of the destination file
var size int64 var size int64
if count == CountToEnd { if count == CountToEnd {
// Try to get Azure file's size // Try to get Azure blob's size
props, err := blobURL.GetProperties(ctx, ac) props, err := blobURL.GetProperties(ctx, o.AccessConditions)
if err != nil { if err != nil {
return err return err
} }
@ -272,7 +256,7 @@ func DownloadBlobToFile(ctx context.Context, blobURL BlobURL, offset int64, coun
size = count size = count
} }
// 3. Compare and try to resize local file's size if it doesn't match Azure file's size. // 2. Compare and try to resize local file's size if it doesn't match Azure blob's size.
stat, err := file.Stat() stat, err := file.Stat()
if err != nil { if err != nil {
return err return err
@ -284,19 +268,18 @@ func DownloadBlobToFile(ctx context.Context, blobURL BlobURL, offset int64, coun
} }
if size > 0 { if size > 0 {
// 4. Set mmap and call DownloadAzureFileToBuffer. // 3. Set mmap and call downloadBlobToBuffer.
m, err := newMMF(file, true, 0, int(size)) m, err := newMMF(file, true, 0, int(size))
if err != nil { if err != nil {
return err return err
} }
defer m.unmap() defer m.unmap()
return downloadBlobToBuffer(ctx, blobURL, offset, size, ac, m, o, nil) return downloadBlobToBuffer(ctx, blobURL, offset, size, m, o, nil)
} else { // if the blob's size is 0, there is no need in downloading it } else { // if the blob's size is 0, there is no need in downloading it
return nil return nil
} }
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// BatchTransferOptions identifies options used by doBatchTransfer. // BatchTransferOptions identifies options used by doBatchTransfer.
@ -374,7 +357,10 @@ func UploadStreamToBlockBlob(ctx context.Context, reader io.Reader, blockBlobURL
result, err := uploadStream(ctx, reader, result, err := uploadStream(ctx, reader,
UploadStreamOptions{BufferSize: o.BufferSize, MaxBuffers: o.MaxBuffers}, UploadStreamOptions{BufferSize: o.BufferSize, MaxBuffers: o.MaxBuffers},
&uploadStreamToBlockBlobOptions{b: blockBlobURL, o: o, blockIDPrefix: newUUID()}) &uploadStreamToBlockBlobOptions{b: blockBlobURL, o: o, blockIDPrefix: newUUID()})
return result.(CommonResponse), err if err != nil {
return nil, err
}
return result.(CommonResponse), nil
} }
type uploadStreamToBlockBlobOptions struct { type uploadStreamToBlockBlobOptions struct {
@ -390,13 +376,17 @@ func (t *uploadStreamToBlockBlobOptions) start(ctx context.Context) (interface{}
} }
func (t *uploadStreamToBlockBlobOptions) chunk(ctx context.Context, num uint32, buffer []byte) error { func (t *uploadStreamToBlockBlobOptions) chunk(ctx context.Context, num uint32, buffer []byte) error {
if num == 0 && len(buffer) < t.o.BufferSize { if num == 0 {
// If whole payload fits in 1 block, don't stage it; End will upload it with 1 I/O operation
t.firstBlock = buffer t.firstBlock = buffer
// If whole payload fits in 1 block, don't stage it; End will upload it with 1 I/O operation
// If the payload is exactly the same size as the buffer, there may be more content coming in.
if len(buffer) < t.o.BufferSize {
return nil return nil
} }
}
// Else, upload a staged block... // Else, upload a staged block...
AtomicMorphUint32(&t.maxBlockNum, func(startVal uint32) (val uint32, morphResult interface{}) { atomicMorphUint32(&t.maxBlockNum, func(startVal uint32) (val uint32, morphResult interface{}) {
// Atomically remember (in t.numBlocks) the maximum block num we've ever seen // Atomically remember (in t.numBlocks) the maximum block num we've ever seen
if startVal < num { if startVal < num {
return num, nil return num, nil
@ -404,12 +394,14 @@ func (t *uploadStreamToBlockBlobOptions) chunk(ctx context.Context, num uint32,
return startVal, nil return startVal, nil
}) })
blockID := newUuidBlockID(t.blockIDPrefix).WithBlockNumber(num).ToBase64() blockID := newUuidBlockID(t.blockIDPrefix).WithBlockNumber(num).ToBase64()
_, err := t.b.StageBlock(ctx, blockID, bytes.NewReader(buffer), LeaseAccessConditions{}) _, err := t.b.StageBlock(ctx, blockID, bytes.NewReader(buffer), LeaseAccessConditions{}, nil)
return err return err
} }
func (t *uploadStreamToBlockBlobOptions) end(ctx context.Context) (interface{}, error) { func (t *uploadStreamToBlockBlobOptions) end(ctx context.Context) (interface{}, error) {
if t.maxBlockNum == 0 { // If the first block had the exact same size as the buffer
// we would have staged it as a block thinking that there might be more data coming
if t.maxBlockNum == 0 && len(t.firstBlock) != t.o.BufferSize {
// If whole payload fits in 1 block (block #0), upload it with 1 I/O operation // If whole payload fits in 1 block (block #0), upload it with 1 I/O operation
return t.b.Upload(ctx, bytes.NewReader(t.firstBlock), return t.b.Upload(ctx, bytes.NewReader(t.firstBlock),
t.o.BlobHTTPHeaders, t.o.Metadata, t.o.AccessConditions) t.o.BlobHTTPHeaders, t.o.Metadata, t.o.AccessConditions)
@ -436,7 +428,28 @@ type UploadStreamOptions struct {
BufferSize int BufferSize int
} }
type firstErr struct {
lock sync.Mutex
finalError error
}
func (fe *firstErr) set(err error) {
fe.lock.Lock()
if fe.finalError == nil {
fe.finalError = err
}
fe.lock.Unlock()
}
func (fe *firstErr) get() (err error) {
fe.lock.Lock()
err = fe.finalError
fe.lock.Unlock()
return
}
func uploadStream(ctx context.Context, reader io.Reader, o UploadStreamOptions, t iTransfer) (interface{}, error) { func uploadStream(ctx context.Context, reader io.Reader, o UploadStreamOptions, t iTransfer) (interface{}, error) {
firstErr := firstErr{}
ctx, cancel := context.WithCancel(ctx) // New context so that any failure cancels everything ctx, cancel := context.WithCancel(ctx) // New context so that any failure cancels everything
defer cancel() defer cancel()
wg := sync.WaitGroup{} // Used to know when all outgoing messages have finished processing wg := sync.WaitGroup{} // Used to know when all outgoing messages have finished processing
@ -463,9 +476,12 @@ func uploadStream(ctx context.Context, reader io.Reader, o UploadStreamOptions,
err := t.chunk(ctx, outgoingMsg.chunkNum, outgoingMsg.buffer) err := t.chunk(ctx, outgoingMsg.chunkNum, outgoingMsg.buffer)
wg.Done() // Indicate this buffer was sent wg.Done() // Indicate this buffer was sent
if nil != err { if nil != err {
// NOTE: finalErr could be assigned to multiple times here which is OK,
// some error will be returned.
firstErr.set(err)
cancel() cancel()
} }
incoming <- outgoingMsg.buffer // The goroutine reading from the stream can use reuse this buffer now incoming <- outgoingMsg.buffer // The goroutine reading from the stream can reuse this buffer now
} }
}() }()
} }
@ -490,7 +506,7 @@ func uploadStream(ctx context.Context, reader io.Reader, o UploadStreamOptions,
buffer = <-incoming buffer = <-incoming
} }
n, err := io.ReadFull(reader, buffer) n, err := io.ReadFull(reader, buffer)
if err != nil { if err != nil { // Less than len(buffer) bytes were read
buffer = buffer[:n] // Make slice match the # of read bytes buffer = buffer[:n] // Make slice match the # of read bytes
} }
if len(buffer) > 0 { if len(buffer) > 0 {
@ -499,12 +515,21 @@ func uploadStream(ctx context.Context, reader io.Reader, o UploadStreamOptions,
outgoing <- OutgoingMsg{chunkNum: c, buffer: buffer} outgoing <- OutgoingMsg{chunkNum: c, buffer: buffer}
} }
if err != nil { // The reader is done, no more outgoing buffers if err != nil { // The reader is done, no more outgoing buffers
if err == io.EOF || err == io.ErrUnexpectedEOF {
err = nil // This function does NOT return an error if io.ReadFull returns io.EOF or io.ErrUnexpectedEOF
} else {
firstErr.set(err)
}
break break
} }
} }
// NOTE: Don't close the incoming channel because the outgoing goroutines post buffers into it when they are done // NOTE: Don't close the incoming channel because the outgoing goroutines post buffers into it when they are done
close(outgoing) // Make all the outgoing goroutines terminate when this channel is empty close(outgoing) // Make all the outgoing goroutines terminate when this channel is empty
wg.Wait() // Wait for all pending outgoing messages to complete wg.Wait() // Wait for all pending outgoing messages to complete
// After all blocks uploaded, commit them to the blob & return the result err := firstErr.get()
if err == nil {
// If no error, after all blocks uploaded, commit them to the blob & return the result
return t.end(ctx) return t.end(ctx)
} }
return nil, err
}

View file

@ -1,6 +1,7 @@
package azblob package azblob
import ( import (
"net"
"net/url" "net/url"
"strings" "strings"
) )
@ -15,7 +16,8 @@ const (
// NOTE: Changing any SAS-related field requires computing a new SAS signature. // NOTE: Changing any SAS-related field requires computing a new SAS signature.
type BlobURLParts struct { type BlobURLParts struct {
Scheme string // Ex: "https://" Scheme string // Ex: "https://"
Host string // Ex: "account.blob.core.windows.net" Host string // Ex: "account.blob.core.windows.net", "10.132.141.33", "10.132.141.33:80"
IPEndpointStyleInfo IPEndpointStyleInfo
ContainerName string // "" if no container ContainerName string // "" if no container
BlobName string // "" if no blob BlobName string // "" if no blob
Snapshot string // "" if not a snapshot Snapshot string // "" if not a snapshot
@ -23,6 +25,31 @@ type BlobURLParts struct {
UnparsedParams string UnparsedParams string
} }
// IPEndpointStyleInfo is used for IP endpoint style URL when working with Azure storage emulator.
// Ex: "https://10.132.141.33/accountname/containername"
type IPEndpointStyleInfo struct {
AccountName string // "" if not using IP endpoint style
}
// isIPEndpointStyle checkes if URL's host is IP, in this case the storage account endpoint will be composed as:
// http(s)://IP(:port)/storageaccount/container/...
// As url's Host property, host could be both host or host:port
func isIPEndpointStyle(host string) bool {
if host == "" {
return false
}
if h, _, err := net.SplitHostPort(host); err == nil {
host = h
}
// For IPv6, there could be case where SplitHostPort fails for cannot finding port.
// In this case, eliminate the '[' and ']' in the URL.
// For details about IPv6 URL, please refer to https://tools.ietf.org/html/rfc2732
if host[0] == '[' && host[len(host)-1] == ']' {
host = host[1 : len(host)-1]
}
return net.ParseIP(host) != nil
}
// NewBlobURLParts parses a URL initializing BlobURLParts' fields including any SAS-related & snapshot query parameters. Any other // NewBlobURLParts parses a URL initializing BlobURLParts' fields including any SAS-related & snapshot query parameters. Any other
// query parameters remain in the UnparsedParams field. This method overwrites all fields in the BlobURLParts object. // query parameters remain in the UnparsedParams field. This method overwrites all fields in the BlobURLParts object.
func NewBlobURLParts(u url.URL) BlobURLParts { func NewBlobURLParts(u url.URL) BlobURLParts {
@ -37,9 +64,16 @@ func NewBlobURLParts(u url.URL) BlobURLParts {
if path[0] == '/' { if path[0] == '/' {
path = path[1:] // If path starts with a slash, remove it path = path[1:] // If path starts with a slash, remove it
} }
if isIPEndpointStyle(up.Host) {
if accountEndIndex := strings.Index(path, "/"); accountEndIndex == -1 { // Slash not found; path has account name & no container name or blob
up.IPEndpointStyleInfo.AccountName = path
} else {
up.IPEndpointStyleInfo.AccountName = path[:accountEndIndex] // The account name is the part between the slashes
path = path[accountEndIndex+1:] // path refers to portion after the account name now (container & blob names)
}
}
// Find the next slash (if it exists) containerEndIndex := strings.Index(path, "/") // Find the next slash (if it exists)
containerEndIndex := strings.Index(path, "/")
if containerEndIndex == -1 { // Slash not found; path has container name & no blob name if containerEndIndex == -1 { // Slash not found; path has container name & no blob name
up.ContainerName = path up.ContainerName = path
} else { } else {
@ -77,6 +111,9 @@ func (values caseInsensitiveValues) Get(key string) ([]string, bool) {
// field contains the SAS, snapshot, and unparsed query parameters. // field contains the SAS, snapshot, and unparsed query parameters.
func (up BlobURLParts) URL() url.URL { func (up BlobURLParts) URL() url.URL {
path := "" path := ""
if isIPEndpointStyle(up.Host) && up.IPEndpointStyleInfo.AccountName != "" {
path += "/" + up.IPEndpointStyleInfo.AccountName
}
// Concatenate container & blob names (if they exist) // Concatenate container & blob names (if they exist)
if up.ContainerName != "" { if up.ContainerName != "" {
path += "/" + up.ContainerName path += "/" + up.ContainerName

View file

@ -8,6 +8,7 @@ import (
) )
// BlobSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage container or blob. // BlobSASSignatureValues is used to generate a Shared Access Signature (SAS) for an Azure Storage container or blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/constructing-a-service-sas
type BlobSASSignatureValues struct { type BlobSASSignatureValues struct {
Version string `param:"sv"` // If not specified, this defaults to SASVersion Version string `param:"sv"` // If not specified, this defaults to SASVersion
Protocol SASProtocol `param:"spr"` // See the SASProtocol* constants Protocol SASProtocol `param:"spr"` // See the SASProtocol* constants
@ -27,17 +28,13 @@ type BlobSASSignatureValues struct {
// NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce // NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce
// the proper SAS query parameters. // the proper SAS query parameters.
func (v BlobSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) SASQueryParameters { func (v BlobSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) (SASQueryParameters, error) {
if sharedKeyCredential == nil {
panic("sharedKeyCredential can't be nil")
}
resource := "c" resource := "c"
if v.BlobName == "" { if v.BlobName == "" {
// Make sure the permission characters are in the correct order // Make sure the permission characters are in the correct order
perms := &ContainerSASPermissions{} perms := &ContainerSASPermissions{}
if err := perms.Parse(v.Permissions); err != nil { if err := perms.Parse(v.Permissions); err != nil {
panic(err) return SASQueryParameters{}, err
} }
v.Permissions = perms.String() v.Permissions = perms.String()
} else { } else {
@ -45,7 +42,7 @@ func (v BlobSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *Share
// Make sure the permission characters are in the correct order // Make sure the permission characters are in the correct order
perms := &BlobSASPermissions{} perms := &BlobSASPermissions{}
if err := perms.Parse(v.Permissions); err != nil { if err := perms.Parse(v.Permissions); err != nil {
panic(err) return SASQueryParameters{}, err
} }
v.Permissions = perms.String() v.Permissions = perms.String()
} }
@ -88,7 +85,7 @@ func (v BlobSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *Share
// Calculated SAS signature // Calculated SAS signature
signature: signature, signature: signature,
} }
return p return p, nil
} }
// getCanonicalName computes the canonical name for a container or blob resource for SAS signing. // getCanonicalName computes the canonical name for a container or blob resource for SAS signing.

View file

@ -45,7 +45,7 @@ func (ab AppendBlobURL) WithSnapshot(snapshot string) AppendBlobURL {
// Create creates a 0-length append blob. Call AppendBlock to append data to an append blob. // Create creates a 0-length append blob. Call AppendBlock to append data to an append blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
func (ab AppendBlobURL) Create(ctx context.Context, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*AppendBlobCreateResponse, error) { func (ab AppendBlobURL) Create(ctx context.Context, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*AppendBlobCreateResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.ModifiedAccessConditions.pointers()
return ab.abClient.Create(ctx, 0, nil, return ab.abClient.Create(ctx, 0, nil,
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5,
&h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition, &h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,
@ -56,17 +56,27 @@ func (ab AppendBlobURL) Create(ctx context.Context, h BlobHTTPHeaders, metadata
// This method panics if the stream is not at position 0. // This method panics if the stream is not at position 0.
// Note that the http client closes the body stream after the request is sent to the service. // Note that the http client closes the body stream after the request is sent to the service.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block. // For more information, see https://docs.microsoft.com/rest/api/storageservices/append-block.
func (ab AppendBlobURL) AppendBlock(ctx context.Context, body io.ReadSeeker, ac BlobAccessConditions) (*AppendBlobAppendBlockResponse, error) { func (ab AppendBlobURL) AppendBlock(ctx context.Context, body io.ReadSeeker, ac AppendBlobAccessConditions, transactionalMD5 []byte) (*AppendBlobAppendBlockResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := ac.AppendBlobAccessConditions.pointers() ifAppendPositionEqual, ifMaxSizeLessThanOrEqual := ac.AppendPositionAccessConditions.pointers()
return ab.abClient.AppendBlock(ctx, body, validateSeekableStreamAt0AndGetCount(body), nil, count, err := validateSeekableStreamAt0AndGetCount(body)
ac.LeaseAccessConditions.pointers(), if err != nil {
return nil, err
}
return ab.abClient.AppendBlock(ctx, body, count, nil,
transactionalMD5, ac.LeaseAccessConditions.pointers(),
ifMaxSizeLessThanOrEqual, ifAppendPositionEqual, ifMaxSizeLessThanOrEqual, ifAppendPositionEqual,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
} }
// AppendBlobAccessConditions identifies append blob-specific access conditions which you optionally set.
type AppendBlobAccessConditions struct { type AppendBlobAccessConditions struct {
ModifiedAccessConditions
LeaseAccessConditions
AppendPositionAccessConditions
}
// AppendPositionAccessConditions identifies append blob-specific access conditions which you optionally set.
type AppendPositionAccessConditions struct {
// IfAppendPositionEqual ensures that the AppendBlock operation succeeds // IfAppendPositionEqual ensures that the AppendBlock operation succeeds
// only if the append position is equal to a value. // only if the append position is equal to a value.
// IfAppendPositionEqual=0 means no 'IfAppendPositionEqual' header specified. // IfAppendPositionEqual=0 means no 'IfAppendPositionEqual' header specified.
@ -83,13 +93,7 @@ type AppendBlobAccessConditions struct {
} }
// pointers is for internal infrastructure. It returns the fields as pointers. // pointers is for internal infrastructure. It returns the fields as pointers.
func (ac AppendBlobAccessConditions) pointers() (iape *int64, imsltoe *int64) { func (ac AppendPositionAccessConditions) pointers() (iape *int64, imsltoe *int64) {
if ac.IfAppendPositionEqual < -1 {
panic("IfAppendPositionEqual can't be less than -1")
}
if ac.IfMaxSizeLessThanOrEqual < -1 {
panic("IfMaxSizeLessThanOrEqual can't be less than -1")
}
var zero int64 // defaults to 0 var zero int64 // defaults to 0
switch ac.IfAppendPositionEqual { switch ac.IfAppendPositionEqual {
case -1: case -1:

View file

@ -14,9 +14,6 @@ type BlobURL struct {
// NewBlobURL creates a BlobURL object using the specified URL and request policy pipeline. // NewBlobURL creates a BlobURL object using the specified URL and request policy pipeline.
func NewBlobURL(url url.URL, p pipeline.Pipeline) BlobURL { func NewBlobURL(url url.URL, p pipeline.Pipeline) BlobURL {
if p == nil {
panic("p can't be nil")
}
blobClient := newBlobClient(url, p) blobClient := newBlobClient(url, p)
return BlobURL{blobClient: blobClient} return BlobURL{blobClient: blobClient}
} }
@ -34,9 +31,6 @@ func (b BlobURL) String() string {
// WithPipeline creates a new BlobURL object identical to the source but with the specified request policy pipeline. // WithPipeline creates a new BlobURL object identical to the source but with the specified request policy pipeline.
func (b BlobURL) WithPipeline(p pipeline.Pipeline) BlobURL { func (b BlobURL) WithPipeline(p pipeline.Pipeline) BlobURL {
if p == nil {
panic("p can't be nil")
}
return NewBlobURL(b.blobClient.URL(), p) return NewBlobURL(b.blobClient.URL(), p)
} }
@ -64,13 +58,14 @@ func (b BlobURL) ToPageBlobURL() PageBlobURL {
} }
// DownloadBlob reads a range of bytes from a blob. The response also includes the blob's properties and metadata. // DownloadBlob reads a range of bytes from a blob. The response also includes the blob's properties and metadata.
// Passing azblob.CountToEnd (0) for count will download the blob from the offset to the end.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob.
func (b BlobURL) Download(ctx context.Context, offset int64, count int64, ac BlobAccessConditions, rangeGetContentMD5 bool) (*DownloadResponse, error) { func (b BlobURL) Download(ctx context.Context, offset int64, count int64, ac BlobAccessConditions, rangeGetContentMD5 bool) (*DownloadResponse, error) {
var xRangeGetContentMD5 *bool var xRangeGetContentMD5 *bool
if rangeGetContentMD5 { if rangeGetContentMD5 {
xRangeGetContentMD5 = &rangeGetContentMD5 xRangeGetContentMD5 = &rangeGetContentMD5
} }
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
dr, err := b.blobClient.Download(ctx, nil, nil, dr, err := b.blobClient.Download(ctx, nil, nil,
httpRange{offset: offset, count: count}.pointers(), httpRange{offset: offset, count: count}.pointers(),
ac.LeaseAccessConditions.pointers(), xRangeGetContentMD5, ac.LeaseAccessConditions.pointers(), xRangeGetContentMD5,
@ -90,7 +85,7 @@ func (b BlobURL) Download(ctx context.Context, offset int64, count int64, ac Blo
// Note that deleting a blob also deletes all its snapshots. // Note that deleting a blob also deletes all its snapshots.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-blob.
func (b BlobURL) Delete(ctx context.Context, deleteOptions DeleteSnapshotsOptionType, ac BlobAccessConditions) (*BlobDeleteResponse, error) { func (b BlobURL) Delete(ctx context.Context, deleteOptions DeleteSnapshotsOptionType, ac BlobAccessConditions) (*BlobDeleteResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.Delete(ctx, nil, nil, ac.LeaseAccessConditions.pointers(), deleteOptions, return b.blobClient.Delete(ctx, nil, nil, ac.LeaseAccessConditions.pointers(), deleteOptions,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
} }
@ -107,14 +102,14 @@ func (b BlobURL) Undelete(ctx context.Context) (*BlobUndeleteResponse, error) {
// bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation // bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive storage type. This operation
// does not update the blob's ETag. // does not update the blob's ETag.
// For detailed information about block blob level tiering see https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers. // For detailed information about block blob level tiering see https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blob-storage-tiers.
func (b BlobURL) SetTier(ctx context.Context, tier AccessTierType) (*BlobSetTierResponse, error) { func (b BlobURL) SetTier(ctx context.Context, tier AccessTierType, lac LeaseAccessConditions) (*BlobSetTierResponse, error) {
return b.blobClient.SetTier(ctx, tier, nil, nil) return b.blobClient.SetTier(ctx, tier, nil, nil, lac.pointers())
} }
// GetBlobProperties returns the blob's properties. // GetBlobProperties returns the blob's properties.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob-properties. // For more information, see https://docs.microsoft.com/rest/api/storageservices/get-blob-properties.
func (b BlobURL) GetProperties(ctx context.Context, ac BlobAccessConditions) (*BlobGetPropertiesResponse, error) { func (b BlobURL) GetProperties(ctx context.Context, ac BlobAccessConditions) (*BlobGetPropertiesResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.GetProperties(ctx, nil, nil, ac.LeaseAccessConditions.pointers(), return b.blobClient.GetProperties(ctx, nil, nil, ac.LeaseAccessConditions.pointers(),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
} }
@ -122,7 +117,7 @@ func (b BlobURL) GetProperties(ctx context.Context, ac BlobAccessConditions) (*B
// SetBlobHTTPHeaders changes a blob's HTTP headers. // SetBlobHTTPHeaders changes a blob's HTTP headers.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties. // For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties.
func (b BlobURL) SetHTTPHeaders(ctx context.Context, h BlobHTTPHeaders, ac BlobAccessConditions) (*BlobSetHTTPHeadersResponse, error) { func (b BlobURL) SetHTTPHeaders(ctx context.Context, h BlobHTTPHeaders, ac BlobAccessConditions) (*BlobSetHTTPHeadersResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.SetHTTPHeaders(ctx, nil, return b.blobClient.SetHTTPHeaders(ctx, nil,
&h.CacheControl, &h.ContentType, h.ContentMD5, &h.ContentEncoding, &h.ContentLanguage, &h.CacheControl, &h.ContentType, h.ContentMD5, &h.ContentEncoding, &h.ContentLanguage,
ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
@ -132,7 +127,7 @@ func (b BlobURL) SetHTTPHeaders(ctx context.Context, h BlobHTTPHeaders, ac BlobA
// SetBlobMetadata changes a blob's metadata. // SetBlobMetadata changes a blob's metadata.
// https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata. // https://docs.microsoft.com/rest/api/storageservices/set-blob-metadata.
func (b BlobURL) SetMetadata(ctx context.Context, metadata Metadata, ac BlobAccessConditions) (*BlobSetMetadataResponse, error) { func (b BlobURL) SetMetadata(ctx context.Context, metadata Metadata, ac BlobAccessConditions) (*BlobSetMetadataResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.SetMetadata(ctx, nil, metadata, ac.LeaseAccessConditions.pointers(), return b.blobClient.SetMetadata(ctx, nil, metadata, ac.LeaseAccessConditions.pointers(),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
} }
@ -143,14 +138,14 @@ func (b BlobURL) CreateSnapshot(ctx context.Context, metadata Metadata, ac BlobA
// CreateSnapshot does NOT panic if the user tries to create a snapshot using a URL that already has a snapshot query parameter // CreateSnapshot does NOT panic if the user tries to create a snapshot using a URL that already has a snapshot query parameter
// because checking this would be a performance hit for a VERY unusual path and I don't think the common case should suffer this // because checking this would be a performance hit for a VERY unusual path and I don't think the common case should suffer this
// performance hit. // performance hit.
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return b.blobClient.CreateSnapshot(ctx, nil, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, ac.LeaseAccessConditions.pointers(), nil) return b.blobClient.CreateSnapshot(ctx, nil, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, ac.LeaseAccessConditions.pointers(), nil)
} }
// AcquireLease acquires a lease on the blob for write and delete operations. The lease duration must be between // AcquireLease acquires a lease on the blob for write and delete operations. The lease duration must be between
// 15 to 60 seconds, or infinite (-1). // 15 to 60 seconds, or infinite (-1).
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
func (b BlobURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac HTTPAccessConditions) (*BlobAcquireLeaseResponse, error) { func (b BlobURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac ModifiedAccessConditions) (*BlobAcquireLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.AcquireLease(ctx, nil, &duration, &proposedID, return b.blobClient.AcquireLease(ctx, nil, &duration, &proposedID,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
@ -158,7 +153,7 @@ func (b BlobURL) AcquireLease(ctx context.Context, proposedID string, duration i
// RenewLease renews the blob's previously-acquired lease. // RenewLease renews the blob's previously-acquired lease.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
func (b BlobURL) RenewLease(ctx context.Context, leaseID string, ac HTTPAccessConditions) (*BlobRenewLeaseResponse, error) { func (b BlobURL) RenewLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*BlobRenewLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.RenewLease(ctx, leaseID, nil, return b.blobClient.RenewLease(ctx, leaseID, nil,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
@ -166,7 +161,7 @@ func (b BlobURL) RenewLease(ctx context.Context, leaseID string, ac HTTPAccessCo
// ReleaseLease releases the blob's previously-acquired lease. // ReleaseLease releases the blob's previously-acquired lease.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
func (b BlobURL) ReleaseLease(ctx context.Context, leaseID string, ac HTTPAccessConditions) (*BlobReleaseLeaseResponse, error) { func (b BlobURL) ReleaseLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*BlobReleaseLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.ReleaseLease(ctx, leaseID, nil, return b.blobClient.ReleaseLease(ctx, leaseID, nil,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
@ -175,7 +170,7 @@ func (b BlobURL) ReleaseLease(ctx context.Context, leaseID string, ac HTTPAccess
// BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1) // BreakLease breaks the blob's previously-acquired lease (if it exists). Pass the LeaseBreakDefault (-1)
// constant to break a fixed-duration lease when it expires or an infinite lease immediately. // constant to break a fixed-duration lease when it expires or an infinite lease immediately.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
func (b BlobURL) BreakLease(ctx context.Context, breakPeriodInSeconds int32, ac HTTPAccessConditions) (*BlobBreakLeaseResponse, error) { func (b BlobURL) BreakLease(ctx context.Context, breakPeriodInSeconds int32, ac ModifiedAccessConditions) (*BlobBreakLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.BreakLease(ctx, nil, leasePeriodPointer(breakPeriodInSeconds), return b.blobClient.BreakLease(ctx, nil, leasePeriodPointer(breakPeriodInSeconds),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
@ -183,7 +178,7 @@ func (b BlobURL) BreakLease(ctx context.Context, breakPeriodInSeconds int32, ac
// ChangeLease changes the blob's lease ID. // ChangeLease changes the blob's lease ID.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-blob.
func (b BlobURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac HTTPAccessConditions) (*BlobChangeLeaseResponse, error) { func (b BlobURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac ModifiedAccessConditions) (*BlobChangeLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.pointers()
return b.blobClient.ChangeLease(ctx, leaseID, proposedID, return b.blobClient.ChangeLease(ctx, leaseID, proposedID,
nil, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) nil, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
@ -201,10 +196,9 @@ func leasePeriodPointer(period int32) (p *int32) {
// StartCopyFromURL copies the data at the source URL to a blob. // StartCopyFromURL copies the data at the source URL to a blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/copy-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/copy-blob.
func (b BlobURL) StartCopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac BlobAccessConditions, dstac BlobAccessConditions) (*BlobStartCopyFromURLResponse, error) { func (b BlobURL) StartCopyFromURL(ctx context.Context, source url.URL, metadata Metadata, srcac ModifiedAccessConditions, dstac BlobAccessConditions) (*BlobStartCopyFromURLResponse, error) {
srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.HTTPAccessConditions.pointers() srcIfModifiedSince, srcIfUnmodifiedSince, srcIfMatchETag, srcIfNoneMatchETag := srcac.pointers()
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.HTTPAccessConditions.pointers() dstIfModifiedSince, dstIfUnmodifiedSince, dstIfMatchETag, dstIfNoneMatchETag := dstac.ModifiedAccessConditions.pointers()
srcLeaseID := srcac.LeaseAccessConditions.pointers()
dstLeaseID := dstac.LeaseAccessConditions.pointers() dstLeaseID := dstac.LeaseAccessConditions.pointers()
return b.blobClient.StartCopyFromURL(ctx, source.String(), nil, metadata, return b.blobClient.StartCopyFromURL(ctx, source.String(), nil, metadata,
@ -212,7 +206,7 @@ func (b BlobURL) StartCopyFromURL(ctx context.Context, source url.URL, metadata
srcIfMatchETag, srcIfNoneMatchETag, srcIfMatchETag, srcIfNoneMatchETag,
dstIfModifiedSince, dstIfUnmodifiedSince, dstIfModifiedSince, dstIfUnmodifiedSince,
dstIfMatchETag, dstIfNoneMatchETag, dstIfMatchETag, dstIfNoneMatchETag,
dstLeaseID, srcLeaseID, nil) dstLeaseID, nil)
} }
// AbortCopyFromURL stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata. // AbortCopyFromURL stops a pending copy that was previously started and leaves a destination blob with 0 length and metadata.

View file

@ -12,7 +12,7 @@ import (
) )
const ( const (
// BlockBlobMaxPutBlobBytes indicates the maximum number of bytes that can be sent in a call to Upload. // BlockBlobMaxUploadBlobBytes indicates the maximum number of bytes that can be sent in a call to Upload.
BlockBlobMaxUploadBlobBytes = 256 * 1024 * 1024 // 256MB BlockBlobMaxUploadBlobBytes = 256 * 1024 * 1024 // 256MB
// BlockBlobMaxStageBlockBytes indicates the maximum number of bytes that can be sent in a call to StageBlock. // BlockBlobMaxStageBlockBytes indicates the maximum number of bytes that can be sent in a call to StageBlock.
@ -30,9 +30,6 @@ type BlockBlobURL struct {
// NewBlockBlobURL creates a BlockBlobURL object using the specified URL and request policy pipeline. // NewBlockBlobURL creates a BlockBlobURL object using the specified URL and request policy pipeline.
func NewBlockBlobURL(url url.URL, p pipeline.Pipeline) BlockBlobURL { func NewBlockBlobURL(url url.URL, p pipeline.Pipeline) BlockBlobURL {
if p == nil {
panic("p can't be nil")
}
blobClient := newBlobClient(url, p) blobClient := newBlobClient(url, p)
bbClient := newBlockBlobClient(url, p) bbClient := newBlockBlobClient(url, p)
return BlockBlobURL{BlobURL: BlobURL{blobClient: blobClient}, bbClient: bbClient} return BlockBlobURL{BlobURL: BlobURL{blobClient: blobClient}, bbClient: bbClient}
@ -59,8 +56,12 @@ func (bb BlockBlobURL) WithSnapshot(snapshot string) BlockBlobURL {
// Note that the http client closes the body stream after the request is sent to the service. // Note that the http client closes the body stream after the request is sent to the service.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
func (bb BlockBlobURL) Upload(ctx context.Context, body io.ReadSeeker, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*BlockBlobUploadResponse, error) { func (bb BlockBlobURL) Upload(ctx context.Context, body io.ReadSeeker, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*BlockBlobUploadResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return bb.bbClient.Upload(ctx, body, validateSeekableStreamAt0AndGetCount(body), nil, count, err := validateSeekableStreamAt0AndGetCount(body)
if err != nil {
return nil, err
}
return bb.bbClient.Upload(ctx, body, count, nil,
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5,
&h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(), &h.CacheControl, metadata, ac.LeaseAccessConditions.pointers(),
&h.ContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, &h.ContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag,
@ -70,16 +71,19 @@ func (bb BlockBlobURL) Upload(ctx context.Context, body io.ReadSeeker, h BlobHTT
// StageBlock uploads the specified block to the block blob's "staging area" to be later committed by a call to CommitBlockList. // StageBlock uploads the specified block to the block blob's "staging area" to be later committed by a call to CommitBlockList.
// Note that the http client closes the body stream after the request is sent to the service. // Note that the http client closes the body stream after the request is sent to the service.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block.
func (bb BlockBlobURL) StageBlock(ctx context.Context, base64BlockID string, body io.ReadSeeker, ac LeaseAccessConditions) (*BlockBlobStageBlockResponse, error) { func (bb BlockBlobURL) StageBlock(ctx context.Context, base64BlockID string, body io.ReadSeeker, ac LeaseAccessConditions, transactionalMD5 []byte) (*BlockBlobStageBlockResponse, error) {
return bb.bbClient.StageBlock(ctx, base64BlockID, validateSeekableStreamAt0AndGetCount(body), body, nil, ac.pointers(), nil) count, err := validateSeekableStreamAt0AndGetCount(body)
if err != nil {
return nil, err
}
return bb.bbClient.StageBlock(ctx, base64BlockID, count, body, transactionalMD5, nil, ac.pointers(), nil)
} }
// StageBlockFromURL copies the specified block from a source URL to the block blob's "staging area" to be later committed by a call to CommitBlockList. // StageBlockFromURL copies the specified block from a source URL to the block blob's "staging area" to be later committed by a call to CommitBlockList.
// If count is CountToEnd (0), then data is read from specified offset to the end. // If count is CountToEnd (0), then data is read from specified offset to the end.
// For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url. // For more information, see https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url.
func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL url.URL, offset int64, count int64, ac LeaseAccessConditions) (*BlockBlobStageBlockFromURLResponse, error) { func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID string, sourceURL url.URL, offset int64, count int64, ac LeaseAccessConditions) (*BlockBlobStageBlockFromURLResponse, error) {
sourceURLStr := sourceURL.String() return bb.bbClient.StageBlockFromURL(ctx, base64BlockID, 0, sourceURL.String(), httpRange{offset: offset, count: count}.pointers(), nil, nil, ac.pointers(), nil)
return bb.bbClient.StageBlockFromURL(ctx, base64BlockID, 0, &sourceURLStr, httpRange{offset: offset, count: count}.pointers(), nil, nil, ac.pointers(), nil)
} }
// CommitBlockList writes a blob by specifying the list of block IDs that make up the blob. // CommitBlockList writes a blob by specifying the list of block IDs that make up the blob.
@ -90,7 +94,7 @@ func (bb BlockBlobURL) StageBlockFromURL(ctx context.Context, base64BlockID stri
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block-list. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-block-list.
func (bb BlockBlobURL) CommitBlockList(ctx context.Context, base64BlockIDs []string, h BlobHTTPHeaders, func (bb BlockBlobURL) CommitBlockList(ctx context.Context, base64BlockIDs []string, h BlobHTTPHeaders,
metadata Metadata, ac BlobAccessConditions) (*BlockBlobCommitBlockListResponse, error) { metadata Metadata, ac BlobAccessConditions) (*BlockBlobCommitBlockListResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return bb.bbClient.CommitBlockList(ctx, BlockLookupList{Latest: base64BlockIDs}, nil, return bb.bbClient.CommitBlockList(ctx, BlockLookupList{Latest: base64BlockIDs}, nil,
&h.CacheControl, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.CacheControl, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5,
metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition, metadata, ac.LeaseAccessConditions.pointers(), &h.ContentDisposition,

View file

@ -3,6 +3,7 @@ package azblob
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"net/url" "net/url"
@ -16,9 +17,6 @@ type ContainerURL struct {
// NewContainerURL creates a ContainerURL object using the specified URL and request policy pipeline. // NewContainerURL creates a ContainerURL object using the specified URL and request policy pipeline.
func NewContainerURL(url url.URL, p pipeline.Pipeline) ContainerURL { func NewContainerURL(url url.URL, p pipeline.Pipeline) ContainerURL {
if p == nil {
panic("p can't be nil")
}
client := newContainerClient(url, p) client := newContainerClient(url, p)
return ContainerURL{client: client} return ContainerURL{client: client}
} }
@ -89,10 +87,10 @@ func (c ContainerURL) Create(ctx context.Context, metadata Metadata, publicAcces
// For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-container. // For more information, see https://docs.microsoft.com/rest/api/storageservices/delete-container.
func (c ContainerURL) Delete(ctx context.Context, ac ContainerAccessConditions) (*ContainerDeleteResponse, error) { func (c ContainerURL) Delete(ctx context.Context, ac ContainerAccessConditions) (*ContainerDeleteResponse, error) {
if ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone { if ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone {
panic("the IfMatch and IfNoneMatch access conditions must have their default values because they are ignored by the service") return nil, errors.New("the IfMatch and IfNoneMatch access conditions must have their default values because they are ignored by the service")
} }
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, _, _ := ac.ModifiedAccessConditions.pointers()
return c.client.Delete(ctx, nil, ac.LeaseAccessConditions.pointers(), return c.client.Delete(ctx, nil, ac.LeaseAccessConditions.pointers(),
ifModifiedSince, ifUnmodifiedSince, nil) ifModifiedSince, ifUnmodifiedSince, nil)
} }
@ -109,9 +107,9 @@ func (c ContainerURL) GetProperties(ctx context.Context, ac LeaseAccessCondition
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-container-metadata. // For more information, see https://docs.microsoft.com/rest/api/storageservices/set-container-metadata.
func (c ContainerURL) SetMetadata(ctx context.Context, metadata Metadata, ac ContainerAccessConditions) (*ContainerSetMetadataResponse, error) { func (c ContainerURL) SetMetadata(ctx context.Context, metadata Metadata, ac ContainerAccessConditions) (*ContainerSetMetadataResponse, error) {
if !ac.IfUnmodifiedSince.IsZero() || ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone { if !ac.IfUnmodifiedSince.IsZero() || ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone {
panic("the IfUnmodifiedSince, IfMatch, and IfNoneMatch must have their default values because they are ignored by the blob service") return nil, errors.New("the IfUnmodifiedSince, IfMatch, and IfNoneMatch must have their default values because they are ignored by the blob service")
} }
ifModifiedSince, _, _, _ := ac.HTTPAccessConditions.pointers() ifModifiedSince, _, _, _ := ac.ModifiedAccessConditions.pointers()
return c.client.SetMetadata(ctx, nil, ac.LeaseAccessConditions.pointers(), metadata, ifModifiedSince, nil) return c.client.SetMetadata(ctx, nil, ac.LeaseAccessConditions.pointers(), metadata, ifModifiedSince, nil)
} }
@ -181,16 +179,16 @@ func (p *AccessPolicyPermission) Parse(s string) error {
func (c ContainerURL) SetAccessPolicy(ctx context.Context, accessType PublicAccessType, si []SignedIdentifier, func (c ContainerURL) SetAccessPolicy(ctx context.Context, accessType PublicAccessType, si []SignedIdentifier,
ac ContainerAccessConditions) (*ContainerSetAccessPolicyResponse, error) { ac ContainerAccessConditions) (*ContainerSetAccessPolicyResponse, error) {
if ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone { if ac.IfMatch != ETagNone || ac.IfNoneMatch != ETagNone {
panic("the IfMatch and IfNoneMatch access conditions must have their default values because they are ignored by the service") return nil, errors.New("the IfMatch and IfNoneMatch access conditions must have their default values because they are ignored by the service")
} }
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, _, _ := ac.ModifiedAccessConditions.pointers()
return c.client.SetAccessPolicy(ctx, si, nil, ac.LeaseAccessConditions.pointers(), return c.client.SetAccessPolicy(ctx, si, nil, ac.LeaseAccessConditions.pointers(),
accessType, ifModifiedSince, ifUnmodifiedSince, nil) accessType, ifModifiedSince, ifUnmodifiedSince, nil)
} }
// AcquireLease acquires a lease on the container for delete operations. The lease duration must be between 15 to 60 seconds, or infinite (-1). // AcquireLease acquires a lease on the container for delete operations. The lease duration must be between 15 to 60 seconds, or infinite (-1).
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
func (c ContainerURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac HTTPAccessConditions) (*ContainerAcquireLeaseResponse, error) { func (c ContainerURL) AcquireLease(ctx context.Context, proposedID string, duration int32, ac ModifiedAccessConditions) (*ContainerAcquireLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
return c.client.AcquireLease(ctx, nil, &duration, &proposedID, return c.client.AcquireLease(ctx, nil, &duration, &proposedID,
ifModifiedSince, ifUnmodifiedSince, nil) ifModifiedSince, ifUnmodifiedSince, nil)
@ -198,28 +196,28 @@ func (c ContainerURL) AcquireLease(ctx context.Context, proposedID string, durat
// RenewLease renews the container's previously-acquired lease. // RenewLease renews the container's previously-acquired lease.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
func (c ContainerURL) RenewLease(ctx context.Context, leaseID string, ac HTTPAccessConditions) (*ContainerRenewLeaseResponse, error) { func (c ContainerURL) RenewLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*ContainerRenewLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
return c.client.RenewLease(ctx, leaseID, nil, ifModifiedSince, ifUnmodifiedSince, nil) return c.client.RenewLease(ctx, leaseID, nil, ifModifiedSince, ifUnmodifiedSince, nil)
} }
// ReleaseLease releases the container's previously-acquired lease. // ReleaseLease releases the container's previously-acquired lease.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
func (c ContainerURL) ReleaseLease(ctx context.Context, leaseID string, ac HTTPAccessConditions) (*ContainerReleaseLeaseResponse, error) { func (c ContainerURL) ReleaseLease(ctx context.Context, leaseID string, ac ModifiedAccessConditions) (*ContainerReleaseLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
return c.client.ReleaseLease(ctx, leaseID, nil, ifModifiedSince, ifUnmodifiedSince, nil) return c.client.ReleaseLease(ctx, leaseID, nil, ifModifiedSince, ifUnmodifiedSince, nil)
} }
// BreakLease breaks the container's previously-acquired lease (if it exists). // BreakLease breaks the container's previously-acquired lease (if it exists).
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
func (c ContainerURL) BreakLease(ctx context.Context, period int32, ac HTTPAccessConditions) (*ContainerBreakLeaseResponse, error) { func (c ContainerURL) BreakLease(ctx context.Context, period int32, ac ModifiedAccessConditions) (*ContainerBreakLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
return c.client.BreakLease(ctx, nil, leasePeriodPointer(period), ifModifiedSince, ifUnmodifiedSince, nil) return c.client.BreakLease(ctx, nil, leasePeriodPointer(period), ifModifiedSince, ifUnmodifiedSince, nil)
} }
// ChangeLease changes the container's lease ID. // ChangeLease changes the container's lease ID.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container. // For more information, see https://docs.microsoft.com/rest/api/storageservices/lease-container.
func (c ContainerURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac HTTPAccessConditions) (*ContainerChangeLeaseResponse, error) { func (c ContainerURL) ChangeLease(ctx context.Context, leaseID string, proposedID string, ac ModifiedAccessConditions) (*ContainerChangeLeaseResponse, error) {
ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers() ifModifiedSince, ifUnmodifiedSince, _, _ := ac.pointers()
return c.client.ChangeLease(ctx, leaseID, proposedID, nil, ifModifiedSince, ifUnmodifiedSince, nil) return c.client.ChangeLease(ctx, leaseID, proposedID, nil, ifModifiedSince, ifUnmodifiedSince, nil)
} }
@ -241,7 +239,7 @@ func (c ContainerURL) ListBlobsFlatSegment(ctx context.Context, marker Marker, o
// For more information, see https://docs.microsoft.com/rest/api/storageservices/list-blobs. // For more information, see https://docs.microsoft.com/rest/api/storageservices/list-blobs.
func (c ContainerURL) ListBlobsHierarchySegment(ctx context.Context, marker Marker, delimiter string, o ListBlobsSegmentOptions) (*ListBlobsHierarchySegmentResponse, error) { func (c ContainerURL) ListBlobsHierarchySegment(ctx context.Context, marker Marker, delimiter string, o ListBlobsSegmentOptions) (*ListBlobsHierarchySegmentResponse, error) {
if o.Details.Snapshots { if o.Details.Snapshots {
panic("snapshots are not supported in this listing operation") return nil, errors.New("snapshots are not supported in this listing operation")
} }
prefix, include, maxResults := o.pointers() prefix, include, maxResults := o.pointers()
return c.client.ListBlobHierarchySegment(ctx, delimiter, prefix, marker.val, maxResults, include, nil, nil) return c.client.ListBlobHierarchySegment(ctx, delimiter, prefix, marker.val, maxResults, include, nil, nil)
@ -264,9 +262,6 @@ func (o *ListBlobsSegmentOptions) pointers() (prefix *string, include []ListBlob
} }
include = o.Details.slice() include = o.Details.slice()
if o.MaxResults != 0 { if o.MaxResults != 0 {
if o.MaxResults < 0 {
panic("MaxResults must be >= 0")
}
maxResults = &o.MaxResults maxResults = &o.MaxResults
} }
return return

View file

@ -26,9 +26,6 @@ type PageBlobURL struct {
// NewPageBlobURL creates a PageBlobURL object using the specified URL and request policy pipeline. // NewPageBlobURL creates a PageBlobURL object using the specified URL and request policy pipeline.
func NewPageBlobURL(url url.URL, p pipeline.Pipeline) PageBlobURL { func NewPageBlobURL(url url.URL, p pipeline.Pipeline) PageBlobURL {
if p == nil {
panic("p can't be nil")
}
blobClient := newBlobClient(url, p) blobClient := newBlobClient(url, p)
pbClient := newPageBlobClient(url, p) pbClient := newPageBlobClient(url, p)
return PageBlobURL{BlobURL: BlobURL{blobClient: blobClient}, pbClient: pbClient} return PageBlobURL{BlobURL: BlobURL{blobClient: blobClient}, pbClient: pbClient}
@ -47,28 +44,28 @@ func (pb PageBlobURL) WithSnapshot(snapshot string) PageBlobURL {
return NewPageBlobURL(p.URL(), pb.blobClient.Pipeline()) return NewPageBlobURL(p.URL(), pb.blobClient.Pipeline())
} }
// CreatePageBlob creates a page blob of the specified length. Call PutPage to upload data data to a page blob. // Create creates a page blob of the specified length. Call PutPage to upload data data to a page blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-blob.
func (pb PageBlobURL) Create(ctx context.Context, size int64, sequenceNumber int64, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*PageBlobCreateResponse, error) { func (pb PageBlobURL) Create(ctx context.Context, size int64, sequenceNumber int64, h BlobHTTPHeaders, metadata Metadata, ac BlobAccessConditions) (*PageBlobCreateResponse, error) {
if sequenceNumber < 0 { ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
panic("sequenceNumber must be greater than or equal to 0") return pb.pbClient.Create(ctx, 0, size, nil,
}
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers()
return pb.pbClient.Create(ctx, 0, nil,
&h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.CacheControl, &h.ContentType, &h.ContentEncoding, &h.ContentLanguage, h.ContentMD5, &h.CacheControl,
metadata, ac.LeaseAccessConditions.pointers(), metadata, ac.LeaseAccessConditions.pointers(),
&h.ContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, &size, &sequenceNumber, nil) &h.ContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, &sequenceNumber, nil)
} }
// UploadPages writes 1 or more pages to the page blob. The start offset and the stream size must be a multiple of 512 bytes. // UploadPages writes 1 or more pages to the page blob. The start offset and the stream size must be a multiple of 512 bytes.
// This method panics if the stream is not at position 0. // This method panics if the stream is not at position 0.
// Note that the http client closes the body stream after the request is sent to the service. // Note that the http client closes the body stream after the request is sent to the service.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page.
func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.ReadSeeker, ac BlobAccessConditions) (*PageBlobUploadPagesResponse, error) { func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.ReadSeeker, ac PageBlobAccessConditions, transactionalMD5 []byte) (*PageBlobUploadPagesResponse, error) {
count := validateSeekableStreamAt0AndGetCount(body) count, err := validateSeekableStreamAt0AndGetCount(body)
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() if err != nil {
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.PageBlobAccessConditions.pointers() return nil, err
return pb.pbClient.UploadPages(ctx, body, count, nil, }
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.SequenceNumberAccessConditions.pointers()
return pb.pbClient.UploadPages(ctx, body, count, transactionalMD5, nil,
PageRange{Start: offset, End: offset + count - 1}.pointers(), PageRange{Start: offset, End: offset + count - 1}.pointers(),
ac.LeaseAccessConditions.pointers(), ac.LeaseAccessConditions.pointers(),
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual, ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual,
@ -77,9 +74,9 @@ func (pb PageBlobURL) UploadPages(ctx context.Context, offset int64, body io.Rea
// ClearPages frees the specified pages from the page blob. // ClearPages frees the specified pages from the page blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page. // For more information, see https://docs.microsoft.com/rest/api/storageservices/put-page.
func (pb PageBlobURL) ClearPages(ctx context.Context, offset int64, count int64, ac BlobAccessConditions) (*PageBlobClearPagesResponse, error) { func (pb PageBlobURL) ClearPages(ctx context.Context, offset int64, count int64, ac PageBlobAccessConditions) (*PageBlobClearPagesResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.PageBlobAccessConditions.pointers() ifSequenceNumberLessThanOrEqual, ifSequenceNumberLessThan, ifSequenceNumberEqual := ac.SequenceNumberAccessConditions.pointers()
return pb.pbClient.ClearPages(ctx, 0, nil, return pb.pbClient.ClearPages(ctx, 0, nil,
PageRange{Start: offset, End: offset + count - 1}.pointers(), PageRange{Start: offset, End: offset + count - 1}.pointers(),
ac.LeaseAccessConditions.pointers(), ac.LeaseAccessConditions.pointers(),
@ -90,7 +87,7 @@ func (pb PageBlobURL) ClearPages(ctx context.Context, offset int64, count int64,
// GetPageRanges returns the list of valid page ranges for a page blob or snapshot of a page blob. // GetPageRanges returns the list of valid page ranges for a page blob or snapshot of a page blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges. // For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges.
func (pb PageBlobURL) GetPageRanges(ctx context.Context, offset int64, count int64, ac BlobAccessConditions) (*PageList, error) { func (pb PageBlobURL) GetPageRanges(ctx context.Context, offset int64, count int64, ac BlobAccessConditions) (*PageList, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return pb.pbClient.GetPageRanges(ctx, nil, nil, return pb.pbClient.GetPageRanges(ctx, nil, nil,
httpRange{offset: offset, count: count}.pointers(), httpRange{offset: offset, count: count}.pointers(),
ac.LeaseAccessConditions.pointers(), ac.LeaseAccessConditions.pointers(),
@ -100,7 +97,7 @@ func (pb PageBlobURL) GetPageRanges(ctx context.Context, offset int64, count int
// GetPageRangesDiff gets the collection of page ranges that differ between a specified snapshot and this page blob. // GetPageRangesDiff gets the collection of page ranges that differ between a specified snapshot and this page blob.
// For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges. // For more information, see https://docs.microsoft.com/rest/api/storageservices/get-page-ranges.
func (pb PageBlobURL) GetPageRangesDiff(ctx context.Context, offset int64, count int64, prevSnapshot string, ac BlobAccessConditions) (*PageList, error) { func (pb PageBlobURL) GetPageRangesDiff(ctx context.Context, offset int64, count int64, prevSnapshot string, ac BlobAccessConditions) (*PageList, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
return pb.pbClient.GetPageRangesDiff(ctx, nil, nil, &prevSnapshot, return pb.pbClient.GetPageRangesDiff(ctx, nil, nil, &prevSnapshot,
httpRange{offset: offset, count: count}.pointers(), httpRange{offset: offset, count: count}.pointers(),
ac.LeaseAccessConditions.pointers(), ac.LeaseAccessConditions.pointers(),
@ -111,10 +108,7 @@ func (pb PageBlobURL) GetPageRangesDiff(ctx context.Context, offset int64, count
// Resize resizes the page blob to the specified size (which must be a multiple of 512). // Resize resizes the page blob to the specified size (which must be a multiple of 512).
// For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties. // For more information, see https://docs.microsoft.com/rest/api/storageservices/set-blob-properties.
func (pb PageBlobURL) Resize(ctx context.Context, size int64, ac BlobAccessConditions) (*PageBlobResizeResponse, error) { func (pb PageBlobURL) Resize(ctx context.Context, size int64, ac BlobAccessConditions) (*PageBlobResizeResponse, error) {
if size%PageBlobPageBytes != 0 { ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
panic("Size must be a multiple of PageBlobPageBytes (512)")
}
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers()
return pb.pbClient.Resize(ctx, size, nil, ac.LeaseAccessConditions.pointers(), return pb.pbClient.Resize(ctx, size, nil, ac.LeaseAccessConditions.pointers(),
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
} }
@ -122,14 +116,11 @@ func (pb PageBlobURL) Resize(ctx context.Context, size int64, ac BlobAccessCondi
// SetSequenceNumber sets the page blob's sequence number. // SetSequenceNumber sets the page blob's sequence number.
func (pb PageBlobURL) UpdateSequenceNumber(ctx context.Context, action SequenceNumberActionType, sequenceNumber int64, func (pb PageBlobURL) UpdateSequenceNumber(ctx context.Context, action SequenceNumberActionType, sequenceNumber int64,
ac BlobAccessConditions) (*PageBlobUpdateSequenceNumberResponse, error) { ac BlobAccessConditions) (*PageBlobUpdateSequenceNumberResponse, error) {
if sequenceNumber < 0 {
panic("sequenceNumber must be greater than or equal to 0")
}
sn := &sequenceNumber sn := &sequenceNumber
if action == SequenceNumberActionIncrement { if action == SequenceNumberActionIncrement {
sn = nil sn = nil
} }
ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch := ac.ModifiedAccessConditions.pointers()
return pb.pbClient.UpdateSequenceNumber(ctx, action, nil, return pb.pbClient.UpdateSequenceNumber(ctx, action, nil,
ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, ac.LeaseAccessConditions.pointers(), ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch,
sn, nil) sn, nil)
@ -141,37 +132,28 @@ func (pb PageBlobURL) UpdateSequenceNumber(ctx context.Context, action SequenceN
// For more information, see https://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob and // For more information, see https://docs.microsoft.com/rest/api/storageservices/incremental-copy-blob and
// https://docs.microsoft.com/en-us/azure/virtual-machines/windows/incremental-snapshots. // https://docs.microsoft.com/en-us/azure/virtual-machines/windows/incremental-snapshots.
func (pb PageBlobURL) StartCopyIncremental(ctx context.Context, source url.URL, snapshot string, ac BlobAccessConditions) (*PageBlobCopyIncrementalResponse, error) { func (pb PageBlobURL) StartCopyIncremental(ctx context.Context, source url.URL, snapshot string, ac BlobAccessConditions) (*PageBlobCopyIncrementalResponse, error) {
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.HTTPAccessConditions.pointers() ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag := ac.ModifiedAccessConditions.pointers()
qp := source.Query() qp := source.Query()
qp.Set("snapshot", snapshot) qp.Set("snapshot", snapshot)
source.RawQuery = qp.Encode() source.RawQuery = qp.Encode()
return pb.pbClient.CopyIncremental(ctx, source.String(), nil, nil, return pb.pbClient.CopyIncremental(ctx, source.String(), nil,
ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil) ifModifiedSince, ifUnmodifiedSince, ifMatchETag, ifNoneMatchETag, nil)
} }
func (pr PageRange) pointers() *string { func (pr PageRange) pointers() *string {
if pr.Start < 0 {
panic("PageRange's Start value must be greater than or equal to 0")
}
if pr.End <= 0 {
panic("PageRange's End value must be greater than 0")
}
if pr.Start%PageBlobPageBytes != 0 {
panic("PageRange's Start value must be a multiple of 512")
}
if pr.End%PageBlobPageBytes != (PageBlobPageBytes - 1) {
panic("PageRange's End value must be 1 less than a multiple of 512")
}
if pr.End <= pr.Start {
panic("PageRange's End value must be after the start")
}
endOffset := strconv.FormatInt(int64(pr.End), 10) endOffset := strconv.FormatInt(int64(pr.End), 10)
asString := fmt.Sprintf("bytes=%v-%s", pr.Start, endOffset) asString := fmt.Sprintf("bytes=%v-%s", pr.Start, endOffset)
return &asString return &asString
} }
// PageBlobAccessConditions identifies page blob-specific access conditions which you optionally set.
type PageBlobAccessConditions struct { type PageBlobAccessConditions struct {
ModifiedAccessConditions
LeaseAccessConditions
SequenceNumberAccessConditions
}
// SequenceNumberAccessConditions identifies page blob-specific access conditions which you optionally set.
type SequenceNumberAccessConditions struct {
// IfSequenceNumberLessThan ensures that the page blob operation succeeds // IfSequenceNumberLessThan ensures that the page blob operation succeeds
// only if the blob's sequence number is less than a value. // only if the blob's sequence number is less than a value.
// IfSequenceNumberLessThan=0 means no 'IfSequenceNumberLessThan' header specified. // IfSequenceNumberLessThan=0 means no 'IfSequenceNumberLessThan' header specified.
@ -195,17 +177,7 @@ type PageBlobAccessConditions struct {
} }
// pointers is for internal infrastructure. It returns the fields as pointers. // pointers is for internal infrastructure. It returns the fields as pointers.
func (ac PageBlobAccessConditions) pointers() (snltoe *int64, snlt *int64, sne *int64) { func (ac SequenceNumberAccessConditions) pointers() (snltoe *int64, snlt *int64, sne *int64) {
if ac.IfSequenceNumberLessThan < -1 {
panic("Ifsequencenumberlessthan can't be less than -1")
}
if ac.IfSequenceNumberLessThanOrEqual < -1 {
panic("IfSequenceNumberLessThanOrEqual can't be less than -1")
}
if ac.IfSequenceNumberEqual < -1 {
panic("IfSequenceNumberEqual can't be less than -1")
}
var zero int64 // Defaults to 0 var zero int64 // Defaults to 0
switch ac.IfSequenceNumberLessThan { switch ac.IfSequenceNumberLessThan {
case -1: case -1:

View file

@ -23,9 +23,6 @@ type ServiceURL struct {
// NewServiceURL creates a ServiceURL object using the specified URL and request policy pipeline. // NewServiceURL creates a ServiceURL object using the specified URL and request policy pipeline.
func NewServiceURL(primaryURL url.URL, p pipeline.Pipeline) ServiceURL { func NewServiceURL(primaryURL url.URL, p pipeline.Pipeline) ServiceURL {
if p == nil {
panic("p can't be nil")
}
client := newServiceClient(primaryURL, p) client := newServiceClient(primaryURL, p)
return ServiceURL{client: client} return ServiceURL{client: client}
} }
@ -81,7 +78,7 @@ func appendToURLPath(u url.URL, name string) url.URL {
// After getting a segment, process it, and then call ListContainersFlatSegment again (passing the the // After getting a segment, process it, and then call ListContainersFlatSegment again (passing the the
// previously-returned Marker) to get the next segment. For more information, see // previously-returned Marker) to get the next segment. For more information, see
// https://docs.microsoft.com/rest/api/storageservices/list-containers2. // https://docs.microsoft.com/rest/api/storageservices/list-containers2.
func (s ServiceURL) ListContainersSegment(ctx context.Context, marker Marker, o ListContainersSegmentOptions) (*ListContainersResponse, error) { func (s ServiceURL) ListContainersSegment(ctx context.Context, marker Marker, o ListContainersSegmentOptions) (*ListContainersSegmentResponse, error) {
prefix, include, maxResults := o.pointers() prefix, include, maxResults := o.pointers()
return s.client.ListContainersSegment(ctx, prefix, marker.val, maxResults, include, nil, nil) return s.client.ListContainersSegment(ctx, prefix, marker.val, maxResults, include, nil, nil)
} }
@ -99,9 +96,6 @@ func (o *ListContainersSegmentOptions) pointers() (prefix *string, include ListC
prefix = &o.Prefix prefix = &o.Prefix
} }
if o.MaxResults != 0 { if o.MaxResults != 0 {
if o.MaxResults < 0 {
panic("MaxResults must be >= 0")
}
maxResults = &o.MaxResults maxResults = &o.MaxResults
} }
include = ListContainersIncludeType(o.Detail.string()) include = ListContainersIncludeType(o.Detail.string())

View file

@ -0,0 +1,3 @@
package azblob
const serviceLibVersion = "0.3"

View file

@ -6,6 +6,7 @@ import (
"crypto/hmac" "crypto/hmac"
"crypto/sha256" "crypto/sha256"
"encoding/base64" "encoding/base64"
"errors"
"net/http" "net/http"
"net/url" "net/url"
"sort" "sort"
@ -17,12 +18,12 @@ import (
// NewSharedKeyCredential creates an immutable SharedKeyCredential containing the // NewSharedKeyCredential creates an immutable SharedKeyCredential containing the
// storage account's name and either its primary or secondary key. // storage account's name and either its primary or secondary key.
func NewSharedKeyCredential(accountName, accountKey string) *SharedKeyCredential { func NewSharedKeyCredential(accountName, accountKey string) (*SharedKeyCredential, error) {
bytes, err := base64.StdEncoding.DecodeString(accountKey) bytes, err := base64.StdEncoding.DecodeString(accountKey)
if err != nil { if err != nil {
panic(err) return &SharedKeyCredential{}, err
} }
return &SharedKeyCredential{accountName: accountName, accountKey: bytes} return &SharedKeyCredential{accountName: accountName, accountKey: bytes}, nil
} }
// SharedKeyCredential contains an account's name and its primary or secondary key. // SharedKeyCredential contains an account's name and its primary or secondary key.
@ -45,7 +46,10 @@ func (f *SharedKeyCredential) New(next pipeline.Policy, po *pipeline.PolicyOptio
if d := request.Header.Get(headerXmsDate); d == "" { if d := request.Header.Get(headerXmsDate); d == "" {
request.Header[headerXmsDate] = []string{time.Now().UTC().Format(http.TimeFormat)} request.Header[headerXmsDate] = []string{time.Now().UTC().Format(http.TimeFormat)}
} }
stringToSign := f.buildStringToSign(request) stringToSign, err := f.buildStringToSign(request)
if err != nil {
return nil, err
}
signature := f.ComputeHMACSHA256(stringToSign) signature := f.ComputeHMACSHA256(stringToSign)
authHeader := strings.Join([]string{"SharedKey ", f.accountName, ":", signature}, "") authHeader := strings.Join([]string{"SharedKey ", f.accountName, ":", signature}, "")
request.Header[headerAuthorization] = []string{authHeader} request.Header[headerAuthorization] = []string{authHeader}
@ -90,7 +94,7 @@ func (f *SharedKeyCredential) ComputeHMACSHA256(message string) (base64String st
return base64.StdEncoding.EncodeToString(h.Sum(nil)) return base64.StdEncoding.EncodeToString(h.Sum(nil))
} }
func (f *SharedKeyCredential) buildStringToSign(request pipeline.Request) string { func (f *SharedKeyCredential) buildStringToSign(request pipeline.Request) (string, error) {
// https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services // https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
headers := request.Header headers := request.Header
contentLength := headers.Get(headerContentLength) contentLength := headers.Get(headerContentLength)
@ -98,6 +102,11 @@ func (f *SharedKeyCredential) buildStringToSign(request pipeline.Request) string
contentLength = "" contentLength = ""
} }
canonicalizedResource, err := f.buildCanonicalizedResource(request.URL)
if err != nil {
return "", err
}
stringToSign := strings.Join([]string{ stringToSign := strings.Join([]string{
request.Method, request.Method,
headers.Get(headerContentEncoding), headers.Get(headerContentEncoding),
@ -112,9 +121,9 @@ func (f *SharedKeyCredential) buildStringToSign(request pipeline.Request) string
headers.Get(headerIfUnmodifiedSince), headers.Get(headerIfUnmodifiedSince),
headers.Get(headerRange), headers.Get(headerRange),
buildCanonicalizedHeader(headers), buildCanonicalizedHeader(headers),
f.buildCanonicalizedResource(request.URL), canonicalizedResource,
}, "\n") }, "\n")
return stringToSign return stringToSign, nil
} }
func buildCanonicalizedHeader(headers http.Header) string { func buildCanonicalizedHeader(headers http.Header) string {
@ -146,7 +155,7 @@ func buildCanonicalizedHeader(headers http.Header) string {
return string(ch.Bytes()) return string(ch.Bytes())
} }
func (f *SharedKeyCredential) buildCanonicalizedResource(u *url.URL) string { func (f *SharedKeyCredential) buildCanonicalizedResource(u *url.URL) (string, error) {
// https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services // https://docs.microsoft.com/en-us/rest/api/storageservices/authentication-for-the-azure-storage-services
cr := bytes.NewBufferString("/") cr := bytes.NewBufferString("/")
cr.WriteString(f.accountName) cr.WriteString(f.accountName)
@ -164,7 +173,7 @@ func (f *SharedKeyCredential) buildCanonicalizedResource(u *url.URL) string {
// params is a map[string][]string; param name is key; params values is []string // params is a map[string][]string; param name is key; params values is []string
params, err := url.ParseQuery(u.RawQuery) // Returns URL decoded values params, err := url.ParseQuery(u.RawQuery) // Returns URL decoded values
if err != nil { if err != nil {
panic(err) return "", errors.New("parsing query parameters must succeed, otherwise there might be serious problems in the SDK/generated code")
} }
if len(params) > 0 { // There is at least 1 query parameter if len(params) > 0 { // There is at least 1 query parameter
@ -183,5 +192,5 @@ func (f *SharedKeyCredential) buildCanonicalizedResource(u *url.URL) string {
cr.WriteString("\n" + paramName + ":" + strings.Join(paramValues, ",")) cr.WriteString("\n" + paramName + ":" + strings.Join(paramValues, ","))
} }
} }
return string(cr.Bytes()) return string(cr.Bytes()), nil
} }

View file

@ -2,6 +2,7 @@ package azblob
import ( import (
"context" "context"
"errors"
"sync/atomic" "sync/atomic"
"runtime" "runtime"
@ -11,6 +12,10 @@ import (
"github.com/Azure/azure-pipeline-go/pipeline" "github.com/Azure/azure-pipeline-go/pipeline"
) )
// TokenRefresher represents a callback method that you write; this method is called periodically
// so you can refresh the token credential's value.
type TokenRefresher func(credential TokenCredential) time.Duration
// TokenCredential represents a token credential (which is also a pipeline.Factory). // TokenCredential represents a token credential (which is also a pipeline.Factory).
type TokenCredential interface { type TokenCredential interface {
Credential Credential
@ -20,12 +25,15 @@ type TokenCredential interface {
// NewTokenCredential creates a token credential for use with role-based access control (RBAC) access to Azure Storage // NewTokenCredential creates a token credential for use with role-based access control (RBAC) access to Azure Storage
// resources. You initialize the TokenCredential with an initial token value. If you pass a non-nil value for // resources. You initialize the TokenCredential with an initial token value. If you pass a non-nil value for
// tokenRefresher, then the function you pass will be called immediately (so it can refresh and change the // tokenRefresher, then the function you pass will be called immediately so it can refresh and change the
// TokenCredential's token value by calling SetToken; your tokenRefresher function must return a time.Duration // TokenCredential's token value by calling SetToken. Your tokenRefresher function must return a time.Duration
// indicating how long the TokenCredential object should wait before calling your tokenRefresher function again. // indicating how long the TokenCredential object should wait before calling your tokenRefresher function again.
func NewTokenCredential(initialToken string, tokenRefresher func(credential TokenCredential) time.Duration) TokenCredential { // If your tokenRefresher callback fails to refresh the token, you can return a duration of 0 to stop your
// TokenCredential object from ever invoking tokenRefresher again. Also, oen way to deal with failing to refresh a
// token is to cancel a context.Context object used by requests that have the TokenCredential object in their pipeline.
func NewTokenCredential(initialToken string, tokenRefresher TokenRefresher) TokenCredential {
tc := &tokenCredential{} tc := &tokenCredential{}
tc.SetToken(initialToken) // We dont' set it above to guarantee atomicity tc.SetToken(initialToken) // We don't set it above to guarantee atomicity
if tokenRefresher == nil { if tokenRefresher == nil {
return tc // If no callback specified, return the simple tokenCredential return tc // If no callback specified, return the simple tokenCredential
} }
@ -68,7 +76,7 @@ type tokenCredential struct {
// The members below are only used if the user specified a tokenRefresher callback function. // The members below are only used if the user specified a tokenRefresher callback function.
timer *time.Timer timer *time.Timer
tokenRefresher func(c TokenCredential) time.Duration tokenRefresher TokenRefresher
lock sync.Mutex lock sync.Mutex
stopped bool stopped bool
} }
@ -84,7 +92,7 @@ func (f *tokenCredential) SetToken(token string) { f.token.Store(token) }
// startRefresh calls refresh which immediately calls tokenRefresher // startRefresh calls refresh which immediately calls tokenRefresher
// and then starts a timer to call tokenRefresher in the future. // and then starts a timer to call tokenRefresher in the future.
func (f *tokenCredential) startRefresh(tokenRefresher func(c TokenCredential) time.Duration) { func (f *tokenCredential) startRefresh(tokenRefresher TokenRefresher) {
f.tokenRefresher = tokenRefresher f.tokenRefresher = tokenRefresher
f.stopped = false // In case user calls StartRefresh, StopRefresh, & then StartRefresh again f.stopped = false // In case user calls StartRefresh, StopRefresh, & then StartRefresh again
f.refresh() f.refresh()
@ -95,12 +103,14 @@ func (f *tokenCredential) startRefresh(tokenRefresher func(c TokenCredential) ti
// in order to refresh the token again in the future. // in order to refresh the token again in the future.
func (f *tokenCredential) refresh() { func (f *tokenCredential) refresh() {
d := f.tokenRefresher(f) // Invoke the user's refresh callback outside of the lock d := f.tokenRefresher(f) // Invoke the user's refresh callback outside of the lock
if d > 0 { // If duration is 0 or negative, refresher wants to not be called again
f.lock.Lock() f.lock.Lock()
if !f.stopped { if !f.stopped {
f.timer = time.AfterFunc(d, f.refresh) f.timer = time.AfterFunc(d, f.refresh)
} }
f.lock.Unlock() f.lock.Unlock()
} }
}
// stopRefresh stops any pending timer and sets stopped field to true to prevent // stopRefresh stops any pending timer and sets stopped field to true to prevent
// any new timer from starting. // any new timer from starting.
@ -118,7 +128,8 @@ func (f *tokenCredential) stopRefresh() {
func (f *tokenCredential) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy { func (f *tokenCredential) New(next pipeline.Policy, po *pipeline.PolicyOptions) pipeline.Policy {
return pipeline.PolicyFunc(func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) { return pipeline.PolicyFunc(func(ctx context.Context, request pipeline.Request) (pipeline.Response, error) {
if request.URL.Scheme != "https" { if request.URL.Scheme != "https" {
panic("Token credentials require a URL using the https protocol scheme.") // HTTPS must be used, otherwise the tokens are at the risk of being exposed
return nil, errors.New("token credentials require a URL using the https protocol scheme")
} }
request.Header[headerAuthorization] = []string{"Bearer " + f.Token()} request.Header[headerAuthorization] = []string{"Bearer " + f.Token()}
return next.Do(ctx, request) return next.Do(ctx, request)

View file

@ -1,4 +1,4 @@
// +build linux darwin freebsd // +build linux darwin freebsd openbsd netbsd
package azblob package azblob
@ -22,6 +22,6 @@ func (m *mmf) unmap() {
err := syscall.Munmap(*m) err := syscall.Munmap(*m)
*m = nil *m = nil
if err != nil { if err != nil {
panic(err) panic("if we are unable to unmap the memory-mapped file, there is serious concern for memory corruption")
} }
} }

View file

@ -33,6 +33,6 @@ func (m *mmf) unmap() {
*m = mmf{} *m = mmf{}
err := syscall.UnmapViewOfFile(addr) err := syscall.UnmapViewOfFile(addr)
if err != nil { if err != nil {
panic(err) panic("if we are unable to unmap the memory-mapped file, there is serious concern for memory corruption")
} }
} }

View file

@ -21,10 +21,6 @@ type PipelineOptions struct {
// NewPipeline creates a Pipeline using the specified credentials and options. // NewPipeline creates a Pipeline using the specified credentials and options.
func NewPipeline(c Credential, o PipelineOptions) pipeline.Pipeline { func NewPipeline(c Credential, o PipelineOptions) pipeline.Pipeline {
if c == nil {
panic("c can't be nil")
}
// Closest to API goes first; closest to the wire goes last // Closest to API goes first; closest to the wire goes last
f := []pipeline.Factory{ f := []pipeline.Factory{
NewTelemetryPolicyFactory(o.Telemetry), NewTelemetryPolicyFactory(o.Telemetry),

View file

@ -109,6 +109,7 @@ func NewRequestLogPolicyFactory(o RequestLogOptions) pipeline.Factory {
}) })
} }
// redactSigQueryParam redacts the 'sig' query parameter in URL's raw query to protect secret.
func redactSigQueryParam(rawQuery string) (bool, string) { func redactSigQueryParam(rawQuery string) (bool, string) {
rawQuery = strings.ToLower(rawQuery) // lowercase the string so we can look for ?sig= and &sig= rawQuery = strings.ToLower(rawQuery) // lowercase the string so we can look for ?sig= and &sig=
sigFound := strings.Contains(rawQuery, "?sig=") sigFound := strings.Contains(rawQuery, "?sig=")
@ -135,7 +136,8 @@ func prepareRequestForLogging(request pipeline.Request) *http.Request {
req = request.Copy() req = request.Copy()
req.Request.URL.RawQuery = rawQuery req.Request.URL.RawQuery = rawQuery
} }
return req.Request
return prepareRequestForServiceLogging(req)
} }
func stack() []byte { func stack() []byte {
@ -148,3 +150,33 @@ func stack() []byte {
buf = make([]byte, 2*len(buf)) buf = make([]byte, 2*len(buf))
} }
} }
///////////////////////////////////////////////////////////////////////////////////////
// Redact phase useful for blob and file service only. For other services,
// this method can directly return request.Request.
///////////////////////////////////////////////////////////////////////////////////////
func prepareRequestForServiceLogging(request pipeline.Request) *http.Request {
req := request
if exist, key := doesHeaderExistCaseInsensitive(req.Header, xMsCopySourceHeader); exist {
req = request.Copy()
url, err := url.Parse(req.Header.Get(key))
if err == nil {
if sigFound, rawQuery := redactSigQueryParam(url.RawQuery); sigFound {
url.RawQuery = rawQuery
req.Header.Set(xMsCopySourceHeader, url.String())
}
}
}
return req.Request
}
const xMsCopySourceHeader = "x-ms-copy-source"
func doesHeaderExistCaseInsensitive(header http.Header, key string) (bool, string) {
for keyInHeader := range header {
if strings.EqualFold(keyInHeader, key) {
return true, keyInHeader
}
}
return false, ""
}

View file

@ -2,15 +2,17 @@ package azblob
import ( import (
"context" "context"
"errors"
"io"
"io/ioutil"
"math/rand" "math/rand"
"net" "net"
"net/http" "net/http"
"strconv" "strconv"
"strings"
"time" "time"
"github.com/Azure/azure-pipeline-go/pipeline" "github.com/Azure/azure-pipeline-go/pipeline"
"io/ioutil"
"io"
) )
// RetryPolicy tells the pipeline what kind of retry policy to use. See the RetryPolicy* constants. // RetryPolicy tells the pipeline what kind of retry policy to use. See the RetryPolicy* constants.
@ -66,21 +68,12 @@ func (o RetryOptions) retryReadsFromSecondaryHost() string {
} }
func (o RetryOptions) defaults() RetryOptions { func (o RetryOptions) defaults() RetryOptions {
if o.Policy != RetryPolicyExponential && o.Policy != RetryPolicyFixed { // We assume the following:
panic("RetryPolicy must be RetryPolicyExponential or RetryPolicyFixed") // 1. o.Policy should either be RetryPolicyExponential or RetryPolicyFixed
} // 2. o.MaxTries >= 0
if o.MaxTries < 0 { // 3. o.TryTimeout, o.RetryDelay, and o.MaxRetryDelay >=0
panic("MaxTries must be >= 0") // 4. o.RetryDelay <= o.MaxRetryDelay
} // 5. Both o.RetryDelay and o.MaxRetryDelay must be 0 or neither can be 0
if o.TryTimeout < 0 || o.RetryDelay < 0 || o.MaxRetryDelay < 0 {
panic("TryTimeout, RetryDelay, and MaxRetryDelay must all be >= 0")
}
if o.RetryDelay > o.MaxRetryDelay {
panic("RetryDelay must be <= MaxRetryDelay")
}
if (o.RetryDelay == 0 && o.MaxRetryDelay != 0) || (o.RetryDelay != 0 && o.MaxRetryDelay == 0) {
panic("Both RetryDelay and MaxRetryDelay must be 0 or neither can be 0")
}
IfDefault := func(current *time.Duration, desired time.Duration) { IfDefault := func(current *time.Duration, desired time.Duration) {
if *current == time.Duration(0) { if *current == time.Duration(0) {
@ -175,9 +168,11 @@ func NewRetryPolicyFactory(o RetryOptions) pipeline.Factory {
// For each try, seek to the beginning of the Body stream. We do this even for the 1st try because // For each try, seek to the beginning of the Body stream. We do this even for the 1st try because
// the stream may not be at offset 0 when we first get it and we want the same behavior for the // the stream may not be at offset 0 when we first get it and we want the same behavior for the
// 1st try as for additional tries. // 1st try as for additional tries.
if err = requestCopy.RewindBody(); err != nil { err = requestCopy.RewindBody()
panic(err) if err != nil {
return nil, errors.New("we must be able to seek on the Body Stream, otherwise retries would cause data corruption")
} }
if !tryingPrimary { if !tryingPrimary {
requestCopy.Request.URL.Host = o.retryReadsFromSecondaryHost() requestCopy.Request.URL.Host = o.retryReadsFromSecondaryHost()
} }
@ -221,9 +216,27 @@ func NewRetryPolicyFactory(o RetryOptions) pipeline.Factory {
considerSecondary = false considerSecondary = false
action = "Retry: Secondary URL returned 404" action = "Retry: Secondary URL returned 404"
case err != nil: case err != nil:
// NOTE: Protocol Responder returns non-nil if REST API returns invalid status code for the invoked operation // NOTE: Protocol Responder returns non-nil if REST API returns invalid status code for the invoked operation.
if netErr, ok := err.(net.Error); ok && (netErr.Temporary() || netErr.Timeout()) { // Use ServiceCode to verify if the error is related to storage service-side,
action = "Retry: net.Error and Temporary() or Timeout()" // ServiceCode is set only when error related to storage service happened.
if stErr, ok := err.(StorageError); ok {
if stErr.Temporary() {
action = "Retry: StorageError with error service code and Temporary()"
} else if stErr.Response() != nil && isSuccessStatusCode(stErr.Response()) { // TODO: This is a temporarily work around, remove this after protocol layer fix the issue that net.Error is wrapped as storageError
action = "Retry: StorageError with success status code"
} else {
action = "NoRetry: StorageError not Temporary() and without retriable status code"
}
} else if netErr, ok := err.(net.Error); ok {
// Use non-retriable net.Error list, but not retriable list.
// As there are errors without Temporary() implementation,
// while need be retried, like 'connection reset by peer', 'transport connection broken' and etc.
// So the SDK do retry for most of the case, unless the error should not be retried for sure.
if !isNotRetriable(netErr) {
action = "Retry: net.Error and not in the non-retriable list"
} else {
action = "NoRetry: net.Error and in the non-retriable list"
}
} else { } else {
action = "NoRetry: unrecognized error" action = "NoRetry: unrecognized error"
} }
@ -237,11 +250,17 @@ func NewRetryPolicyFactory(o RetryOptions) pipeline.Factory {
if err != nil { if err != nil {
tryCancel() // If we're returning an error, cancel this current/last per-retry timeout context tryCancel() // If we're returning an error, cancel this current/last per-retry timeout context
} else { } else {
// TODO: Right now, we've decided to leak the per-try Context until the user's Context is canceled. // We wrap the last per-try context in a body and overwrite the Response's Body field with our wrapper.
// Another option is that we wrap the last per-try context in a body and overwrite the Response's Body field with our wrapper.
// So, when the user closes the Body, the our per-try context gets closed too. // So, when the user closes the Body, the our per-try context gets closed too.
// Another option, is that the Last Policy do this wrapping for a per-retry context (not for the user's context) // Another option, is that the Last Policy do this wrapping for a per-retry context (not for the user's context)
_ = tryCancel // So, for now, we don't call cancel: cancel() if response == nil || response.Response() == nil {
// We do panic in the case response or response.Response() is nil,
// as for client, the response should not be nil if request is sent and the operations is executed successfully.
// Another option, is that execute the cancel function when response or response.Response() is nil,
// as in this case, current per-try has nothing to do in future.
return nil, errors.New("invalid state, response should not be nil when the operation is executed successfully")
}
response.Response().Body = &contextCancelReadCloser{cf: tryCancel, body: response.Response().Body}
} }
break // Don't retry break // Don't retry
} }
@ -259,6 +278,78 @@ func NewRetryPolicyFactory(o RetryOptions) pipeline.Factory {
}) })
} }
// contextCancelReadCloser helps to invoke context's cancelFunc properly when the ReadCloser is closed.
type contextCancelReadCloser struct {
cf context.CancelFunc
body io.ReadCloser
}
func (rc *contextCancelReadCloser) Read(p []byte) (n int, err error) {
return rc.body.Read(p)
}
func (rc *contextCancelReadCloser) Close() error {
err := rc.body.Close()
if rc.cf != nil {
rc.cf()
}
return err
}
// isNotRetriable checks if the provided net.Error isn't retriable.
func isNotRetriable(errToParse net.Error) bool {
// No error, so this is NOT retriable.
if errToParse == nil {
return true
}
// The error is either temporary or a timeout so it IS retriable (not not retriable).
if errToParse.Temporary() || errToParse.Timeout() {
return false
}
genericErr := error(errToParse)
// From here all the error are neither Temporary() nor Timeout().
switch err := errToParse.(type) {
case *net.OpError:
// The net.Error is also a net.OpError but the inner error is nil, so this is not retriable.
if err.Err == nil {
return true
}
genericErr = err.Err
}
switch genericErr.(type) {
case *net.AddrError, net.UnknownNetworkError, *net.DNSError, net.InvalidAddrError, *net.ParseError, *net.DNSConfigError:
// If the error is one of the ones listed, then it is NOT retriable.
return true
}
// If it's invalid header field name/value error thrown by http module, then it is NOT retriable.
// This could happen when metadata's key or value is invalid. (RoundTrip in transport.go)
if strings.Contains(genericErr.Error(), "invalid header field") {
return true
}
// Assume the error is retriable.
return false
}
var successStatusCodes = []int{http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNoContent, http.StatusPartialContent}
func isSuccessStatusCode(resp *http.Response) bool {
if resp == nil {
return false
}
for _, i := range successStatusCodes {
if i == resp.StatusCode {
return true
}
}
return false
}
// According to https://github.com/golang/go/wiki/CompilerOptimizations, the compiler will inline this method and hopefully optimize all calls to it away // According to https://github.com/golang/go/wiki/CompilerOptimizations, the compiler will inline this method and hopefully optimize all calls to it away
var logf = func(format string, a ...interface{}) {} var logf = func(format string, a ...interface{}) {}

View file

@ -55,15 +55,6 @@ type retryReader struct {
// NewRetryReader creates a retry reader. // NewRetryReader creates a retry reader.
func NewRetryReader(ctx context.Context, initialResponse *http.Response, func NewRetryReader(ctx context.Context, initialResponse *http.Response,
info HTTPGetterInfo, o RetryReaderOptions, getter HTTPGetter) io.ReadCloser { info HTTPGetterInfo, o RetryReaderOptions, getter HTTPGetter) io.ReadCloser {
if getter == nil {
panic("getter must not be nil")
}
if info.Count < 0 {
panic("info.Count must be >= 0")
}
if o.MaxRetryRequests < 0 {
panic("o.MaxRetryRequests must be >= 0")
}
return &retryReader{ctx: ctx, getter: getter, info: info, countWasBounded: info.Count != CountToEnd, response: initialResponse, o: o} return &retryReader{ctx: ctx, getter: getter, info: info, countWasBounded: info.Count != CountToEnd, response: initialResponse, o: o}
} }
@ -106,7 +97,7 @@ func (s *retryReader) Read(p []byte) (n int, err error) {
return n, err // All retries exhausted return n, err // All retries exhausted
} }
if netErr, ok := err.(net.Error); ok && (netErr.Timeout() || netErr.Temporary()) { if _, ok := err.(net.Error); ok {
continue continue
// Loop around and try to get and read from new stream. // Loop around and try to get and read from new stream.
} }

View file

@ -2,6 +2,7 @@ package azblob
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@ -22,17 +23,17 @@ type AccountSASSignatureValues struct {
// NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce // NewSASQueryParameters uses an account's shared key credential to sign this signature values to produce
// the proper SAS query parameters. // the proper SAS query parameters.
func (v AccountSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) SASQueryParameters { func (v AccountSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *SharedKeyCredential) (SASQueryParameters, error) {
// https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-an-Account-SAS // https://docs.microsoft.com/en-us/rest/api/storageservices/Constructing-an-Account-SAS
if v.ExpiryTime.IsZero() || v.Permissions == "" || v.ResourceTypes == "" || v.Services == "" { if v.ExpiryTime.IsZero() || v.Permissions == "" || v.ResourceTypes == "" || v.Services == "" {
panic("Account SAS is missing at least one of these: ExpiryTime, Permissions, Service, or ResourceType") return SASQueryParameters{}, errors.New("account SAS is missing at least one of these: ExpiryTime, Permissions, Service, or ResourceType")
} }
if v.Version == "" { if v.Version == "" {
v.Version = SASVersion v.Version = SASVersion
} }
perms := &AccountSASPermissions{} perms := &AccountSASPermissions{}
if err := perms.Parse(v.Permissions); err != nil { if err := perms.Parse(v.Permissions); err != nil {
panic(err) return SASQueryParameters{}, err
} }
v.Permissions = perms.String() v.Permissions = perms.String()
@ -68,7 +69,7 @@ func (v AccountSASSignatureValues) NewSASQueryParameters(sharedKeyCredential *Sh
// Calculated SAS signature // Calculated SAS signature
signature: signature, signature: signature,
} }
return p return p, nil
} }
// The AccountSASPermissions type simplifies creating the permissions string for an Azure Storage Account SAS. // The AccountSASPermissions type simplifies creating the permissions string for an Azure Storage Account SAS.
@ -205,7 +206,7 @@ func (rt *AccountSASResourceTypes) Parse(s string) error {
switch r { switch r {
case 's': case 's':
rt.Service = true rt.Service = true
case 'q': case 'c':
rt.Container = true rt.Container = true
case 'o': case 'o':
rt.Object = true rt.Object = true

View file

@ -43,11 +43,14 @@ func newStorageError(cause error, response *http.Response, description string) e
response: response, response: response,
description: description, description: description,
}, },
serviceCode: ServiceCodeType(response.Header.Get("x-ms-error-code")),
} }
} }
// ServiceCode returns service-error information. The caller may examine these values but should not modify any of them. // ServiceCode returns service-error information. The caller may examine these values but should not modify any of them.
func (e *storageError) ServiceCode() ServiceCodeType { return e.serviceCode } func (e *storageError) ServiceCode() ServiceCodeType {
return e.serviceCode
}
// Error implements the error interface's Error method to return a string representation of the error. // Error implements the error interface's Error method to return a string representation of the error.
func (e *storageError) Error() string { func (e *storageError) Error() string {
@ -94,8 +97,6 @@ func (e *storageError) UnmarshalXML(d *xml.Decoder, start xml.StartElement) (err
break break
case xml.CharData: case xml.CharData:
switch tokName { switch tokName {
case "Code":
e.serviceCode = ServiceCodeType(tt)
case "Message": case "Message":
e.description = string(tt) e.description = string(tt)
default: default:

View file

@ -16,16 +16,10 @@ type httpRange struct {
} }
func (r httpRange) pointers() *string { func (r httpRange) pointers() *string {
if r.offset == 0 && r.count == 0 { // Do common case first for performance if r.offset == 0 && r.count == CountToEnd { // Do common case first for performance
return nil // No specified range return nil // No specified range
} }
if r.offset < 0 { endOffset := "" // if count == CountToEnd (0)
panic("The range offset must be >= 0")
}
if r.count < 0 {
panic("The range count must be >= 0")
}
endOffset := "" // if count == 0
if r.count > 0 { if r.count > 0 {
endOffset = strconv.FormatInt((r.offset+r.count)-1, 10) endOffset = strconv.FormatInt((r.offset+r.count)-1, 10)
} }
@ -35,27 +29,36 @@ func (r httpRange) pointers() *string {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
func validateSeekableStreamAt0AndGetCount(body io.ReadSeeker) int64 { func validateSeekableStreamAt0AndGetCount(body io.ReadSeeker) (int64, error) {
if body == nil { // nil body's are "logically" seekable to 0 and are 0 bytes long if body == nil { // nil body's are "logically" seekable to 0 and are 0 bytes long
return 0 return 0, nil
}
validateSeekableStreamAt0(body)
count, err := body.Seek(0, io.SeekEnd)
if err != nil {
panic("failed to seek stream")
}
body.Seek(0, io.SeekStart)
return count
} }
func validateSeekableStreamAt0(body io.ReadSeeker) { err := validateSeekableStreamAt0(body)
if err != nil {
return 0, err
}
count, err := body.Seek(0, io.SeekEnd)
if err != nil {
return 0, errors.New("body stream must be seekable")
}
body.Seek(0, io.SeekStart)
return count, nil
}
// return an error if body is not a valid seekable stream at 0
func validateSeekableStreamAt0(body io.ReadSeeker) error {
if body == nil { // nil body's are "logically" seekable to 0 if body == nil { // nil body's are "logically" seekable to 0
return return nil
} }
if pos, err := body.Seek(0, io.SeekCurrent); pos != 0 || err != nil { if pos, err := body.Seek(0, io.SeekCurrent); pos != 0 || err != nil {
// Help detect programmer error
if err != nil { if err != nil {
panic(err) return errors.New("body stream must be seekable")
} }
panic(errors.New("stream must be set to position 0")) return errors.New("body stream must be set to position 0")
} }
return nil
} }

View file

@ -21,10 +21,7 @@ type uuid [16]byte
func newUUID() (u uuid) { func newUUID() (u uuid) {
u = uuid{} u = uuid{}
// Set all bits to randomly (or pseudo-randomly) chosen values. // Set all bits to randomly (or pseudo-randomly) chosen values.
_, err := rand.Read(u[:]) rand.Read(u[:])
if err != nil {
panic("ran.Read failed")
}
u[8] = (u[8] | reservedRFC4122) & 0x7F // u.setVariant(ReservedRFC4122) u[8] = (u[8] | reservedRFC4122) & 0x7F // u.setVariant(ReservedRFC4122)
var version byte = 4 var version byte = 4

View file

@ -33,20 +33,21 @@ func newAppendBlobClient(url url.URL, p pipeline.Pipeline) appendBlobClient {
// error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more // error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more
// information, see <a // information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> transactionalContentMD5 is specify the transactional md5 for the body, to
// lease is active and matches this ID. maxSize is optional conditional header. The max length in bytes permitted for // be validated by the service. leaseID is if specified, the operation only succeeds if the resource's lease is active
// the append blob. If the Append Block operation would cause the blob to exceed that limit or if the blob size is // and matches this ID. maxSize is optional conditional header. The max length in bytes permitted for the append blob.
// already greater than the value specified in this header, the request will fail with MaxBlobSizeConditionNotMet error // If the Append Block operation would cause the blob to exceed that limit or if the blob size is already greater than
// (HTTP status code 412 - Precondition Failed). appendPosition is optional conditional header, used only for the // the value specified in this header, the request will fail with MaxBlobSizeConditionNotMet error (HTTP status code
// Append Block operation. A number indicating the byte offset to compare. Append Block will succeed only if the append // 412 - Precondition Failed). appendPosition is optional conditional header, used only for the Append Block operation.
// position is equal to this number. If it is not, the request will fail with the AppendPositionConditionNotMet error // A number indicating the byte offset to compare. Append Block will succeed only if the append position is equal to
// (HTTP status code 412 - Precondition Failed). ifModifiedSince is specify this header value to operate only on a blob // this number. If it is not, the request will fail with the AppendPositionConditionNotMet error (HTTP status code 412
// if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate // - Precondition Failed). ifModifiedSince is specify this header value to operate only on a blob if it has been
// only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to // modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if
// operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a // it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs
// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded // with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
// in the analytics logs when storage analytics logging is enabled. // requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobAppendBlockResponse, error) { // logs when storage analytics logging is enabled.
func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobAppendBlockResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: body, {targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
@ -55,7 +56,7 @@ func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeek
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.appendBlockPreparer(body, contentLength, timeout, leaseID, maxSize, appendPosition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.appendBlockPreparer(body, contentLength, timeout, transactionalContentMD5, leaseID, maxSize, appendPosition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -67,7 +68,7 @@ func (client appendBlobClient) AppendBlock(ctx context.Context, body io.ReadSeek
} }
// appendBlockPreparer prepares the AppendBlock request. // appendBlockPreparer prepares the AppendBlock request.
func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, transactionalContentMD5 []byte, leaseID *string, maxSize *int64, appendPosition *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, body) req, err := pipeline.NewRequest("PUT", client.url, body)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -79,6 +80,9 @@ func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLe
params.Set("comp", "appendblock") params.Set("comp", "appendblock")
req.URL.RawQuery = params.Encode() req.URL.RawQuery = params.Encode()
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
}
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
@ -94,8 +98,8 @@ func (client appendBlobClient) appendBlockPreparer(body io.ReadSeeker, contentLe
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -135,25 +139,22 @@ func (client appendBlobClient) appendBlockResponder(resp pipeline.Response) (pip
// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified // destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified
// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, // metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19,
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and // metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and
// Metadata for more information. leaseID is if specified, the operation only succeeds if the container's lease is // Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. // active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header.
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified
// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. // since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value.
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a // ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled. // analytics logging is enabled.
func (client appendBlobClient) Create(ctx context.Context, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobCreateResponse, error) { func (client appendBlobClient) Create(ctx context.Context, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*AppendBlobCreateResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.createPreparer(contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.createPreparer(contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -165,7 +166,7 @@ func (client appendBlobClient) Create(ctx context.Context, contentLength int64,
} }
// createPreparer prepares the Create request. // createPreparer prepares the Create request.
func (client appendBlobClient) createPreparer(contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client appendBlobClient) createPreparer(contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -208,8 +209,8 @@ func (client appendBlobClient) createPreparer(contentLength int64, timeout *int3
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))

View file

@ -32,7 +32,7 @@ func newBlobClient(url url.URL, p pipeline.Pipeline) blobClient {
// copyID is the copy identifier provided in the x-ms-copy-id header of the original Copy Blob operation. timeout is // copyID is the copy identifier provided in the x-ms-copy-id header of the original Copy Blob operation. timeout is
// the timeout parameter is expressed in seconds. For more information, see <a // the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character // lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled. // limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client blobClient) AbortCopyFromURL(ctx context.Context, copyID string, timeout *int32, leaseID *string, requestID *string) (*BlobAbortCopyFromURLResponse, error) { func (client blobClient) AbortCopyFromURL(ctx context.Context, copyID string, timeout *int32, leaseID *string, requestID *string) (*BlobAbortCopyFromURLResponse, error) {
@ -99,18 +99,18 @@ func (client blobClient) abortCopyFromURLResponder(resp pipeline.Response) (pipe
// service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor // service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid Constructor
// (String) for a list of valid GUID string formats. ifModifiedSince is specify this header value to operate only on a // (String) for a list of valid GUID string formats. ifModifiedSince is specify this header value to operate only on a
// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to // blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to
// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value // operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs // to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is // without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is
// recorded in the analytics logs when storage analytics logging is enabled. // recorded in the analytics logs when storage analytics logging is enabled.
func (client blobClient) AcquireLease(ctx context.Context, timeout *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobAcquireLeaseResponse, error) { func (client blobClient) AcquireLease(ctx context.Context, timeout *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlobAcquireLeaseResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.acquireLeasePreparer(timeout, duration, proposedLeaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.acquireLeasePreparer(timeout, duration, proposedLeaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -122,7 +122,7 @@ func (client blobClient) AcquireLease(ctx context.Context, timeout *int32, durat
} }
// acquireLeasePreparer prepares the AcquireLease request. // acquireLeasePreparer prepares the AcquireLease request.
func (client blobClient) acquireLeasePreparer(timeout *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) acquireLeasePreparer(timeout *int32, duration *int32, proposedLeaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -145,8 +145,8 @@ func (client blobClient) acquireLeasePreparer(timeout *int32, duration *int32, p
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -182,18 +182,18 @@ func (client blobClient) acquireLeaseResponder(resp pipeline.Response) (pipeline
// not appear with a break operation, a fixed-duration lease breaks after the remaining lease period elapses, and an // not appear with a break operation, a fixed-duration lease breaks after the remaining lease period elapses, and an
// infinite lease breaks immediately. ifModifiedSince is specify this header value to operate only on a blob if it has // infinite lease breaks immediately. ifModifiedSince is specify this header value to operate only on a blob if it has
// been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a // been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only // blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on
// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching // blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the // requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
// analytics logs when storage analytics logging is enabled. // logs when storage analytics logging is enabled.
func (client blobClient) BreakLease(ctx context.Context, timeout *int32, breakPeriod *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobBreakLeaseResponse, error) { func (client blobClient) BreakLease(ctx context.Context, timeout *int32, breakPeriod *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlobBreakLeaseResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.breakLeasePreparer(timeout, breakPeriod, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.breakLeasePreparer(timeout, breakPeriod, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -205,7 +205,7 @@ func (client blobClient) BreakLease(ctx context.Context, timeout *int32, breakPe
} }
// breakLeasePreparer prepares the BreakLease request. // breakLeasePreparer prepares the BreakLease request.
func (client blobClient) breakLeasePreparer(timeout *int32, breakPeriod *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) breakLeasePreparer(timeout *int32, breakPeriod *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -225,8 +225,8 @@ func (client blobClient) breakLeasePreparer(timeout *int32, breakPeriod *int32,
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -253,25 +253,25 @@ func (client blobClient) breakLeaseResponder(resp pipeline.Response) (pipeline.R
// ChangeLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete // ChangeLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete
// operations // operations
// //
// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. // leaseID is specifies the current lease ID on the resource. proposedLeaseID is proposed lease ID, in a GUID string
// proposedLeaseID is proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the // format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See
// proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string // Guid Constructor (String) for a list of valid GUID string formats. timeout is the timeout parameter is expressed in
// formats. timeout is the timeout parameter is expressed in seconds. For more information, see <a // seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if // Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only // it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
// on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate // on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate
// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a // only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a
// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded // matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded
// in the analytics logs when storage analytics logging is enabled. // in the analytics logs when storage analytics logging is enabled.
func (client blobClient) ChangeLease(ctx context.Context, leaseID string, proposedLeaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobChangeLeaseResponse, error) { func (client blobClient) ChangeLease(ctx context.Context, leaseID string, proposedLeaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlobChangeLeaseResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.changeLeasePreparer(leaseID, proposedLeaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.changeLeasePreparer(leaseID, proposedLeaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -283,7 +283,7 @@ func (client blobClient) ChangeLease(ctx context.Context, leaseID string, propos
} }
// changeLeasePreparer prepares the ChangeLease request. // changeLeasePreparer prepares the ChangeLease request.
func (client blobClient) changeLeasePreparer(leaseID string, proposedLeaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) changeLeasePreparer(leaseID string, proposedLeaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -302,8 +302,8 @@ func (client blobClient) changeLeasePreparer(leaseID string, proposedLeaseID str
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -338,22 +338,19 @@ func (client blobClient) changeLeaseResponder(resp pipeline.Response) (pipeline.
// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing // 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing
// Containers, Blobs, and Metadata for more information. ifModifiedSince is specify this header value to operate only // Containers, Blobs, and Metadata for more information. ifModifiedSince is specify this header value to operate only
// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to // on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to
// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value // operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs // to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. leaseID is if specified, the operation only succeeds if the container's lease is active // without a matching value. leaseID is if specified, the operation only succeeds if the resource's lease is active and
// and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character limit that is // matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded
// recorded in the analytics logs when storage analytics logging is enabled. // in the analytics logs when storage analytics logging is enabled.
func (client blobClient) CreateSnapshot(ctx context.Context, timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, leaseID *string, requestID *string) (*BlobCreateSnapshotResponse, error) { func (client blobClient) CreateSnapshot(ctx context.Context, timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, leaseID *string, requestID *string) (*BlobCreateSnapshotResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.createSnapshotPreparer(timeout, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, leaseID, requestID) req, err := client.createSnapshotPreparer(timeout, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, leaseID, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -365,7 +362,7 @@ func (client blobClient) CreateSnapshot(ctx context.Context, timeout *int32, met
} }
// createSnapshotPreparer prepares the CreateSnapshot request. // createSnapshotPreparer prepares the CreateSnapshot request.
func (client blobClient) createSnapshotPreparer(timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, leaseID *string, requestID *string) (pipeline.Request, error) { func (client blobClient) createSnapshotPreparer(timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, leaseID *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -387,8 +384,8 @@ func (client blobClient) createSnapshotPreparer(timeout *int32, metadata map[str
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -430,23 +427,23 @@ func (client blobClient) createSnapshotResponder(resp pipeline.Response) (pipeli
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a // a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. deleteSnapshots is required if the blob has associated snapshots. Specify one // lease is active and matches this ID. deleteSnapshots is required if the blob has associated snapshots. Specify one
// of the following two options: include: Delete the base blob and all of its snapshots. only: Delete only the blob's // of the following two options: include: Delete the base blob and all of its snapshots. only: Delete only the blob's
// snapshots and not the blob itself ifModifiedSince is specify this header value to operate only on a blob if it has // snapshots and not the blob itself ifModifiedSince is specify this header value to operate only on a blob if it has
// been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a // been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only // blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on
// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching // blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the // requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
// analytics logs when storage analytics logging is enabled. // logs when storage analytics logging is enabled.
func (client blobClient) Delete(ctx context.Context, snapshot *string, timeout *int32, leaseID *string, deleteSnapshots DeleteSnapshotsOptionType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobDeleteResponse, error) { func (client blobClient) Delete(ctx context.Context, snapshot *string, timeout *int32, leaseID *string, deleteSnapshots DeleteSnapshotsOptionType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlobDeleteResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.deletePreparer(snapshot, timeout, leaseID, deleteSnapshots, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.deletePreparer(snapshot, timeout, leaseID, deleteSnapshots, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -458,7 +455,7 @@ func (client blobClient) Delete(ctx context.Context, snapshot *string, timeout *
} }
// deletePreparer prepares the Delete request. // deletePreparer prepares the Delete request.
func (client blobClient) deletePreparer(snapshot *string, timeout *int32, leaseID *string, deleteSnapshots DeleteSnapshotsOptionType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) deletePreparer(snapshot *string, timeout *int32, leaseID *string, deleteSnapshots DeleteSnapshotsOptionType, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("DELETE", client.url, nil) req, err := pipeline.NewRequest("DELETE", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -483,8 +480,8 @@ func (client blobClient) deletePreparer(snapshot *string, timeout *int32, leaseI
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -516,22 +513,22 @@ func (client blobClient) deleteResponder(resp pipeline.Response) (pipeline.Respo
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a // a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified // Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
// range. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. // range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// rangeGetContentMD5 is when set to true and specified together with the Range, the service returns the MD5 hash for // rangeGetContentMD5 is when set to true and specified together with the Range, the service returns the MD5 hash for
// the range, as long as the range is less than or equal to 4 MB in size. ifModifiedSince is specify this header value // the range, as long as the range is less than or equal to 4 MB in size. ifModifiedSince is specify this header value
// to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this // to operate only on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this
// header value to operate only on a blob if it has not been modified since the specified date/time. ifMatches is // header value to operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify
// specify an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to // an ETag value to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only
// operate only on blobs without a matching value. requestID is provides a client-generated, opaque value with a 1 KB // on blobs without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character
// character limit that is recorded in the analytics logs when storage analytics logging is enabled. // limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client blobClient) Download(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, rangeGetContentMD5 *bool, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*downloadResponse, error) { func (client blobClient) Download(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, rangeGetContentMD5 *bool, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*downloadResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.downloadPreparer(snapshot, timeout, rangeParameter, leaseID, rangeGetContentMD5, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.downloadPreparer(snapshot, timeout, rangeParameter, leaseID, rangeGetContentMD5, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -543,7 +540,7 @@ func (client blobClient) Download(ctx context.Context, snapshot *string, timeout
} }
// downloadPreparer prepares the Download request. // downloadPreparer prepares the Download request.
func (client blobClient) downloadPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, rangeGetContentMD5 *bool, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) downloadPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, rangeGetContentMD5 *bool, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil) req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -571,8 +568,8 @@ func (client blobClient) downloadPreparer(snapshot *string, timeout *int32, rang
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -593,6 +590,44 @@ func (client blobClient) downloadResponder(resp pipeline.Response) (pipeline.Res
return &downloadResponse{rawResponse: resp.Response()}, err return &downloadResponse{rawResponse: resp.Response()}, err
} }
// GetAccountInfo returns the sku name and account kind
func (client blobClient) GetAccountInfo(ctx context.Context) (*BlobGetAccountInfoResponse, error) {
req, err := client.getAccountInfoPreparer()
if err != nil {
return nil, err
}
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getAccountInfoResponder}, req)
if err != nil {
return nil, err
}
return resp.(*BlobGetAccountInfoResponse), err
}
// getAccountInfoPreparer prepares the GetAccountInfo request.
func (client blobClient) getAccountInfoPreparer() (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil {
return req, pipeline.NewError(err, "failed to create request")
}
params := req.URL.Query()
params.Set("restype", "account")
params.Set("comp", "properties")
req.URL.RawQuery = params.Encode()
req.Header.Set("x-ms-version", ServiceVersion)
return req, nil
}
// getAccountInfoResponder handles the response to the GetAccountInfo request.
func (client blobClient) getAccountInfoResponder(resp pipeline.Response) (pipeline.Response, error) {
err := validateResponse(resp, http.StatusOK)
if resp == nil {
return nil, err
}
io.Copy(ioutil.Discard, resp.Response().Body)
resp.Response().Body.Close()
return &BlobGetAccountInfoResponse{rawResponse: resp.Response()}, err
}
// GetProperties the Get Properties operation returns all user-defined metadata, standard HTTP properties, and system // GetProperties the Get Properties operation returns all user-defined metadata, standard HTTP properties, and system
// properties for the blob. It does not return the content of the blob. // properties for the blob. It does not return the content of the blob.
// //
@ -601,21 +636,21 @@ func (client blobClient) downloadResponder(resp pipeline.Response) (pipeline.Res
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a // a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it // lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it
// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a // has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only // blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on
// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching // blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the // requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
// analytics logs when storage analytics logging is enabled. // logs when storage analytics logging is enabled.
func (client blobClient) GetProperties(ctx context.Context, snapshot *string, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobGetPropertiesResponse, error) { func (client blobClient) GetProperties(ctx context.Context, snapshot *string, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlobGetPropertiesResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.getPropertiesPreparer(snapshot, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.getPropertiesPreparer(snapshot, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -627,7 +662,7 @@ func (client blobClient) GetProperties(ctx context.Context, snapshot *string, ti
} }
// getPropertiesPreparer prepares the GetProperties request. // getPropertiesPreparer prepares the GetProperties request.
func (client blobClient) getPropertiesPreparer(snapshot *string, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) getPropertiesPreparer(snapshot *string, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("HEAD", client.url, nil) req, err := pipeline.NewRequest("HEAD", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -649,8 +684,8 @@ func (client blobClient) getPropertiesPreparer(snapshot *string, timeout *int32,
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -676,23 +711,23 @@ func (client blobClient) getPropertiesResponder(resp pipeline.Response) (pipelin
// ReleaseLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete // ReleaseLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete
// operations // operations
// //
// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. timeout // leaseID is specifies the current lease ID on the resource. timeout is the timeout parameter is expressed in seconds.
// is the timeout parameter is expressed in seconds. For more information, see <a // For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if // Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only // it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
// on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate // on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate
// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a // only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a
// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded // matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded
// in the analytics logs when storage analytics logging is enabled. // in the analytics logs when storage analytics logging is enabled.
func (client blobClient) ReleaseLease(ctx context.Context, leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobReleaseLeaseResponse, error) { func (client blobClient) ReleaseLease(ctx context.Context, leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlobReleaseLeaseResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.releaseLeasePreparer(leaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.releaseLeasePreparer(leaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -704,7 +739,7 @@ func (client blobClient) ReleaseLease(ctx context.Context, leaseID string, timeo
} }
// releaseLeasePreparer prepares the ReleaseLease request. // releaseLeasePreparer prepares the ReleaseLease request.
func (client blobClient) releaseLeasePreparer(leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) releaseLeasePreparer(leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -722,8 +757,8 @@ func (client blobClient) releaseLeasePreparer(leaseID string, timeout *int32, if
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -750,23 +785,23 @@ func (client blobClient) releaseLeaseResponder(resp pipeline.Response) (pipeline
// RenewLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete // RenewLease [Update] The Lease Blob operation establishes and manages a lock on a blob for write and delete
// operations // operations
// //
// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. timeout // leaseID is specifies the current lease ID on the resource. timeout is the timeout parameter is expressed in seconds.
// is the timeout parameter is expressed in seconds. For more information, see <a // For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if // Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only // it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
// on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate // on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate
// only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a // only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a
// matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded // matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded
// in the analytics logs when storage analytics logging is enabled. // in the analytics logs when storage analytics logging is enabled.
func (client blobClient) RenewLease(ctx context.Context, leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobRenewLeaseResponse, error) { func (client blobClient) RenewLease(ctx context.Context, leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlobRenewLeaseResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.renewLeasePreparer(leaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.renewLeasePreparer(leaseID, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -778,7 +813,7 @@ func (client blobClient) RenewLease(ctx context.Context, leaseID string, timeout
} }
// renewLeasePreparer prepares the RenewLease request. // renewLeasePreparer prepares the RenewLease request.
func (client blobClient) renewLeasePreparer(leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) renewLeasePreparer(leaseID string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -796,8 +831,8 @@ func (client blobClient) renewLeasePreparer(leaseID string, timeout *int32, ifMo
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -832,22 +867,21 @@ func (client blobClient) renewLeaseResponder(resp pipeline.Response) (pipeline.R
// blocks were validated when each was uploaded. blobContentEncoding is optional. Sets the blob's content encoding. If // blocks were validated when each was uploaded. blobContentEncoding is optional. Sets the blob's content encoding. If
// specified, this property is stored with the blob and returned with a read request. blobContentLanguage is optional. // specified, this property is stored with the blob and returned with a read request. blobContentLanguage is optional.
// Set the blob's content language. If specified, this property is stored with the blob and returned with a read // Set the blob's content language. If specified, this property is stored with the blob and returned with a read
// request. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this // request. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// ID. ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the // ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified
// specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been // date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified
// modified since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching // since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value.
// value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. // ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. blobContentDisposition is
// blobContentDisposition is optional. Sets the blob's Content-Disposition header. requestID is provides a // optional. Sets the blob's Content-Disposition header. requestID is provides a client-generated, opaque value with a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // 1 KB character limit that is recorded in the analytics logs when storage analytics logging is enabled.
// analytics logging is enabled. func (client blobClient) SetHTTPHeaders(ctx context.Context, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentMD5 []byte, blobContentEncoding *string, blobContentLanguage *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobContentDisposition *string, requestID *string) (*BlobSetHTTPHeadersResponse, error) {
func (client blobClient) SetHTTPHeaders(ctx context.Context, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentMD5 []byte, blobContentEncoding *string, blobContentLanguage *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobContentDisposition *string, requestID *string) (*BlobSetHTTPHeadersResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.setHTTPHeadersPreparer(timeout, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, blobContentDisposition, requestID) req, err := client.setHTTPHeadersPreparer(timeout, blobCacheControl, blobContentType, blobContentMD5, blobContentEncoding, blobContentLanguage, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, blobContentDisposition, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -859,7 +893,7 @@ func (client blobClient) SetHTTPHeaders(ctx context.Context, timeout *int32, blo
} }
// setHTTPHeadersPreparer prepares the SetHTTPHeaders request. // setHTTPHeadersPreparer prepares the SetHTTPHeaders request.
func (client blobClient) setHTTPHeadersPreparer(timeout *int32, blobCacheControl *string, blobContentType *string, blobContentMD5 []byte, blobContentEncoding *string, blobContentLanguage *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobContentDisposition *string, requestID *string) (pipeline.Request, error) { func (client blobClient) setHTTPHeadersPreparer(timeout *int32, blobCacheControl *string, blobContentType *string, blobContentMD5 []byte, blobContentEncoding *string, blobContentLanguage *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobContentDisposition *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -894,8 +928,8 @@ func (client blobClient) setHTTPHeadersPreparer(timeout *int32, blobCacheControl
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -932,23 +966,20 @@ func (client blobClient) setHTTPHeadersResponder(resp pipeline.Response) (pipeli
// the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version // the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version
// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing // 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing
// Containers, Blobs, and Metadata for more information. leaseID is if specified, the operation only succeeds if the // Containers, Blobs, and Metadata for more information. leaseID is if specified, the operation only succeeds if the
// container's lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a // resource's lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a
// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to // blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to
// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value // operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs // to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is // without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is
// recorded in the analytics logs when storage analytics logging is enabled. // recorded in the analytics logs when storage analytics logging is enabled.
func (client blobClient) SetMetadata(ctx context.Context, timeout *int32, metadata map[string]string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlobSetMetadataResponse, error) { func (client blobClient) SetMetadata(ctx context.Context, timeout *int32, metadata map[string]string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlobSetMetadataResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.setMetadataPreparer(timeout, metadata, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.setMetadataPreparer(timeout, metadata, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -960,7 +991,7 @@ func (client blobClient) SetMetadata(ctx context.Context, timeout *int32, metada
} }
// setMetadataPreparer prepares the SetMetadata request. // setMetadataPreparer prepares the SetMetadata request.
func (client blobClient) setMetadataPreparer(timeout *int32, metadata map[string]string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blobClient) setMetadataPreparer(timeout *int32, metadata map[string]string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -985,8 +1016,8 @@ func (client blobClient) setMetadataPreparer(timeout *int32, metadata map[string
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -1018,15 +1049,16 @@ func (client blobClient) setMetadataResponder(resp pipeline.Response) (pipeline.
// information, see <a // information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB // Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled. // character limit that is recorded in the analytics logs when storage analytics logging is enabled. leaseID is if
func (client blobClient) SetTier(ctx context.Context, tier AccessTierType, timeout *int32, requestID *string) (*BlobSetTierResponse, error) { // specified, the operation only succeeds if the resource's lease is active and matches this ID.
func (client blobClient) SetTier(ctx context.Context, tier AccessTierType, timeout *int32, requestID *string, leaseID *string) (*BlobSetTierResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.setTierPreparer(tier, timeout, requestID) req, err := client.setTierPreparer(tier, timeout, requestID, leaseID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1038,7 +1070,7 @@ func (client blobClient) SetTier(ctx context.Context, tier AccessTierType, timeo
} }
// setTierPreparer prepares the SetTier request. // setTierPreparer prepares the SetTier request.
func (client blobClient) setTierPreparer(tier AccessTierType, timeout *int32, requestID *string) (pipeline.Request, error) { func (client blobClient) setTierPreparer(tier AccessTierType, timeout *int32, requestID *string, leaseID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -1054,6 +1086,9 @@ func (client blobClient) setTierPreparer(tier AccessTierType, timeout *int32, re
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)
} }
if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID)
}
return req, nil return req, nil
} }
@ -1082,27 +1117,23 @@ func (client blobClient) setTierResponder(resp pipeline.Response) (pipeline.Resp
// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing // 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing
// Containers, Blobs, and Metadata for more information. sourceIfModifiedSince is specify this header value to operate // Containers, Blobs, and Metadata for more information. sourceIfModifiedSince is specify this header value to operate
// only on a blob if it has been modified since the specified date/time. sourceIfUnmodifiedSince is specify this header // only on a blob if it has been modified since the specified date/time. sourceIfUnmodifiedSince is specify this header
// value to operate only on a blob if it has not been modified since the specified date/time. sourceIfMatches is // value to operate only on a blob if it has not been modified since the specified date/time. sourceIfMatch is specify
// specify an ETag value to operate only on blobs with a matching value. sourceIfNoneMatch is specify an ETag value to // an ETag value to operate only on blobs with a matching value. sourceIfNoneMatch is specify an ETag value to operate
// operate only on blobs without a matching value. ifModifiedSince is specify this header value to operate only on a // only on blobs without a matching value. ifModifiedSince is specify this header value to operate only on a blob if it
// blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to // has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value // blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs // blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
// without a matching value. leaseID is if specified, the operation only succeeds if the container's lease is active // leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// and matches this ID. sourceLeaseID is specify this header to perform the operation only if the lease ID given // requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
// matches the active lease ID of the source blob. requestID is provides a client-generated, opaque value with a 1 KB // logs when storage analytics logging is enabled.
// character limit that is recorded in the analytics logs when storage analytics logging is enabled. func (client blobClient) StartCopyFromURL(ctx context.Context, copySource string, timeout *int32, metadata map[string]string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, leaseID *string, requestID *string) (*BlobStartCopyFromURLResponse, error) {
func (client blobClient) StartCopyFromURL(ctx context.Context, copySource string, timeout *int32, metadata map[string]string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatches *ETag, sourceIfNoneMatch *ETag, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, leaseID *string, sourceLeaseID *string, requestID *string) (*BlobStartCopyFromURLResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.startCopyFromURLPreparer(copySource, timeout, metadata, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatches, sourceIfNoneMatch, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, leaseID, sourceLeaseID, requestID) req, err := client.startCopyFromURLPreparer(copySource, timeout, metadata, sourceIfModifiedSince, sourceIfUnmodifiedSince, sourceIfMatch, sourceIfNoneMatch, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, leaseID, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -1114,7 +1145,7 @@ func (client blobClient) StartCopyFromURL(ctx context.Context, copySource string
} }
// startCopyFromURLPreparer prepares the StartCopyFromURL request. // startCopyFromURLPreparer prepares the StartCopyFromURL request.
func (client blobClient) startCopyFromURLPreparer(copySource string, timeout *int32, metadata map[string]string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatches *ETag, sourceIfNoneMatch *ETag, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, leaseID *string, sourceLeaseID *string, requestID *string) (pipeline.Request, error) { func (client blobClient) startCopyFromURLPreparer(copySource string, timeout *int32, metadata map[string]string, sourceIfModifiedSince *time.Time, sourceIfUnmodifiedSince *time.Time, sourceIfMatch *ETag, sourceIfNoneMatch *ETag, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, leaseID *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -1135,8 +1166,8 @@ func (client blobClient) startCopyFromURLPreparer(copySource string, timeout *in
if sourceIfUnmodifiedSince != nil { if sourceIfUnmodifiedSince != nil {
req.Header.Set("x-ms-source-if-unmodified-since", (*sourceIfUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("x-ms-source-if-unmodified-since", (*sourceIfUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if sourceIfMatches != nil { if sourceIfMatch != nil {
req.Header.Set("x-ms-source-if-match", string(*sourceIfMatches)) req.Header.Set("x-ms-source-if-match", string(*sourceIfMatch))
} }
if sourceIfNoneMatch != nil { if sourceIfNoneMatch != nil {
req.Header.Set("x-ms-source-if-none-match", string(*sourceIfNoneMatch)) req.Header.Set("x-ms-source-if-none-match", string(*sourceIfNoneMatch))
@ -1147,8 +1178,8 @@ func (client blobClient) startCopyFromURLPreparer(copySource string, timeout *in
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -1157,9 +1188,6 @@ func (client blobClient) startCopyFromURLPreparer(copySource string, timeout *in
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
if sourceLeaseID != nil {
req.Header.Set("x-ms-source-lease-id", *sourceLeaseID)
}
req.Header.Set("x-ms-version", ServiceVersion) req.Header.Set("x-ms-version", ServiceVersion)
if requestID != nil { if requestID != nil {
req.Header.Set("x-ms-client-request-id", *requestID) req.Header.Set("x-ms-client-request-id", *requestID)

View file

@ -48,25 +48,22 @@ func newBlockBlobClient(url url.URL, p pipeline.Pipeline) blockBlobClient {
// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified // destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified
// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, // metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19,
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and // metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and
// Metadata for more information. leaseID is if specified, the operation only succeeds if the container's lease is // Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. // active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header.
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified
// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. // since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value.
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a // ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled. // analytics logging is enabled.
func (client blockBlobClient) CommitBlockList(ctx context.Context, blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobCommitBlockListResponse, error) { func (client blockBlobClient) CommitBlockList(ctx context.Context, blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobCommitBlockListResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.commitBlockListPreparer(blocks, timeout, blobCacheControl, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.commitBlockListPreparer(blocks, timeout, blobCacheControl, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -78,7 +75,7 @@ func (client blockBlobClient) CommitBlockList(ctx context.Context, blocks BlockL
} }
// commitBlockListPreparer prepares the CommitBlockList request. // commitBlockListPreparer prepares the CommitBlockList request.
func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, timeout *int32, blobCacheControl *string, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -121,8 +118,8 @@ func (client blockBlobClient) commitBlockListPreparer(blocks BlockLookupList, ti
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -163,7 +160,7 @@ func (client blockBlobClient) commitBlockListResponder(resp pipeline.Response) (
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/creating-a-snapshot-of-a-blob">Creating
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a // a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character // lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled. // limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client blockBlobClient) GetBlockList(ctx context.Context, listType BlockListType, snapshot *string, timeout *int32, leaseID *string, requestID *string) (*BlockList, error) { func (client blockBlobClient) GetBlockList(ctx context.Context, listType BlockListType, snapshot *string, timeout *int32, leaseID *string, requestID *string) (*BlockList, error) {
@ -223,7 +220,7 @@ func (client blockBlobClient) getBlockListResponder(resp pipeline.Response) (pip
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)
@ -240,13 +237,14 @@ func (client blockBlobClient) getBlockListResponder(resp pipeline.Response) (pip
// blockID is a valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or // blockID is a valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or
// equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the // equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the
// same size for each block. contentLength is the length of the request. body is initial data body will be closed upon // same size for each block. contentLength is the length of the request. body is initial data body will be closed upon
// successful return. Callers should ensure closure when receiving an error.timeout is the timeout parameter is // successful return. Callers should ensure closure when receiving an error.transactionalContentMD5 is specify the
// expressed in seconds. For more information, see <a // transactional md5 for the body, to be validated by the service. timeout is the timeout parameter is expressed in
// seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character // lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled. // limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, contentLength int64, body io.ReadSeeker, timeout *int32, leaseID *string, requestID *string) (*BlockBlobStageBlockResponse, error) { func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, contentLength int64, body io.ReadSeeker, transactionalContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (*BlockBlobStageBlockResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: body, {targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
@ -255,7 +253,7 @@ func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, co
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.stageBlockPreparer(blockID, contentLength, body, timeout, leaseID, requestID) req, err := client.stageBlockPreparer(blockID, contentLength, body, transactionalContentMD5, timeout, leaseID, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -267,7 +265,7 @@ func (client blockBlobClient) StageBlock(ctx context.Context, blockID string, co
} }
// stageBlockPreparer prepares the StageBlock request. // stageBlockPreparer prepares the StageBlock request.
func (client blockBlobClient) stageBlockPreparer(blockID string, contentLength int64, body io.ReadSeeker, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) stageBlockPreparer(blockID string, contentLength int64, body io.ReadSeeker, transactionalContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, body) req, err := pipeline.NewRequest("PUT", client.url, body)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -280,6 +278,9 @@ func (client blockBlobClient) stageBlockPreparer(blockID string, contentLength i
params.Set("comp", "block") params.Set("comp", "block")
req.URL.RawQuery = params.Encode() req.URL.RawQuery = params.Encode()
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
}
if leaseID != nil { if leaseID != nil {
req.Header.Set("x-ms-lease-id", *leaseID) req.Header.Set("x-ms-lease-id", *leaseID)
} }
@ -306,15 +307,15 @@ func (client blockBlobClient) stageBlockResponder(resp pipeline.Response) (pipel
// //
// blockID is a valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or // blockID is a valid Base64 string value that identifies the block. Prior to encoding, the string must be less than or
// equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the // equal to 64 bytes in size. For a given blob, the length of the value specified for the blockid parameter must be the
// same size for each block. contentLength is the length of the request. sourceURL is specifiy an URL to the copy // same size for each block. contentLength is the length of the request. sourceURL is specify a URL to the copy source.
// source. sourceRange is bytes of source data in the specified range. sourceContentMD5 is specify the md5 calculated // sourceRange is bytes of source data in the specified range. sourceContentMD5 is specify the md5 calculated for the
// for the range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in // range of bytes that must be read from the copy source. timeout is the timeout parameter is expressed in seconds. For
// seconds. For more information, see <a // more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character // lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled. // limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client blockBlobClient) StageBlockFromURL(ctx context.Context, blockID string, contentLength int64, sourceURL *string, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (*BlockBlobStageBlockFromURLResponse, error) { func (client blockBlobClient) StageBlockFromURL(ctx context.Context, blockID string, contentLength int64, sourceURL string, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (*BlockBlobStageBlockFromURLResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
@ -333,7 +334,7 @@ func (client blockBlobClient) StageBlockFromURL(ctx context.Context, blockID str
} }
// stageBlockFromURLPreparer prepares the StageBlockFromURL request. // stageBlockFromURLPreparer prepares the StageBlockFromURL request.
func (client blockBlobClient) stageBlockFromURLPreparer(blockID string, contentLength int64, sourceURL *string, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) stageBlockFromURLPreparer(blockID string, contentLength int64, sourceURL string, sourceRange *string, sourceContentMD5 []byte, timeout *int32, leaseID *string, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -346,9 +347,7 @@ func (client blockBlobClient) stageBlockFromURLPreparer(blockID string, contentL
params.Set("comp", "block") params.Set("comp", "block")
req.URL.RawQuery = params.Encode() req.URL.RawQuery = params.Encode()
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
if sourceURL != nil { req.Header.Set("x-ms-copy-source", sourceURL)
req.Header.Set("x-ms-copy-source", *sourceURL)
}
if sourceRange != nil { if sourceRange != nil {
req.Header.Set("x-ms-source-range", *sourceRange) req.Header.Set("x-ms-source-range", *sourceRange)
} }
@ -397,27 +396,24 @@ func (client blockBlobClient) stageBlockFromURLResponder(resp pipeline.Response)
// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified // destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified
// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, // metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19,
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and // metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and
// Metadata for more information. leaseID is if specified, the operation only succeeds if the container's lease is // Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. // active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header.
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified
// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. // since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value.
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a // ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled. // analytics logging is enabled.
func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobUploadResponse, error) { func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*BlockBlobUploadResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: body, {targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.uploadPreparer(body, contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.uploadPreparer(body, contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -429,7 +425,7 @@ func (client blockBlobClient) Upload(ctx context.Context, body io.ReadSeeker, co
} }
// uploadPreparer prepares the Upload request. // uploadPreparer prepares the Upload request.
func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, body) req, err := pipeline.NewRequest("PUT", client.url, body)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -472,8 +468,8 @@ func (client blockBlobClient) uploadPreparer(body io.ReadSeeker, contentLength i
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))

View file

@ -7,14 +7,13 @@ import (
"bytes" "bytes"
"context" "context"
"encoding/xml" "encoding/xml"
"github.com/Azure/azure-pipeline-go/pipeline"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url" "net/url"
"strconv" "strconv"
"time" "time"
"github.com/Azure/azure-pipeline-go/pipeline"
) )
// containerClient is the client for the Container methods of the Azblob service. // containerClient is the client for the Container methods of the Azblob service.
@ -179,10 +178,10 @@ func (client containerClient) breakLeaseResponder(resp pipeline.Response) (pipel
// ChangeLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be // ChangeLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be
// 15 to 60 seconds, or can be infinite // 15 to 60 seconds, or can be infinite
// //
// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. // leaseID is specifies the current lease ID on the resource. proposedLeaseID is proposed lease ID, in a GUID string
// proposedLeaseID is proposed lease ID, in a GUID string format. The Blob service returns 400 (Invalid request) if the // format. The Blob service returns 400 (Invalid request) if the proposed lease ID is not in the correct format. See
// proposed lease ID is not in the correct format. See Guid Constructor (String) for a list of valid GUID string // Guid Constructor (String) for a list of valid GUID string formats. timeout is the timeout parameter is expressed in
// formats. timeout is the timeout parameter is expressed in seconds. For more information, see <a // seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if // Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only // it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
@ -264,10 +263,7 @@ func (client containerClient) Create(ctx context.Context, timeout *int32, metada
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.createPreparer(timeout, metadata, access, requestID) req, err := client.createPreparer(timeout, metadata, access, requestID)
@ -324,7 +320,7 @@ func (client containerClient) createResponder(resp pipeline.Response) (pipeline.
// //
// timeout is the timeout parameter is expressed in seconds. For more information, see <a // timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it // lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it
// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a // has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
// blob if it has not been modified since the specified date/time. requestID is provides a client-generated, opaque // blob if it has not been modified since the specified date/time. requestID is provides a client-generated, opaque
@ -391,7 +387,7 @@ func (client containerClient) deleteResponder(resp pipeline.Response) (pipeline.
// //
// timeout is the timeout parameter is expressed in seconds. For more information, see <a // timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character // lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled. // limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) GetAccessPolicy(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*SignedIdentifiers, error) { func (client containerClient) GetAccessPolicy(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*SignedIdentifiers, error) {
@ -448,7 +444,7 @@ func (client containerClient) getAccessPolicyResponder(resp pipeline.Response) (
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)
@ -460,12 +456,50 @@ func (client containerClient) getAccessPolicyResponder(resp pipeline.Response) (
return result, nil return result, nil
} }
// GetAccountInfo returns the sku name and account kind
func (client containerClient) GetAccountInfo(ctx context.Context) (*ContainerGetAccountInfoResponse, error) {
req, err := client.getAccountInfoPreparer()
if err != nil {
return nil, err
}
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getAccountInfoResponder}, req)
if err != nil {
return nil, err
}
return resp.(*ContainerGetAccountInfoResponse), err
}
// getAccountInfoPreparer prepares the GetAccountInfo request.
func (client containerClient) getAccountInfoPreparer() (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil {
return req, pipeline.NewError(err, "failed to create request")
}
params := req.URL.Query()
params.Set("restype", "account")
params.Set("comp", "properties")
req.URL.RawQuery = params.Encode()
req.Header.Set("x-ms-version", ServiceVersion)
return req, nil
}
// getAccountInfoResponder handles the response to the GetAccountInfo request.
func (client containerClient) getAccountInfoResponder(resp pipeline.Response) (pipeline.Response, error) {
err := validateResponse(resp, http.StatusOK)
if resp == nil {
return nil, err
}
io.Copy(ioutil.Discard, resp.Response().Body)
resp.Response().Body.Close()
return &ContainerGetAccountInfoResponse{rawResponse: resp.Response()}, err
}
// GetProperties returns all user-defined metadata and system properties for the specified container. The data returned // GetProperties returns all user-defined metadata and system properties for the specified container. The data returned
// does not include the container's list of blobs // does not include the container's list of blobs
// //
// timeout is the timeout parameter is expressed in seconds. For more information, see <a // timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character // lease is active and matches this ID. requestID is provides a client-generated, opaque value with a 1 KB character
// limit that is recorded in the analytics logs when storage analytics logging is enabled. // limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client containerClient) GetProperties(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*ContainerGetPropertiesResponse, error) { func (client containerClient) GetProperties(ctx context.Context, timeout *int32, leaseID *string, requestID *string) (*ContainerGetPropertiesResponse, error) {
@ -601,7 +635,7 @@ func (client containerClient) listBlobFlatSegmentResponder(resp pipeline.Respons
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)
@ -699,7 +733,7 @@ func (client containerClient) listBlobHierarchySegmentResponder(resp pipeline.Re
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)
@ -714,8 +748,8 @@ func (client containerClient) listBlobHierarchySegmentResponder(resp pipeline.Re
// ReleaseLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be // ReleaseLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be
// 15 to 60 seconds, or can be infinite // 15 to 60 seconds, or can be infinite
// //
// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. timeout // leaseID is specifies the current lease ID on the resource. timeout is the timeout parameter is expressed in seconds.
// is the timeout parameter is expressed in seconds. For more information, see <a // For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if // Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only // it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
@ -782,8 +816,8 @@ func (client containerClient) releaseLeaseResponder(resp pipeline.Response) (pip
// RenewLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15 // RenewLease [Update] establishes and manages a lock on a container for delete operations. The lock duration can be 15
// to 60 seconds, or can be infinite // to 60 seconds, or can be infinite
// //
// leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. timeout // leaseID is specifies the current lease ID on the resource. timeout is the timeout parameter is expressed in seconds.
// is the timeout parameter is expressed in seconds. For more information, see <a // For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if // Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if
// it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only // it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
@ -853,7 +887,7 @@ func (client containerClient) renewLeaseResponder(resp pipeline.Response) (pipel
// containerACL is the acls for the container timeout is the timeout parameter is expressed in seconds. For more // containerACL is the acls for the container timeout is the timeout parameter is expressed in seconds. For more
// information, see <a // information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. access is specifies whether data in the container may be accessed publicly and // lease is active and matches this ID. access is specifies whether data in the container may be accessed publicly and
// the level of access ifModifiedSince is specify this header value to operate only on a blob if it has been modified // the level of access ifModifiedSince is specify this header value to operate only on a blob if it has been modified
// since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has // since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has
@ -933,7 +967,7 @@ func (client containerClient) setAccessPolicyResponder(resp pipeline.Response) (
// //
// timeout is the timeout parameter is expressed in seconds. For more information, see <a // timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. metadata is optional. Specifies a user-defined name-value pair associated with // lease is active and matches this ID. metadata is optional. Specifies a user-defined name-value pair associated with
// the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to // the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or file to
// the destination blob. If one or more name-value pairs are specified, the destination blob is created with the // the destination blob. If one or more name-value pairs are specified, the destination blob is created with the
@ -946,10 +980,7 @@ func (client containerClient) SetMetadata(ctx context.Context, timeout *int32, l
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.setMetadataPreparer(timeout, leaseID, metadata, ifModifiedSince, requestID) req, err := client.setMetadataPreparer(timeout, leaseID, metadata, ifModifiedSince, requestID)

View file

@ -32,24 +32,24 @@ func newPageBlobClient(url url.URL, p pipeline.Pipeline) pageBlobClient {
// information, see <a // information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified // Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
// range. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. // range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number // ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number
// less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob // less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob
// if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate // if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate
// only on a blob if it has the specified sequence number. ifModifiedSince is specify this header value to operate only // only on a blob if it has the specified sequence number. ifModifiedSince is specify this header value to operate only
// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to // on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to
// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value // operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs // to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is // without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is
// recorded in the analytics logs when storage analytics logging is enabled. // recorded in the analytics logs when storage analytics logging is enabled.
func (client pageBlobClient) ClearPages(ctx context.Context, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobClearPagesResponse, error) { func (client pageBlobClient) ClearPages(ctx context.Context, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobClearPagesResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.clearPagesPreparer(contentLength, timeout, rangeParameter, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.clearPagesPreparer(contentLength, timeout, rangeParameter, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -61,7 +61,7 @@ func (client pageBlobClient) ClearPages(ctx context.Context, contentLength int64
} }
// clearPagesPreparer prepares the ClearPages request. // clearPagesPreparer prepares the ClearPages request.
func (client pageBlobClient) clearPagesPreparer(contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) clearPagesPreparer(contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -94,8 +94,8 @@ func (client pageBlobClient) clearPagesPreparer(contentLength int64, timeout *in
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -129,28 +129,20 @@ func (client pageBlobClient) clearPagesResponder(resp pipeline.Response) (pipeli
// must either be public or must be authenticated via a shared access signature. timeout is the timeout parameter is // must either be public or must be authenticated via a shared access signature. timeout is the timeout parameter is
// expressed in seconds. For more information, see <a // expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> metadata is optional. Specifies a user-defined name-value pair associated // Timeouts for Blob Service Operations.</a> ifModifiedSince is specify this header value to operate only on a blob if
// with the blob. If no name-value pairs are specified, the operation will copy the metadata from the source blob or // it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only
// file to the destination blob. If one or more name-value pairs are specified, the destination blob is created with // on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate
// the specified metadata, and metadata is not copied from the source blob or file. Note that beginning with version // only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a
// 2009-09-19, metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing // matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded
// Containers, Blobs, and Metadata for more information. ifModifiedSince is specify this header value to operate only // in the analytics logs when storage analytics logging is enabled.
// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to func (client pageBlobClient) CopyIncremental(ctx context.Context, copySource string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobCopyIncrementalResponse, error) {
// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is
// recorded in the analytics logs when storage analytics logging is enabled.
func (client pageBlobClient) CopyIncremental(ctx context.Context, copySource string, timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobCopyIncrementalResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.copyIncrementalPreparer(copySource, timeout, metadata, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.copyIncrementalPreparer(copySource, timeout, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -162,7 +154,7 @@ func (client pageBlobClient) CopyIncremental(ctx context.Context, copySource str
} }
// copyIncrementalPreparer prepares the CopyIncremental request. // copyIncrementalPreparer prepares the CopyIncremental request.
func (client pageBlobClient) copyIncrementalPreparer(copySource string, timeout *int32, metadata map[string]string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) copyIncrementalPreparer(copySource string, timeout *int32, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -173,19 +165,14 @@ func (client pageBlobClient) copyIncrementalPreparer(copySource string, timeout
} }
params.Set("comp", "incrementalcopy") params.Set("comp", "incrementalcopy")
req.URL.RawQuery = params.Encode() req.URL.RawQuery = params.Encode()
if metadata != nil {
for k, v := range metadata {
req.Header.Set("x-ms-meta-"+k, v)
}
}
if ifModifiedSince != nil { if ifModifiedSince != nil {
req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Modified-Since", (*ifModifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -211,8 +198,9 @@ func (client pageBlobClient) copyIncrementalResponder(resp pipeline.Response) (p
// Create the Create operation creates a new page blob. // Create the Create operation creates a new page blob.
// //
// contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more // contentLength is the length of the request. blobContentLength is this header specifies the maximum size for the page
// information, see <a // blob, up to 1 TB. The page blob size must be aligned to a 512-byte boundary. timeout is the timeout parameter is
// expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> blobContentType is optional. Sets the blob's content type. If specified, // Timeouts for Blob Service Operations.</a> blobContentType is optional. Sets the blob's content type. If specified,
// this property is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the // this property is stored with the blob and returned with a read request. blobContentEncoding is optional. Sets the
@ -226,28 +214,23 @@ func (client pageBlobClient) copyIncrementalResponder(resp pipeline.Response) (p
// destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified // destination blob. If one or more name-value pairs are specified, the destination blob is created with the specified
// metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19, // metadata, and metadata is not copied from the source blob or file. Note that beginning with version 2009-09-19,
// metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and // metadata names must adhere to the naming rules for C# identifiers. See Naming and Referencing Containers, Blobs, and
// Metadata for more information. leaseID is if specified, the operation only succeeds if the container's lease is // Metadata for more information. leaseID is if specified, the operation only succeeds if the resource's lease is
// active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header. // active and matches this ID. blobContentDisposition is optional. Sets the blob's Content-Disposition header.
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified
// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. // since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value.
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. blobContentLength is this // ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. blobSequenceNumber is set
// header specifies the maximum size for the page blob, up to 1 TB. The page blob size must be aligned to a 512-byte // for page blobs only. The sequence number is a user-controlled value that you can use to track requests. The value of
// boundary. blobSequenceNumber is set for page blobs only. The sequence number is a user-controlled value that you can // the sequence number must be between 0 and 2^63 - 1. requestID is provides a client-generated, opaque value with a 1
// use to track requests. The value of the sequence number must be between 0 and 2^63 - 1. requestID is provides a // KB character limit that is recorded in the analytics logs when storage analytics logging is enabled.
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage func (client pageBlobClient) Create(ctx context.Context, contentLength int64, blobContentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (*PageBlobCreateResponse, error) {
// analytics logging is enabled.
func (client pageBlobClient) Create(ctx context.Context, contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobContentLength *int64, blobSequenceNumber *int64, requestID *string) (*PageBlobCreateResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}, chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
{targetValue: metadata,
constraints: []constraint{{target: "metadata", name: null, rule: false,
chain: []constraint{{target: "metadata", name: pattern, rule: `^[a-zA-Z]+$`, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.createPreparer(contentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, blobContentLength, blobSequenceNumber, requestID) req, err := client.createPreparer(contentLength, blobContentLength, timeout, blobContentType, blobContentEncoding, blobContentLanguage, blobContentMD5, blobCacheControl, metadata, leaseID, blobContentDisposition, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, blobSequenceNumber, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -259,7 +242,7 @@ func (client pageBlobClient) Create(ctx context.Context, contentLength int64, ti
} }
// createPreparer prepares the Create request. // createPreparer prepares the Create request.
func (client pageBlobClient) createPreparer(contentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobContentLength *int64, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) createPreparer(contentLength int64, blobContentLength int64, timeout *int32, blobContentType *string, blobContentEncoding *string, blobContentLanguage *string, blobContentMD5 []byte, blobCacheControl *string, metadata map[string]string, leaseID *string, blobContentDisposition *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -302,15 +285,13 @@ func (client pageBlobClient) createPreparer(contentLength int64, timeout *int32,
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
} }
if blobContentLength != nil { req.Header.Set("x-ms-blob-content-length", strconv.FormatInt(blobContentLength, 10))
req.Header.Set("x-ms-blob-content-length", strconv.FormatInt(*blobContentLength, 10))
}
if blobSequenceNumber != nil { if blobSequenceNumber != nil {
req.Header.Set("x-ms-blob-sequence-number", strconv.FormatInt(*blobSequenceNumber, 10)) req.Header.Set("x-ms-blob-sequence-number", strconv.FormatInt(*blobSequenceNumber, 10))
} }
@ -342,21 +323,21 @@ func (client pageBlobClient) createResponder(resp pipeline.Response) (pipeline.R
// a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a // a Snapshot of a Blob.</a> timeout is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified // Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
// range. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. // range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified // ifModifiedSince is specify this header value to operate only on a blob if it has been modified since the specified
// date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified // date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if it has not been modified
// since the specified date/time. ifMatches is specify an ETag value to operate only on blobs with a matching value. // since the specified date/time. ifMatch is specify an ETag value to operate only on blobs with a matching value.
// ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a // ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. requestID is provides a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled. // analytics logging is enabled.
func (client pageBlobClient) GetPageRanges(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) { func (client pageBlobClient) GetPageRanges(ctx context.Context, snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.getPageRangesPreparer(snapshot, timeout, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.getPageRangesPreparer(snapshot, timeout, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -368,7 +349,7 @@ func (client pageBlobClient) GetPageRanges(ctx context.Context, snapshot *string
} }
// getPageRangesPreparer prepares the GetPageRanges request. // getPageRangesPreparer prepares the GetPageRanges request.
func (client pageBlobClient) getPageRangesPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) getPageRangesPreparer(snapshot *string, timeout *int32, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil) req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -394,8 +375,8 @@ func (client pageBlobClient) getPageRangesPreparer(snapshot *string, timeout *in
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -420,7 +401,7 @@ func (client pageBlobClient) getPageRangesResponder(resp pipeline.Response) (pip
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)
@ -445,21 +426,21 @@ func (client pageBlobClient) getPageRangesResponder(resp pipeline.Response) (pip
// target blob and previous snapshot. Changed pages include both updated and cleared pages. The target blob may be a // target blob and previous snapshot. Changed pages include both updated and cleared pages. The target blob may be a
// snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note that incremental snapshots // snapshot, as long as the snapshot specified by prevsnapshot is the older of the two. Note that incremental snapshots
// are currently supported only for blobs created on or after January 1, 2016. rangeParameter is return only the bytes // are currently supported only for blobs created on or after January 1, 2016. rangeParameter is return only the bytes
// of the blob in the specified range. leaseID is if specified, the operation only succeeds if the container's lease is // of the blob in the specified range. leaseID is if specified, the operation only succeeds if the resource's lease is
// active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it has been // active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it has been
// modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if // modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a blob if
// it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only on blobs // it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on blobs
// with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value. // with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
// requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics // requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
// logs when storage analytics logging is enabled. // logs when storage analytics logging is enabled.
func (client pageBlobClient) GetPageRangesDiff(ctx context.Context, snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) { func (client pageBlobClient) GetPageRangesDiff(ctx context.Context, snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageList, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.getPageRangesDiffPreparer(snapshot, timeout, prevsnapshot, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.getPageRangesDiffPreparer(snapshot, timeout, prevsnapshot, rangeParameter, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -471,7 +452,7 @@ func (client pageBlobClient) GetPageRangesDiff(ctx context.Context, snapshot *st
} }
// getPageRangesDiffPreparer prepares the GetPageRangesDiff request. // getPageRangesDiffPreparer prepares the GetPageRangesDiff request.
func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout *int32, prevsnapshot *string, rangeParameter *string, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil) req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -500,8 +481,8 @@ func (client pageBlobClient) getPageRangesDiffPreparer(snapshot *string, timeout
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -526,7 +507,7 @@ func (client pageBlobClient) getPageRangesDiffResponder(resp pipeline.Response)
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)
@ -544,21 +525,21 @@ func (client pageBlobClient) getPageRangesDiffResponder(resp pipeline.Response)
// be aligned to a 512-byte boundary. timeout is the timeout parameter is expressed in seconds. For more information, // be aligned to a 512-byte boundary. timeout is the timeout parameter is expressed in seconds. For more information,
// see <a // see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it // lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it
// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a // has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only // blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on
// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching // blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
// value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the // requestID is provides a client-generated, opaque value with a 1 KB character limit that is recorded in the analytics
// analytics logs when storage analytics logging is enabled. // logs when storage analytics logging is enabled.
func (client pageBlobClient) Resize(ctx context.Context, blobContentLength int64, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobResizeResponse, error) { func (client pageBlobClient) Resize(ctx context.Context, blobContentLength int64, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobResizeResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.resizePreparer(blobContentLength, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.resizePreparer(blobContentLength, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -570,7 +551,7 @@ func (client pageBlobClient) Resize(ctx context.Context, blobContentLength int64
} }
// resizePreparer prepares the Resize request. // resizePreparer prepares the Resize request.
func (client pageBlobClient) resizePreparer(blobContentLength int64, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) resizePreparer(blobContentLength int64, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -590,8 +571,8 @@ func (client pageBlobClient) resizePreparer(blobContentLength int64, timeout *in
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -621,23 +602,23 @@ func (client pageBlobClient) resizeResponder(resp pipeline.Response) (pipeline.R
// applies to page blobs only. This property indicates how the service should modify the blob's sequence number timeout // applies to page blobs only. This property indicates how the service should modify the blob's sequence number timeout
// is the timeout parameter is expressed in seconds. For more information, see <a // is the timeout parameter is expressed in seconds. For more information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the container's // Timeouts for Blob Service Operations.</a> leaseID is if specified, the operation only succeeds if the resource's
// lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it // lease is active and matches this ID. ifModifiedSince is specify this header value to operate only on a blob if it
// has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a // has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to operate only on a
// blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value to operate only // blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value to operate only on
// on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching // blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs without a matching value.
// value. blobSequenceNumber is set for page blobs only. The sequence number is a user-controlled value that you can // blobSequenceNumber is set for page blobs only. The sequence number is a user-controlled value that you can use to
// use to track requests. The value of the sequence number must be between 0 and 2^63 - 1. requestID is provides a // track requests. The value of the sequence number must be between 0 and 2^63 - 1. requestID is provides a
// client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage // client-generated, opaque value with a 1 KB character limit that is recorded in the analytics logs when storage
// analytics logging is enabled. // analytics logging is enabled.
func (client pageBlobClient) UpdateSequenceNumber(ctx context.Context, sequenceNumberAction SequenceNumberActionType, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (*PageBlobUpdateSequenceNumberResponse, error) { func (client pageBlobClient) UpdateSequenceNumber(ctx context.Context, sequenceNumberAction SequenceNumberActionType, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (*PageBlobUpdateSequenceNumberResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: timeout, {targetValue: timeout,
constraints: []constraint{{target: "timeout", name: null, rule: false, constraints: []constraint{{target: "timeout", name: null, rule: false,
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.updateSequenceNumberPreparer(sequenceNumberAction, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, blobSequenceNumber, requestID) req, err := client.updateSequenceNumberPreparer(sequenceNumberAction, timeout, leaseID, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, blobSequenceNumber, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -649,7 +630,7 @@ func (client pageBlobClient) UpdateSequenceNumber(ctx context.Context, sequenceN
} }
// updateSequenceNumberPreparer prepares the UpdateSequenceNumber request. // updateSequenceNumberPreparer prepares the UpdateSequenceNumber request.
func (client pageBlobClient) updateSequenceNumberPreparer(sequenceNumberAction SequenceNumberActionType, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) updateSequenceNumberPreparer(sequenceNumberAction SequenceNumberActionType, timeout *int32, leaseID *string, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, blobSequenceNumber *int64, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, nil) req, err := pipeline.NewRequest("PUT", client.url, nil)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -669,8 +650,8 @@ func (client pageBlobClient) updateSequenceNumberPreparer(sequenceNumberAction S
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))
@ -700,21 +681,22 @@ func (client pageBlobClient) updateSequenceNumberResponder(resp pipeline.Respons
// UploadPages the Upload Pages operation writes a range of pages to a page blob // UploadPages the Upload Pages operation writes a range of pages to a page blob
// //
// body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an // body is initial data body will be closed upon successful return. Callers should ensure closure when receiving an
// error.contentLength is the length of the request. timeout is the timeout parameter is expressed in seconds. For more // error.contentLength is the length of the request. transactionalContentMD5 is specify the transactional md5 for the
// body, to be validated by the service. timeout is the timeout parameter is expressed in seconds. For more
// information, see <a // information, see <a
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified // Timeouts for Blob Service Operations.</a> rangeParameter is return only the bytes of the blob in the specified
// range. leaseID is if specified, the operation only succeeds if the container's lease is active and matches this ID. // range. leaseID is if specified, the operation only succeeds if the resource's lease is active and matches this ID.
// ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number // ifSequenceNumberLessThanOrEqualTo is specify this header value to operate only on a blob if it has a sequence number
// less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob // less than or equal to the specified. ifSequenceNumberLessThan is specify this header value to operate only on a blob
// if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate // if it has a sequence number less than the specified. ifSequenceNumberEqualTo is specify this header value to operate
// only on a blob if it has the specified sequence number. ifModifiedSince is specify this header value to operate only // only on a blob if it has the specified sequence number. ifModifiedSince is specify this header value to operate only
// on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to // on a blob if it has been modified since the specified date/time. ifUnmodifiedSince is specify this header value to
// operate only on a blob if it has not been modified since the specified date/time. ifMatches is specify an ETag value // operate only on a blob if it has not been modified since the specified date/time. ifMatch is specify an ETag value
// to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs // to operate only on blobs with a matching value. ifNoneMatch is specify an ETag value to operate only on blobs
// without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is // without a matching value. requestID is provides a client-generated, opaque value with a 1 KB character limit that is
// recorded in the analytics logs when storage analytics logging is enabled. // recorded in the analytics logs when storage analytics logging is enabled.
func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobUploadPagesResponse, error) { func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker, contentLength int64, transactionalContentMD5 []byte, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (*PageBlobUploadPagesResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: body, {targetValue: body,
constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}}, constraints: []constraint{{target: "body", name: null, rule: true, chain: nil}}},
@ -723,7 +705,7 @@ func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker
chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil { chain: []constraint{{target: "timeout", name: inclusiveMinimum, rule: 0, chain: nil}}}}}}); err != nil {
return nil, err return nil, err
} }
req, err := client.uploadPagesPreparer(body, contentLength, timeout, rangeParameter, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatches, ifNoneMatch, requestID) req, err := client.uploadPagesPreparer(body, contentLength, transactionalContentMD5, timeout, rangeParameter, leaseID, ifSequenceNumberLessThanOrEqualTo, ifSequenceNumberLessThan, ifSequenceNumberEqualTo, ifModifiedSince, ifUnmodifiedSince, ifMatch, ifNoneMatch, requestID)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -735,7 +717,7 @@ func (client pageBlobClient) UploadPages(ctx context.Context, body io.ReadSeeker
} }
// uploadPagesPreparer prepares the UploadPages request. // uploadPagesPreparer prepares the UploadPages request.
func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLength int64, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatches *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) { func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLength int64, transactionalContentMD5 []byte, timeout *int32, rangeParameter *string, leaseID *string, ifSequenceNumberLessThanOrEqualTo *int64, ifSequenceNumberLessThan *int64, ifSequenceNumberEqualTo *int64, ifModifiedSince *time.Time, ifUnmodifiedSince *time.Time, ifMatch *ETag, ifNoneMatch *ETag, requestID *string) (pipeline.Request, error) {
req, err := pipeline.NewRequest("PUT", client.url, body) req, err := pipeline.NewRequest("PUT", client.url, body)
if err != nil { if err != nil {
return req, pipeline.NewError(err, "failed to create request") return req, pipeline.NewError(err, "failed to create request")
@ -747,6 +729,9 @@ func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLeng
params.Set("comp", "page") params.Set("comp", "page")
req.URL.RawQuery = params.Encode() req.URL.RawQuery = params.Encode()
req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10)) req.Header.Set("Content-Length", strconv.FormatInt(contentLength, 10))
if transactionalContentMD5 != nil {
req.Header.Set("Content-MD5", base64.StdEncoding.EncodeToString(transactionalContentMD5))
}
if rangeParameter != nil { if rangeParameter != nil {
req.Header.Set("x-ms-range", *rangeParameter) req.Header.Set("x-ms-range", *rangeParameter)
} }
@ -768,8 +753,8 @@ func (client pageBlobClient) uploadPagesPreparer(body io.ReadSeeker, contentLeng
if ifUnmodifiedSince != nil { if ifUnmodifiedSince != nil {
req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123)) req.Header.Set("If-Unmodified-Since", (*ifUnmodifiedSince).In(gmt).Format(time.RFC1123))
} }
if ifMatches != nil { if ifMatch != nil {
req.Header.Set("If-Match", string(*ifMatches)) req.Header.Set("If-Match", string(*ifMatch))
} }
if ifNoneMatch != nil { if ifNoneMatch != nil {
req.Header.Set("If-None-Match", string(*ifNoneMatch)) req.Header.Set("If-None-Match", string(*ifNoneMatch))

View file

@ -55,7 +55,7 @@ func validateResponse(resp pipeline.Response, successStatusCodes ...int) error {
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return NewResponseError(err, resp.Response(), "failed to read response body") return err
} }
// the service code, description and details will be populated during unmarshalling // the service code, description and details will be populated during unmarshalling
responseError := NewResponseError(nil, resp.Response(), resp.Response().Status) responseError := NewResponseError(nil, resp.Response(), resp.Response().Status)

View file

@ -25,6 +25,44 @@ func newServiceClient(url url.URL, p pipeline.Pipeline) serviceClient {
return serviceClient{newManagementClient(url, p)} return serviceClient{newManagementClient(url, p)}
} }
// GetAccountInfo returns the sku name and account kind
func (client serviceClient) GetAccountInfo(ctx context.Context) (*ServiceGetAccountInfoResponse, error) {
req, err := client.getAccountInfoPreparer()
if err != nil {
return nil, err
}
resp, err := client.Pipeline().Do(ctx, responderPolicyFactory{responder: client.getAccountInfoResponder}, req)
if err != nil {
return nil, err
}
return resp.(*ServiceGetAccountInfoResponse), err
}
// getAccountInfoPreparer prepares the GetAccountInfo request.
func (client serviceClient) getAccountInfoPreparer() (pipeline.Request, error) {
req, err := pipeline.NewRequest("GET", client.url, nil)
if err != nil {
return req, pipeline.NewError(err, "failed to create request")
}
params := req.URL.Query()
params.Set("restype", "account")
params.Set("comp", "properties")
req.URL.RawQuery = params.Encode()
req.Header.Set("x-ms-version", ServiceVersion)
return req, nil
}
// getAccountInfoResponder handles the response to the GetAccountInfo request.
func (client serviceClient) getAccountInfoResponder(resp pipeline.Response) (pipeline.Response, error) {
err := validateResponse(resp, http.StatusOK)
if resp == nil {
return nil, err
}
io.Copy(ioutil.Discard, resp.Response().Body)
resp.Response().Body.Close()
return &ServiceGetAccountInfoResponse{rawResponse: resp.Response()}, err
}
// GetProperties gets the properties of a storage account's Blob service, including properties for Storage Analytics // GetProperties gets the properties of a storage account's Blob service, including properties for Storage Analytics
// and CORS (Cross-Origin Resource Sharing) rules. // and CORS (Cross-Origin Resource Sharing) rules.
// //
@ -83,7 +121,7 @@ func (client serviceClient) getPropertiesResponder(resp pipeline.Response) (pipe
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)
@ -153,7 +191,7 @@ func (client serviceClient) getStatisticsResponder(resp pipeline.Response) (pipe
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)
@ -183,7 +221,7 @@ func (client serviceClient) getStatisticsResponder(resp pipeline.Response) (pipe
// href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting // href="https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/setting-timeouts-for-blob-service-operations">Setting
// Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB // Timeouts for Blob Service Operations.</a> requestID is provides a client-generated, opaque value with a 1 KB
// character limit that is recorded in the analytics logs when storage analytics logging is enabled. // character limit that is recorded in the analytics logs when storage analytics logging is enabled.
func (client serviceClient) ListContainersSegment(ctx context.Context, prefix *string, marker *string, maxresults *int32, include ListContainersIncludeType, timeout *int32, requestID *string) (*ListContainersResponse, error) { func (client serviceClient) ListContainersSegment(ctx context.Context, prefix *string, marker *string, maxresults *int32, include ListContainersIncludeType, timeout *int32, requestID *string) (*ListContainersSegmentResponse, error) {
if err := validate([]validation{ if err := validate([]validation{
{targetValue: maxresults, {targetValue: maxresults,
constraints: []constraint{{target: "maxresults", name: null, rule: false, constraints: []constraint{{target: "maxresults", name: null, rule: false,
@ -201,7 +239,7 @@ func (client serviceClient) ListContainersSegment(ctx context.Context, prefix *s
if err != nil { if err != nil {
return nil, err return nil, err
} }
return resp.(*ListContainersResponse), err return resp.(*ListContainersSegmentResponse), err
} }
// listContainersSegmentPreparer prepares the ListContainersSegment request. // listContainersSegmentPreparer prepares the ListContainersSegment request.
@ -241,14 +279,14 @@ func (client serviceClient) listContainersSegmentResponder(resp pipeline.Respons
if resp == nil { if resp == nil {
return nil, err return nil, err
} }
result := &ListContainersResponse{rawResponse: resp.Response()} result := &ListContainersSegmentResponse{rawResponse: resp.Response()}
if err != nil { if err != nil {
return result, err return result, err
} }
defer resp.Response().Body.Close() defer resp.Response().Body.Close()
b, err := ioutil.ReadAll(resp.Response().Body) b, err := ioutil.ReadAll(resp.Response().Body)
if err != nil { if err != nil {
return result, NewResponseError(err, resp.Response(), "failed to read response body") return result, err
} }
if len(b) > 0 { if len(b) > 0 {
b = removeBOM(b) b = removeBOM(b)

View file

@ -65,7 +65,7 @@ func (r *DownloadResponse) Body(o RetryReaderOptions) io.ReadCloser {
func(ctx context.Context, getInfo HTTPGetterInfo) (*http.Response, error) { func(ctx context.Context, getInfo HTTPGetterInfo) (*http.Response, error) {
resp, err := r.b.Download(ctx, getInfo.Offset, getInfo.Count, resp, err := r.b.Download(ctx, getInfo.Offset, getInfo.Count,
BlobAccessConditions{ BlobAccessConditions{
HTTPAccessConditions: HTTPAccessConditions{IfMatch: getInfo.ETag}, ModifiedAccessConditions: ModifiedAccessConditions{IfMatch: getInfo.ETag},
}, },
false) false)
if err != nil { if err != nil {

8
vendor/vendor.json vendored
View file

@ -9,10 +9,10 @@
"revisionTime": "2018-06-07T21:19:23Z" "revisionTime": "2018-06-07T21:19:23Z"
}, },
{ {
"checksumSHA1": "5nsGu77r69lloEWbFhMof2UA9rY=", "checksumSHA1": "2tjghBLyLnO+Gry+Nu+f6y8txiw=",
"path": "github.com/Azure/azure-storage-blob-go/2018-03-28/azblob", "path": "github.com/Azure/azure-storage-blob-go/azblob",
"revision": "eaae161d9d5e07363f04ddb19d84d57efc66d1a1", "revision": "cf01652132ccc92af2b9da9d2de542b5b7eafc1d",
"revisionTime": "2018-07-12T00:56:34Z" "revisionTime": "2018-10-23T07:08:48Z"
}, },
{ {
"checksumSHA1": "QC55lHNOv1+UAL2xtIHw17MJ8J8=", "checksumSHA1": "QC55lHNOv1+UAL2xtIHw17MJ8J8=",