...

Source file src/github.com/Azure/azure-sdk-for-go/storage/blockblob.go

Documentation: github.com/Azure/azure-sdk-for-go/storage

     1  package storage
     2  
     3  // Copyright (c) Microsoft Corporation. All rights reserved.
     4  // Licensed under the MIT License. See License.txt in the project root for license information.
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/xml"
     9  	"fmt"
    10  	"io"
    11  	"net/http"
    12  	"net/url"
    13  	"strconv"
    14  	"strings"
    15  	"time"
    16  )
    17  
    18  // BlockListType is used to filter out types of blocks in a Get Blocks List call
    19  // for a block blob.
    20  //
    21  // See https://msdn.microsoft.com/en-us/library/azure/dd179400.aspx for all
    22  // block types.
    23  type BlockListType string
    24  
    25  // Filters for listing blocks in block blobs
    26  const (
    27  	BlockListTypeAll         BlockListType = "all"
    28  	BlockListTypeCommitted   BlockListType = "committed"
    29  	BlockListTypeUncommitted BlockListType = "uncommitted"
    30  )
    31  
    32  // Maximum sizes (per REST API) for various concepts
    33  const (
    34  	MaxBlobBlockSize = 100 * 1024 * 1024
    35  	MaxBlobPageSize  = 4 * 1024 * 1024
    36  )
    37  
    38  // BlockStatus defines states a block for a block blob can
    39  // be in.
    40  type BlockStatus string
    41  
    42  // List of statuses that can be used to refer to a block in a block list
    43  const (
    44  	BlockStatusUncommitted BlockStatus = "Uncommitted"
    45  	BlockStatusCommitted   BlockStatus = "Committed"
    46  	BlockStatusLatest      BlockStatus = "Latest"
    47  )
    48  
    49  // Block is used to create Block entities for Put Block List
    50  // call.
    51  type Block struct {
    52  	ID     string
    53  	Status BlockStatus
    54  }
    55  
    56  // BlockListResponse contains the response fields from Get Block List call.
    57  //
    58  // See https://msdn.microsoft.com/en-us/library/azure/dd179400.aspx
    59  type BlockListResponse struct {
    60  	XMLName           xml.Name        `xml:"BlockList"`
    61  	CommittedBlocks   []BlockResponse `xml:"CommittedBlocks>Block"`
    62  	UncommittedBlocks []BlockResponse `xml:"UncommittedBlocks>Block"`
    63  }
    64  
    65  // BlockResponse contains the block information returned
    66  // in the GetBlockListCall.
    67  type BlockResponse struct {
    68  	Name string `xml:"Name"`
    69  	Size int64  `xml:"Size"`
    70  }
    71  
    72  // CreateBlockBlob initializes an empty block blob with no blocks.
    73  //
    74  // See CreateBlockBlobFromReader for more info on creating blobs.
    75  //
    76  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Blob
    77  func (b *Blob) CreateBlockBlob(options *PutBlobOptions) error {
    78  	return b.CreateBlockBlobFromReader(nil, options)
    79  }
    80  
    81  // CreateBlockBlobFromReader initializes a block blob using data from
    82  // reader. Size must be the number of bytes read from reader. To
    83  // create an empty blob, use size==0 and reader==nil.
    84  //
    85  // Any headers set in blob.Properties or metadata in blob.Metadata
    86  // will be set on the blob.
    87  //
    88  // The API rejects requests with size > 256 MiB (but this limit is not
    89  // checked by the SDK). To write a larger blob, use CreateBlockBlob,
    90  // PutBlock, and PutBlockList.
    91  //
    92  // To create a blob from scratch, call container.GetBlobReference() to
    93  // get an empty blob, fill in blob.Properties and blob.Metadata as
    94  // appropriate then call this method.
    95  //
    96  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Blob
    97  func (b *Blob) CreateBlockBlobFromReader(blob io.Reader, options *PutBlobOptions) error {
    98  	params := url.Values{}
    99  	headers := b.Container.bsc.client.getStandardHeaders()
   100  	headers["x-ms-blob-type"] = string(BlobTypeBlock)
   101  
   102  	headers["Content-Length"] = "0"
   103  	var n int64
   104  	var err error
   105  	if blob != nil {
   106  		type lener interface {
   107  			Len() int
   108  		}
   109  		// TODO(rjeczalik): handle io.ReadSeeker, in case blob is *os.File etc.
   110  		if l, ok := blob.(lener); ok {
   111  			n = int64(l.Len())
   112  		} else {
   113  			var buf bytes.Buffer
   114  			n, err = io.Copy(&buf, blob)
   115  			if err != nil {
   116  				return err
   117  			}
   118  			blob = &buf
   119  		}
   120  
   121  		headers["Content-Length"] = strconv.FormatInt(n, 10)
   122  	}
   123  	b.Properties.ContentLength = n
   124  
   125  	headers = mergeHeaders(headers, headersFromStruct(b.Properties))
   126  	headers = b.Container.bsc.client.addMetadataToHeaders(headers, b.Metadata)
   127  
   128  	if options != nil {
   129  		params = addTimeout(params, options.Timeout)
   130  		headers = mergeHeaders(headers, headersFromStruct(*options))
   131  	}
   132  	uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
   133  
   134  	resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, blob, b.Container.bsc.auth)
   135  	if err != nil {
   136  		return err
   137  	}
   138  	return b.respondCreation(resp, BlobTypeBlock)
   139  }
   140  
   141  // PutBlockOptions includes the options for a put block operation
   142  type PutBlockOptions struct {
   143  	Timeout    uint
   144  	LeaseID    string `header:"x-ms-lease-id"`
   145  	ContentMD5 string `header:"Content-MD5"`
   146  	RequestID  string `header:"x-ms-client-request-id"`
   147  }
   148  
   149  // PutBlock saves the given data chunk to the specified block blob with
   150  // given ID.
   151  //
   152  // The API rejects chunks larger than 100 MiB (but this limit is not
   153  // checked by the SDK).
   154  //
   155  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Block
   156  func (b *Blob) PutBlock(blockID string, chunk []byte, options *PutBlockOptions) error {
   157  	return b.PutBlockWithLength(blockID, uint64(len(chunk)), bytes.NewReader(chunk), options)
   158  }
   159  
   160  // PutBlockWithLength saves the given data stream of exactly specified size to
   161  // the block blob with given ID. It is an alternative to PutBlocks where data
   162  // comes as stream but the length is known in advance.
   163  //
   164  // The API rejects requests with size > 100 MiB (but this limit is not
   165  // checked by the SDK).
   166  //
   167  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Block
   168  func (b *Blob) PutBlockWithLength(blockID string, size uint64, blob io.Reader, options *PutBlockOptions) error {
   169  	query := url.Values{
   170  		"comp":    {"block"},
   171  		"blockid": {blockID},
   172  	}
   173  	headers := b.Container.bsc.client.getStandardHeaders()
   174  	headers["Content-Length"] = fmt.Sprintf("%v", size)
   175  
   176  	if options != nil {
   177  		query = addTimeout(query, options.Timeout)
   178  		headers = mergeHeaders(headers, headersFromStruct(*options))
   179  	}
   180  	uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), query)
   181  
   182  	resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, blob, b.Container.bsc.auth)
   183  	if err != nil {
   184  		return err
   185  	}
   186  	return b.respondCreation(resp, BlobTypeBlock)
   187  }
   188  
   189  // PutBlockFromURLOptions includes the options for a put block from URL operation
   190  type PutBlockFromURLOptions struct {
   191  	PutBlockOptions
   192  
   193  	SourceContentMD5   string `header:"x-ms-source-content-md5"`
   194  	SourceContentCRC64 string `header:"x-ms-source-content-crc64"`
   195  }
   196  
   197  // PutBlockFromURL copy data of exactly specified size from specified URL to
   198  // the block blob with given ID. It is an alternative to PutBlocks where data
   199  // comes from a remote URL and the offset and length is known in advance.
   200  //
   201  // The API rejects requests with size > 100 MiB (but this limit is not
   202  // checked by the SDK).
   203  //
   204  // See https://docs.microsoft.com/en-us/rest/api/storageservices/put-block-from-url
   205  func (b *Blob) PutBlockFromURL(blockID string, blobURL string, offset int64, size uint64, options *PutBlockFromURLOptions) error {
   206  	query := url.Values{
   207  		"comp":    {"block"},
   208  		"blockid": {blockID},
   209  	}
   210  	headers := b.Container.bsc.client.getStandardHeaders()
   211  	// The value of this header must be set to zero.
   212  	// When the length is not zero, the operation will fail with the status code 400 (Bad Request).
   213  	headers["Content-Length"] = "0"
   214  	headers["x-ms-copy-source"] = blobURL
   215  	headers["x-ms-source-range"] = fmt.Sprintf("bytes=%d-%d", offset, uint64(offset)+size-1)
   216  
   217  	if options != nil {
   218  		query = addTimeout(query, options.Timeout)
   219  		headers = mergeHeaders(headers, headersFromStruct(*options))
   220  	}
   221  	uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), query)
   222  
   223  	resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, nil, b.Container.bsc.auth)
   224  	if err != nil {
   225  		return err
   226  	}
   227  	return b.respondCreation(resp, BlobTypeBlock)
   228  }
   229  
   230  // PutBlockListOptions includes the options for a put block list operation
   231  type PutBlockListOptions struct {
   232  	Timeout           uint
   233  	LeaseID           string     `header:"x-ms-lease-id"`
   234  	IfModifiedSince   *time.Time `header:"If-Modified-Since"`
   235  	IfUnmodifiedSince *time.Time `header:"If-Unmodified-Since"`
   236  	IfMatch           string     `header:"If-Match"`
   237  	IfNoneMatch       string     `header:"If-None-Match"`
   238  	RequestID         string     `header:"x-ms-client-request-id"`
   239  }
   240  
   241  // PutBlockList saves list of blocks to the specified block blob.
   242  //
   243  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Put-Block-List
   244  func (b *Blob) PutBlockList(blocks []Block, options *PutBlockListOptions) error {
   245  	params := url.Values{"comp": {"blocklist"}}
   246  	blockListXML := prepareBlockListRequest(blocks)
   247  	headers := b.Container.bsc.client.getStandardHeaders()
   248  	headers["Content-Length"] = fmt.Sprintf("%v", len(blockListXML))
   249  	headers = mergeHeaders(headers, headersFromStruct(b.Properties))
   250  	headers = b.Container.bsc.client.addMetadataToHeaders(headers, b.Metadata)
   251  
   252  	if options != nil {
   253  		params = addTimeout(params, options.Timeout)
   254  		headers = mergeHeaders(headers, headersFromStruct(*options))
   255  	}
   256  	uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
   257  
   258  	resp, err := b.Container.bsc.client.exec(http.MethodPut, uri, headers, strings.NewReader(blockListXML), b.Container.bsc.auth)
   259  	if err != nil {
   260  		return err
   261  	}
   262  	defer drainRespBody(resp)
   263  	return checkRespCode(resp, []int{http.StatusCreated})
   264  }
   265  
   266  // GetBlockListOptions includes the options for a get block list operation
   267  type GetBlockListOptions struct {
   268  	Timeout   uint
   269  	Snapshot  *time.Time
   270  	LeaseID   string `header:"x-ms-lease-id"`
   271  	RequestID string `header:"x-ms-client-request-id"`
   272  }
   273  
   274  // GetBlockList retrieves list of blocks in the specified block blob.
   275  //
   276  // See https://docs.microsoft.com/en-us/rest/api/storageservices/fileservices/Get-Block-List
   277  func (b *Blob) GetBlockList(blockType BlockListType, options *GetBlockListOptions) (BlockListResponse, error) {
   278  	params := url.Values{
   279  		"comp":          {"blocklist"},
   280  		"blocklisttype": {string(blockType)},
   281  	}
   282  	headers := b.Container.bsc.client.getStandardHeaders()
   283  
   284  	if options != nil {
   285  		params = addTimeout(params, options.Timeout)
   286  		params = addSnapshot(params, options.Snapshot)
   287  		headers = mergeHeaders(headers, headersFromStruct(*options))
   288  	}
   289  	uri := b.Container.bsc.client.getEndpoint(blobServiceName, b.buildPath(), params)
   290  
   291  	var out BlockListResponse
   292  	resp, err := b.Container.bsc.client.exec(http.MethodGet, uri, headers, nil, b.Container.bsc.auth)
   293  	if err != nil {
   294  		return out, err
   295  	}
   296  	defer resp.Body.Close()
   297  
   298  	err = xmlUnmarshal(resp.Body, &out)
   299  	return out, err
   300  }
   301  

View as plain text