Upgrade Azure Go SDK to v14.6.0

This commit is contained in:
Pengfei Ni
2018-04-24 14:31:34 +08:00
parent 3dbcd1ddce
commit b1b930a39b
134 changed files with 14672 additions and 21634 deletions

View File

@@ -31,11 +31,11 @@ go_library(
"table_batch.go",
"tableserviceclient.go",
"util.go",
"version.go",
],
importpath = "github.com/Azure/azure-sdk-for-go/storage",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/Azure/azure-sdk-for-go/version:go_default_library",
"//vendor/github.com/Azure/go-autorest/autorest:go_default_library",
"//vendor/github.com/Azure/go-autorest/autorest/azure:go_default_library",
"//vendor/github.com/marstr/guid:go_default_library",

View File

@@ -1,73 +1,18 @@
# Azure Storage SDK for Go
# Azure Storage SDK for Go (Preview)
The `github.com/Azure/azure-sdk-for-go/storage` package is used to perform REST operations against the [Azure Storage Service](https://docs.microsoft.com/en-us/azure/storage/). To manage your storage accounts (Azure Resource Manager / ARM), use the [github.com/Azure/azure-sdk-for-go/arm/storage](https://github.com/Azure/azure-sdk-for-go/tree/master/arm/storage) package. For your classic storage accounts (Azure Service Management / ASM), use [github.com/Azure/azure-sdk-for-go/management/storageservice](https://github.com/Azure/azure-sdk-for-go/tree/master/management/storageservice) package.
:exclamation: IMPORTANT: This package is in maintenance only and will be deprecated in the
future. Consider using the new package for blobs currently in preview at
[github.com/Azure/azure-storage-blob-go](https://github.com/Azure/azure-storage-blob-go).
New Table, Queue and File packages are also in development.
This package includes support for [Azure Storage Emulator](https://azure.microsoft.com/documentation/articles/storage-use-emulator/).
The `github.com/Azure/azure-sdk-for-go/storage` package is used to manage
[Azure Storage](https://docs.microsoft.com/en-us/azure/storage/) data plane
resources: containers, blobs, tables, and queues.
# Getting Started
To manage storage *accounts* use Azure Resource Manager (ARM) via the packages
at [github.com/Azure/azure-sdk-for-go/services/storage](https://github.com/Azure/azure-sdk-for-go/tree/master/services/storage).
1. Go get the SDK `go get -u github.com/Azure/azure-sdk-for-go/storage`
1. If you don't already have one, [create a Storage Account](https://docs.microsoft.com/en-us/azure/storage/storage-create-storage-account).
- Take note of your Azure Storage Account Name and Azure Storage Account Key. They'll both be necessary for using this library.
- This option is production ready, but can also be used for development.
1. (Optional, Windows only) Download and start the [Azure Storage Emulator](https://azure.microsoft.com/documentation/articles/storage-use-emulator/).
1. Checkout our existing [samples](https://github.com/Azure-Samples?q=Storage&language=go).
This package also supports the [Azure Storage
Emulator](https://azure.microsoft.com/documentation/articles/storage-use-emulator/)
(Windows only).
# Contributing
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
When contributing, please conform to the following practices:
- Run [gofmt](https://golang.org/cmd/gofmt/) to use standard go formatting.
- Run [golint](https://github.com/golang/lint) to conform to standard naming conventions.
- Run [go vet](https://golang.org/cmd/vet/) to catch common Go mistakes.
- Use [GoASTScanner/gas](https://github.com/GoASTScanner/gas) to ensure there are no common security violations in your contribution.
- Run [go test](https://golang.org/cmd/go/#hdr-Test_packages) to catch possible bugs in the code: `go test ./storage/...`.
- This project uses HTTP recordings for testing.
- The recorder should be attached to the client before calling the functions to test and later stopped.
- If you updated an existing test, its recording might need to be updated. Run `go test ./storage/... -ow -check.f TestName` to rerecord the test.
- Important note: all HTTP requests in the recording must be unique: different bodies, headers (`User-Agent`, `Authorization` and `Date` or `x-ms-date` headers are ignored), URLs and methods. As opposed to the example above, the following test is not suitable for recording:
``` go
func (s *StorageQueueSuite) TestQueueExists(c *chk.C) {
cli := getQueueClient(c)
rec := cli.client.appendRecorder(c)
defer rec.Stop()
queue := cli.GetQueueReference(queueName(c))
ok, err := queue.Exists()
c.Assert(err, chk.IsNil)
c.Assert(ok, chk.Equals, false)
c.Assert(queue.Create(nil), chk.IsNil)
defer queue.Delete(nil)
ok, err = queue.Exists() // This is the very same request as the one 5 lines above
// The test replayer gets confused and the test fails in the last line
c.Assert(err, chk.IsNil)
c.Assert(ok, chk.Equals, true)
}
```
- On the other side, this test does not repeat requests: the URLs are different.
``` go
func (s *StorageQueueSuite) TestQueueExists(c *chk.C) {
cli := getQueueClient(c)
rec := cli.client.appendRecorder(c)
defer rec.Stop()
queue1 := cli.GetQueueReference(queueName(c, "nonexistent"))
ok, err := queue1.Exists()
c.Assert(err, chk.IsNil)
c.Assert(ok, chk.Equals, false)
queue2 := cli.GetQueueReference(queueName(c, "exisiting"))
c.Assert(queue2.Create(nil), chk.IsNil)
defer queue2.Delete(nil)
ok, err = queue2.Exists()
c.Assert(err, chk.IsNil)
c.Assert(ok, chk.Equals, true)
}
```

View File

@@ -140,9 +140,9 @@ func (b *Blob) Exists() (bool, error) {
headers := b.Container.bsc.client.getStandardHeaders()
resp, err := b.Container.bsc.client.exec(http.MethodHead, uri, headers, nil, b.Container.bsc.auth)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusOK, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusOK, nil
}
}
return false, err
@@ -208,13 +208,13 @@ func (b *Blob) Get(options *GetBlobOptions) (io.ReadCloser, error) {
return nil, err
}
if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err := checkRespCode(resp, []int{http.StatusOK}); err != nil {
return nil, err
}
if err := b.writeProperties(resp.headers, true); err != nil {
return resp.body, err
if err := b.writeProperties(resp.Header, true); err != nil {
return resp.Body, err
}
return resp.body, nil
return resp.Body, nil
}
// GetRange reads the specified range of a blob to a stream. The bytesRange
@@ -228,18 +228,18 @@ func (b *Blob) GetRange(options *GetBlobRangeOptions) (io.ReadCloser, error) {
return nil, err
}
if err := checkRespCode(resp.statusCode, []int{http.StatusPartialContent}); err != nil {
if err := checkRespCode(resp, []int{http.StatusPartialContent}); err != nil {
return nil, err
}
// Content-Length header should not be updated, as the service returns the range length
// (which is not alwys the full blob length)
if err := b.writeProperties(resp.headers, false); err != nil {
return resp.body, err
if err := b.writeProperties(resp.Header, false); err != nil {
return resp.Body, err
}
return resp.body, nil
return resp.Body, nil
}
func (b *Blob) getRange(options *GetBlobRangeOptions) (*storageResponse, error) {
func (b *Blob) getRange(options *GetBlobRangeOptions) (*http.Response, error) {
params := url.Values{}
headers := b.Container.bsc.client.getStandardHeaders()
@@ -293,13 +293,13 @@ func (b *Blob) CreateSnapshot(options *SnapshotOptions) (snapshotTimestamp *time
if err != nil || resp == nil {
return nil, err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err := checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil {
if err := checkRespCode(resp, []int{http.StatusCreated}); err != nil {
return nil, err
}
snapshotResponse := resp.headers.Get(http.CanonicalHeaderKey("x-ms-snapshot"))
snapshotResponse := resp.Header.Get(http.CanonicalHeaderKey("x-ms-snapshot"))
if snapshotResponse != "" {
snapshotTimestamp, err := time.Parse(time.RFC3339, snapshotResponse)
if err != nil {
@@ -340,12 +340,12 @@ func (b *Blob) GetProperties(options *GetBlobPropertiesOptions) error {
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
return err
}
return b.writeProperties(resp.headers, true)
return b.writeProperties(resp.Header, true)
}
func (b *Blob) writeProperties(h http.Header, includeContentLen bool) error {
@@ -463,8 +463,8 @@ func (b *Blob) SetProperties(options *SetBlobPropertiesOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusOK})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusOK})
}
// SetBlobMetadataOptions includes the options for a set blob metadata operation
@@ -501,8 +501,8 @@ func (b *Blob) SetMetadata(options *SetBlobMetadataOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusOK})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusOK})
}
// GetBlobMetadataOptions includes the options for a get blob metadata operation
@@ -538,13 +538,13 @@ func (b *Blob) GetMetadata(options *GetBlobMetadataOptions) error {
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err := checkRespCode(resp, []int{http.StatusOK}); err != nil {
return err
}
b.writeMetadata(resp.headers)
b.writeMetadata(resp.Header)
return nil
}
@@ -574,8 +574,8 @@ func (b *Blob) Delete(options *DeleteBlobOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusAccepted})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusAccepted})
}
// DeleteIfExists deletes the given blob from the specified container If the
@@ -585,15 +585,15 @@ func (b *Blob) Delete(options *DeleteBlobOptions) error {
func (b *Blob) DeleteIfExists(options *DeleteBlobOptions) (bool, error) {
resp, err := b.delete(options)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusAccepted, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusAccepted, nil
}
}
return false, err
}
func (b *Blob) delete(options *DeleteBlobOptions) (*storageResponse, error) {
func (b *Blob) delete(options *DeleteBlobOptions) (*http.Response, error) {
params := url.Values{}
headers := b.Container.bsc.client.getStandardHeaders()
@@ -621,9 +621,9 @@ func pathForResource(container, name string) string {
return fmt.Sprintf("/%s", container)
}
func (b *Blob) respondCreation(resp *storageResponse, bt BlobType) error {
readAndCloseBody(resp.body)
err := checkRespCode(resp.statusCode, []int{http.StatusCreated})
func (b *Blob) respondCreation(resp *http.Response, bt BlobType) error {
defer readAndCloseBody(resp.Body)
err := checkRespCode(resp, []int{http.StatusCreated})
if err != nil {
return err
}

View File

@@ -121,6 +121,10 @@ func (c *Client) blobAndFileSASURI(options SASOptions, uri, permissions, canonic
"sig": {sig},
}
if start != "" {
sasParams.Add("st", start)
}
if c.apiVersion >= "2015-04-05" {
if protocols != "" {
sasParams.Add("spr", protocols)

View File

@@ -108,8 +108,8 @@ func (b BlobStorageClient) ListContainers(params ListContainersParameters) (*Con
if err != nil {
return nil, err
}
defer resp.body.Close()
err = xmlUnmarshal(resp.body, &outAlias)
defer resp.Body.Close()
err = xmlUnmarshal(resp.Body, &outAlias)
if err != nil {
return nil, err
}

View File

@@ -229,8 +229,8 @@ func (b *Blob) PutBlockList(blocks []Block, options *PutBlockListOptions) error
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusCreated})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusCreated})
}
// GetBlockListOptions includes the options for a get block list operation
@@ -263,8 +263,8 @@ func (b *Blob) GetBlockList(blockType BlockListType, options *GetBlockListOption
if err != nil {
return out, err
}
defer resp.body.Close()
defer resp.Body.Close()
err = xmlUnmarshal(resp.body, &out)
err = xmlUnmarshal(resp.Body, &out)
return out, err
}

View File

@@ -17,7 +17,6 @@ package storage
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
"encoding/xml"
@@ -35,6 +34,7 @@ import (
"strings"
"time"
"github.com/Azure/azure-sdk-for-go/version"
"github.com/Azure/go-autorest/autorest"
"github.com/Azure/go-autorest/autorest/azure"
)
@@ -151,14 +151,8 @@ type Client struct {
accountSASToken url.Values
}
type storageResponse struct {
statusCode int
headers http.Header
body io.ReadCloser
}
type odataResponse struct {
storageResponse
resp *http.Response
odata odataErrorWrapper
}
@@ -198,6 +192,7 @@ type odataErrorWrapper struct {
type UnexpectedStatusCodeError struct {
allowed []int
got int
inner error
}
func (e UnexpectedStatusCodeError) Error() string {
@@ -208,7 +203,7 @@ func (e UnexpectedStatusCodeError) Error() string {
for _, v := range e.allowed {
expected = append(expected, s(v))
}
return fmt.Sprintf("storage: status code from service response is %s; was expecting %s", got, strings.Join(expected, " or "))
return fmt.Sprintf("storage: status code from service response is %s; was expecting %s. Inner error: %+v", got, strings.Join(expected, " or "), e.inner)
}
// Got is the actual status code returned by Azure.
@@ -216,6 +211,11 @@ func (e UnexpectedStatusCodeError) Got() int {
return e.got
}
// Inner returns any inner error info.
func (e UnexpectedStatusCodeError) Inner() error {
return e.inner
}
// NewClientFromConnectionString creates a Client from the connection string.
func NewClientFromConnectionString(input string) (Client, error) {
// build a map of connection string key/value pairs
@@ -415,7 +415,7 @@ func (c Client) getDefaultUserAgent() string {
runtime.Version(),
runtime.GOARCH,
runtime.GOOS,
sdkVersion,
version.Number,
c.apiVersion,
)
}
@@ -704,7 +704,7 @@ func (c Client) getStandardHeaders() map[string]string {
}
}
func (c Client) exec(verb, url string, headers map[string]string, body io.Reader, auth authentication) (*storageResponse, error) {
func (c Client) exec(verb, url string, headers map[string]string, body io.Reader, auth authentication) (*http.Response, error) {
headers, err := c.addAuthorizationHeader(verb, url, headers, auth)
if err != nil {
return nil, err
@@ -742,48 +742,10 @@ func (c Client) exec(verb, url string, headers map[string]string, body io.Reader
}
if resp.StatusCode >= 400 && resp.StatusCode <= 505 {
var respBody []byte
respBody, err = readAndCloseBody(resp.Body)
if err != nil {
return nil, err
}
requestID, date, version := getDebugHeaders(resp.Header)
if len(respBody) == 0 {
// no error in response body, might happen in HEAD requests
err = serviceErrFromStatusCode(resp.StatusCode, resp.Status, requestID, date, version)
} else {
storageErr := AzureStorageServiceError{
StatusCode: resp.StatusCode,
RequestID: requestID,
Date: date,
APIVersion: version,
}
// response contains storage service error object, unmarshal
if resp.Header.Get("Content-Type") == "application/xml" {
errIn := serviceErrFromXML(respBody, &storageErr)
if err != nil { // error unmarshaling the error response
err = errIn
}
} else {
errIn := serviceErrFromJSON(respBody, &storageErr)
if err != nil { // error unmarshaling the error response
err = errIn
}
}
err = storageErr
}
return &storageResponse{
statusCode: resp.StatusCode,
headers: resp.Header,
body: ioutil.NopCloser(bytes.NewReader(respBody)), /* restore the body */
}, err
return resp, getErrorFromResponse(resp)
}
return &storageResponse{
statusCode: resp.StatusCode,
headers: resp.Header,
body: resp.Body}, nil
return resp, nil
}
func (c Client) execInternalJSONCommon(verb, url string, headers map[string]string, body io.Reader, auth authentication) (*odataResponse, *http.Request, *http.Response, error) {
@@ -802,10 +764,7 @@ func (c Client) execInternalJSONCommon(verb, url string, headers map[string]stri
return nil, nil, nil, err
}
respToRet := &odataResponse{}
respToRet.body = resp.Body
respToRet.statusCode = resp.StatusCode
respToRet.headers = resp.Header
respToRet := &odataResponse{resp: resp}
statusCode := resp.StatusCode
if statusCode >= 400 && statusCode <= 505 {
@@ -890,7 +849,7 @@ func genChangesetReader(req *http.Request, respToRet *odataResponse, batchPartBu
if err != nil {
return err
}
respToRet.statusCode = changesetResp.StatusCode
respToRet.resp = changesetResp
}
return nil
@@ -963,13 +922,18 @@ func (e AzureStorageServiceError) Error() string {
// checkRespCode returns UnexpectedStatusError if the given response code is not
// one of the allowed status codes; otherwise nil.
func checkRespCode(respCode int, allowed []int) error {
func checkRespCode(resp *http.Response, allowed []int) error {
for _, v := range allowed {
if respCode == v {
if resp.StatusCode == v {
return nil
}
}
return UnexpectedStatusCodeError{allowed, respCode}
err := getErrorFromResponse(resp)
return UnexpectedStatusCodeError{
allowed: allowed,
got: resp.StatusCode,
inner: err,
}
}
func (c Client) addMetadataToHeaders(h map[string]string, metadata map[string]string) map[string]string {
@@ -986,3 +950,37 @@ func getDebugHeaders(h http.Header) (requestID, date, version string) {
date = h.Get("Date")
return
}
func getErrorFromResponse(resp *http.Response) error {
respBody, err := readAndCloseBody(resp.Body)
if err != nil {
return err
}
requestID, date, version := getDebugHeaders(resp.Header)
if len(respBody) == 0 {
// no error in response body, might happen in HEAD requests
err = serviceErrFromStatusCode(resp.StatusCode, resp.Status, requestID, date, version)
} else {
storageErr := AzureStorageServiceError{
StatusCode: resp.StatusCode,
RequestID: requestID,
Date: date,
APIVersion: version,
}
// response contains storage service error object, unmarshal
if resp.Header.Get("Content-Type") == "application/xml" {
errIn := serviceErrFromXML(respBody, &storageErr)
if err != nil { // error unmarshaling the error response
err = errIn
}
} else {
errIn := serviceErrFromJSON(respBody, &storageErr)
if err != nil { // error unmarshaling the error response
err = errIn
}
}
err = storageErr
}
return err
}

View File

@@ -16,7 +16,6 @@ package storage
import (
"encoding/xml"
"errors"
"fmt"
"io"
"net/http"
@@ -95,11 +94,12 @@ func (c *Container) GetSASURI(options ContainerSASOptions) (string, error) {
// ContainerProperties contains various properties of a container returned from
// various endpoints like ListContainers.
type ContainerProperties struct {
LastModified string `xml:"Last-Modified"`
Etag string `xml:"Etag"`
LeaseStatus string `xml:"LeaseStatus"`
LeaseState string `xml:"LeaseState"`
LeaseDuration string `xml:"LeaseDuration"`
LastModified string `xml:"Last-Modified"`
Etag string `xml:"Etag"`
LeaseStatus string `xml:"LeaseStatus"`
LeaseState string `xml:"LeaseState"`
LeaseDuration string `xml:"LeaseDuration"`
PublicAccess ContainerAccessType `xml:"PublicAccess"`
}
// ContainerListResponse contains the response fields from
@@ -258,8 +258,8 @@ func (c *Container) Create(options *CreateContainerOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusCreated})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusCreated})
}
// CreateIfNotExists creates a blob container if it does not exist. Returns
@@ -267,15 +267,15 @@ func (c *Container) Create(options *CreateContainerOptions) error {
func (c *Container) CreateIfNotExists(options *CreateContainerOptions) (bool, error) {
resp, err := c.create(options)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict {
return resp.statusCode == http.StatusCreated, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict {
return resp.StatusCode == http.StatusCreated, nil
}
}
return false, err
}
func (c *Container) create(options *CreateContainerOptions) (*storageResponse, error) {
func (c *Container) create(options *CreateContainerOptions) (*http.Response, error) {
query := url.Values{"restype": {"container"}}
headers := c.bsc.client.getStandardHeaders()
headers = c.bsc.client.addMetadataToHeaders(headers, c.Metadata)
@@ -307,9 +307,9 @@ func (c *Container) Exists() (bool, error) {
resp, err := c.bsc.client.exec(http.MethodHead, uri, headers, nil, c.bsc.auth)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusOK, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusOK, nil
}
}
return false, err
@@ -349,13 +349,8 @@ func (c *Container) SetPermissions(permissions ContainerPermissions, options *Se
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
return errors.New("Unable to set permissions")
}
return nil
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusOK})
}
// GetContainerPermissionOptions includes options for a get container permissions operation
@@ -385,14 +380,14 @@ func (c *Container) GetPermissions(options *GetContainerPermissionOptions) (*Con
if err != nil {
return nil, err
}
defer resp.body.Close()
defer resp.Body.Close()
var ap AccessPolicy
err = xmlUnmarshal(resp.body, &ap.SignedIdentifiersList)
err = xmlUnmarshal(resp.Body, &ap.SignedIdentifiersList)
if err != nil {
return nil, err
}
return buildAccessPolicy(ap, &resp.headers), nil
return buildAccessPolicy(ap, &resp.Header), nil
}
func buildAccessPolicy(ap AccessPolicy, headers *http.Header) *ContainerPermissions {
@@ -436,8 +431,8 @@ func (c *Container) Delete(options *DeleteContainerOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusAccepted})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusAccepted})
}
// DeleteIfExists deletes the container with given name on the storage
@@ -449,15 +444,15 @@ func (c *Container) Delete(options *DeleteContainerOptions) error {
func (c *Container) DeleteIfExists(options *DeleteContainerOptions) (bool, error) {
resp, err := c.delete(options)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusAccepted, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusAccepted, nil
}
}
return false, err
}
func (c *Container) delete(options *DeleteContainerOptions) (*storageResponse, error) {
func (c *Container) delete(options *DeleteContainerOptions) (*http.Response, error) {
query := url.Values{"restype": {"container"}}
headers := c.bsc.client.getStandardHeaders()
@@ -497,9 +492,9 @@ func (c *Container) ListBlobs(params ListBlobsParameters) (BlobListResponse, err
if err != nil {
return out, err
}
defer resp.body.Close()
defer resp.Body.Close()
err = xmlUnmarshal(resp.body, &out)
err = xmlUnmarshal(resp.Body, &out)
for i := range out.Blobs {
out.Blobs[i].Container = c
}
@@ -540,8 +535,8 @@ func (c *Container) SetMetadata(options *ContainerMetadataOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusOK})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusOK})
}
// GetMetadata returns all user-defined metadata for the specified container.
@@ -568,12 +563,12 @@ func (c *Container) GetMetadata(options *ContainerMetadataOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
defer readAndCloseBody(resp.Body)
if err := checkRespCode(resp, []int{http.StatusOK}); err != nil {
return err
}
c.writeMetadata(resp.headers)
c.writeMetadata(resp.Header)
return nil
}
@@ -612,3 +607,34 @@ func (capd *ContainerAccessPolicy) generateContainerPermissions() (permissions s
return permissions
}
// GetProperties updated the properties of the container.
//
// See https://docs.microsoft.com/en-us/rest/api/storageservices/get-container-properties
func (c *Container) GetProperties() error {
params := url.Values{
"restype": {"container"},
}
headers := c.bsc.client.getStandardHeaders()
uri := c.bsc.client.getEndpoint(blobServiceName, c.buildPath(), params)
resp, err := c.bsc.client.exec(http.MethodGet, uri, headers, nil, c.bsc.auth)
if err != nil {
return err
}
defer resp.Body.Close()
if err := checkRespCode(resp, []int{http.StatusOK}); err != nil {
return err
}
// update properties
c.Properties.Etag = resp.Header.Get(headerEtag)
c.Properties.LeaseStatus = resp.Header.Get("x-ms-lease-status")
c.Properties.LeaseState = resp.Header.Get("x-ms-lease-state")
c.Properties.LeaseDuration = resp.Header.Get("x-ms-lease-duration")
c.Properties.LastModified = resp.Header.Get("Last-Modified")
c.Properties.PublicAccess = ContainerAccessType(resp.Header.Get(ContainerAccessHeader))
return nil
}

View File

@@ -110,13 +110,13 @@ func (b *Blob) StartCopy(sourceBlob string, options *CopyOptions) (string, error
if err != nil {
return "", err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err := checkRespCode(resp.statusCode, []int{http.StatusAccepted, http.StatusCreated}); err != nil {
if err := checkRespCode(resp, []int{http.StatusAccepted, http.StatusCreated}); err != nil {
return "", err
}
copyID := resp.headers.Get("x-ms-copy-id")
copyID := resp.Header.Get("x-ms-copy-id")
if copyID == "" {
return "", errors.New("Got empty copy id header")
}
@@ -152,8 +152,8 @@ func (b *Blob) AbortCopy(copyID string, options *AbortCopyOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusNoContent})
}
// WaitForCopy loops until a BlobCopy operation is completed (or fails with error)
@@ -223,13 +223,13 @@ func (b *Blob) IncrementalCopyBlob(sourceBlobURL string, snapshotTime time.Time,
if err != nil {
return "", err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err := checkRespCode(resp.statusCode, []int{http.StatusAccepted}); err != nil {
if err := checkRespCode(resp, []int{http.StatusAccepted}); err != nil {
return "", err
}
copyID := resp.headers.Get("x-ms-copy-id")
copyID := resp.Header.Get("x-ms-copy-id")
if copyID == "" {
return "", errors.New("Got empty copy id header")
}

View File

@@ -107,10 +107,10 @@ func (d *Directory) CreateIfNotExists(options *FileRequestOptions) (bool, error)
params := prepareOptions(options)
resp, err := d.fsc.createResourceNoClose(d.buildPath(), resourceDirectory, params, nil)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict {
if resp.statusCode == http.StatusCreated {
d.updateEtagAndLastModified(resp.headers)
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict {
if resp.StatusCode == http.StatusCreated {
d.updateEtagAndLastModified(resp.Header)
return true, nil
}
@@ -135,9 +135,9 @@ func (d *Directory) Delete(options *FileRequestOptions) error {
func (d *Directory) DeleteIfExists(options *FileRequestOptions) (bool, error) {
resp, err := d.fsc.deleteResourceNoClose(d.buildPath(), resourceDirectory, options)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusAccepted, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusAccepted, nil
}
}
return false, err
@@ -200,9 +200,9 @@ func (d *Directory) ListDirsAndFiles(params ListDirsAndFilesParameters) (*DirsAn
return nil, err
}
defer resp.body.Close()
defer resp.Body.Close()
var out DirsAndFilesListResponse
err = xmlUnmarshal(resp.body, &out)
err = xmlUnmarshal(resp.Body, &out)
return &out, err
}

View File

@@ -16,6 +16,7 @@ package storage
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
@@ -111,13 +112,13 @@ func (e *Entity) Get(timeout uint, ml MetadataLevel, options *GetEntityOptions)
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
return err
}
respBody, err := ioutil.ReadAll(resp.body)
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
@@ -153,22 +154,21 @@ func (e *Entity) Insert(ml MetadataLevel, options *EntityOptions) error {
if err != nil {
return err
}
defer resp.body.Close()
data, err := ioutil.ReadAll(resp.body)
if err != nil {
return err
}
defer readAndCloseBody(resp.Body)
if ml != EmptyPayload {
if err = checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil {
if err = checkRespCode(resp, []int{http.StatusCreated}); err != nil {
return err
}
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
if err = e.UnmarshalJSON(data); err != nil {
return err
}
} else {
if err = checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil {
if err = checkRespCode(resp, []int{http.StatusNoContent}); err != nil {
return err
}
}
@@ -207,18 +207,18 @@ func (e *Entity) Delete(force bool, options *EntityOptions) error {
uri := e.Table.tsc.client.getEndpoint(tableServiceName, e.buildPath(), query)
resp, err := e.Table.tsc.client.exec(http.MethodDelete, uri, headers, nil, e.Table.tsc.auth)
if err != nil {
if resp.statusCode == http.StatusPreconditionFailed {
if resp.StatusCode == http.StatusPreconditionFailed {
return fmt.Errorf(etagErrorTemplate, err)
}
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err = checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil {
if err = checkRespCode(resp, []int{http.StatusNoContent}); err != nil {
return err
}
return e.updateTimestamp(resp.headers)
return e.updateTimestamp(resp.Header)
}
// InsertOrReplace inserts an entity or replaces the existing one.
@@ -247,7 +247,7 @@ func (e *Entity) MarshalJSON() ([]byte, error) {
switch t := v.(type) {
case []byte:
completeMap[typeKey] = OdataBinary
completeMap[k] = string(t)
completeMap[k] = t
case time.Time:
completeMap[typeKey] = OdataDateTime
completeMap[k] = t.Format(time.RFC3339Nano)
@@ -321,7 +321,10 @@ func (e *Entity) UnmarshalJSON(data []byte) error {
}
switch v {
case OdataBinary:
props[valueKey] = []byte(str)
props[valueKey], err = base64.StdEncoding.DecodeString(str)
if err != nil {
return fmt.Errorf(errorTemplate, err)
}
case OdataDateTime:
t, err := time.Parse("2006-01-02T15:04:05Z", str)
if err != nil {
@@ -396,13 +399,13 @@ func (e *Entity) insertOr(verb string, options *EntityOptions) error {
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err = checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil {
if err = checkRespCode(resp, []int{http.StatusNoContent}); err != nil {
return err
}
return e.updateEtagAndTimestamp(resp.headers)
return e.updateEtagAndTimestamp(resp.Header)
}
func (e *Entity) updateMerge(force bool, verb string, options *EntityOptions) error {
@@ -420,18 +423,18 @@ func (e *Entity) updateMerge(force bool, verb string, options *EntityOptions) er
uri := e.Table.tsc.client.getEndpoint(tableServiceName, e.buildPath(), query)
resp, err := e.Table.tsc.client.exec(verb, uri, headers, bytes.NewReader(body), e.Table.tsc.auth)
if err != nil {
if resp.statusCode == http.StatusPreconditionFailed {
if resp.StatusCode == http.StatusPreconditionFailed {
return fmt.Errorf(etagErrorTemplate, err)
}
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err = checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil {
if err = checkRespCode(resp, []int{http.StatusNoContent}); err != nil {
return err
}
return e.updateEtagAndTimestamp(resp.headers)
return e.updateEtagAndTimestamp(resp.Header)
}
func stringFromMap(props map[string]interface{}, key string) string {

View File

@@ -28,6 +28,10 @@ import (
const fourMB = uint64(4194304)
const oneTB = uint64(1099511627776)
// Export maximum range and file sizes
const MaxRangeSize = fourMB
const MaxFileSize = oneTB
// File represents a file on a share.
type File struct {
fsc *FileServiceClient
@@ -183,9 +187,9 @@ func (f *File) Delete(options *FileRequestOptions) error {
func (f *File) DeleteIfExists(options *FileRequestOptions) (bool, error) {
resp, err := f.fsc.deleteResourceNoClose(f.buildPath(), resourceFile, options)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusAccepted, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusAccepted, nil
}
}
return false, err
@@ -207,11 +211,11 @@ func (f *File) DownloadToStream(options *FileRequestOptions) (io.ReadCloser, err
return nil, err
}
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
readAndCloseBody(resp.body)
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
readAndCloseBody(resp.Body)
return nil, err
}
return resp.body, nil
return resp.Body, nil
}
// DownloadRangeToStream operation downloads the specified range of this file with optional MD5 hash.
@@ -237,14 +241,14 @@ func (f *File) DownloadRangeToStream(fileRange FileRange, options *GetFileOption
return fs, err
}
if err = checkRespCode(resp.statusCode, []int{http.StatusOK, http.StatusPartialContent}); err != nil {
readAndCloseBody(resp.body)
if err = checkRespCode(resp, []int{http.StatusOK, http.StatusPartialContent}); err != nil {
readAndCloseBody(resp.Body)
return fs, err
}
fs.Body = resp.body
fs.Body = resp.Body
if options != nil && options.GetContentMD5 {
fs.ContentMD5 = resp.headers.Get("Content-MD5")
fs.ContentMD5 = resp.Header.Get("Content-MD5")
}
return fs, nil
}
@@ -310,20 +314,20 @@ func (f *File) ListRanges(options *ListRangesOptions) (*FileRanges, error) {
return nil, err
}
defer resp.body.Close()
defer resp.Body.Close()
var cl uint64
cl, err = strconv.ParseUint(resp.headers.Get("x-ms-content-length"), 10, 64)
cl, err = strconv.ParseUint(resp.Header.Get("x-ms-content-length"), 10, 64)
if err != nil {
ioutil.ReadAll(resp.body)
ioutil.ReadAll(resp.Body)
return nil, err
}
var out FileRanges
out.ContentLength = cl
out.ETag = resp.headers.Get("ETag")
out.LastModified = resp.headers.Get("Last-Modified")
out.ETag = resp.Header.Get("ETag")
out.LastModified = resp.Header.Get("Last-Modified")
err = xmlUnmarshal(resp.body, &out)
err = xmlUnmarshal(resp.Body, &out)
return &out, err
}
@@ -371,8 +375,8 @@ func (f *File) modifyRange(bytes io.Reader, fileRange FileRange, timeout *uint,
if err != nil {
return nil, err
}
defer readAndCloseBody(resp.body)
return resp.headers, checkRespCode(resp.statusCode, []int{http.StatusCreated})
defer readAndCloseBody(resp.Body)
return resp.Header, checkRespCode(resp, []int{http.StatusCreated})
}
// SetMetadata replaces the metadata for this file.

View File

@@ -154,8 +154,8 @@ func (f FileServiceClient) ListShares(params ListSharesParameters) (*ShareListRe
if err != nil {
return nil, err
}
defer resp.body.Close()
err = xmlUnmarshal(resp.body, &out)
defer resp.Body.Close()
err = xmlUnmarshal(resp.Body, &out)
// assign our client to the newly created Share objects
for i := range out.Shares {
@@ -179,7 +179,7 @@ func (f *FileServiceClient) SetServiceProperties(props ServiceProperties) error
}
// retrieves directory or share content
func (f FileServiceClient) listContent(path string, params url.Values, extraHeaders map[string]string) (*storageResponse, error) {
func (f FileServiceClient) listContent(path string, params url.Values, extraHeaders map[string]string) (*http.Response, error) {
if err := f.checkForStorageEmulator(); err != nil {
return nil, err
}
@@ -193,8 +193,8 @@ func (f FileServiceClient) listContent(path string, params url.Values, extraHead
return nil, err
}
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
readAndCloseBody(resp.body)
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
readAndCloseBody(resp.Body)
return nil, err
}
@@ -212,9 +212,9 @@ func (f FileServiceClient) resourceExists(path string, res resourceType) (bool,
resp, err := f.client.exec(http.MethodHead, uri, headers, nil, f.auth)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusOK, resp.headers, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusOK, resp.Header, nil
}
}
return false, nil, err
@@ -226,12 +226,12 @@ func (f FileServiceClient) createResource(path string, res resourceType, urlPara
if err != nil {
return nil, err
}
defer readAndCloseBody(resp.body)
return resp.headers, checkRespCode(resp.statusCode, expectedResponseCodes)
defer readAndCloseBody(resp.Body)
return resp.Header, checkRespCode(resp, expectedResponseCodes)
}
// creates a resource depending on the specified resource type, doesn't close the response body
func (f FileServiceClient) createResourceNoClose(path string, res resourceType, urlParams url.Values, extraHeaders map[string]string) (*storageResponse, error) {
func (f FileServiceClient) createResourceNoClose(path string, res resourceType, urlParams url.Values, extraHeaders map[string]string) (*http.Response, error) {
if err := f.checkForStorageEmulator(); err != nil {
return nil, err
}
@@ -251,17 +251,17 @@ func (f FileServiceClient) getResourceHeaders(path string, comp compType, res re
if err != nil {
return nil, err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
return nil, err
}
return resp.headers, nil
return resp.Header, nil
}
// gets the specified resource, doesn't close the response body
func (f FileServiceClient) getResourceNoClose(path string, comp compType, res resourceType, params url.Values, verb string, extraHeaders map[string]string) (*storageResponse, error) {
func (f FileServiceClient) getResourceNoClose(path string, comp compType, res resourceType, params url.Values, verb string, extraHeaders map[string]string) (*http.Response, error) {
if err := f.checkForStorageEmulator(); err != nil {
return nil, err
}
@@ -279,12 +279,12 @@ func (f FileServiceClient) deleteResource(path string, res resourceType, options
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusAccepted})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusAccepted})
}
// deletes the resource and returns the response, doesn't close the response body
func (f FileServiceClient) deleteResourceNoClose(path string, res resourceType, options *FileRequestOptions) (*storageResponse, error) {
func (f FileServiceClient) deleteResourceNoClose(path string, res resourceType, options *FileRequestOptions) (*http.Response, error) {
if err := f.checkForStorageEmulator(); err != nil {
return nil, err
}
@@ -323,9 +323,9 @@ func (f FileServiceClient) setResourceHeaders(path string, comp compType, res re
if err != nil {
return nil, err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
return resp.headers, checkRespCode(resp.statusCode, []int{http.StatusOK})
return resp.Header, checkRespCode(resp, []int{http.StatusOK})
}
//checkForStorageEmulator determines if the client is setup for use with

View File

@@ -53,13 +53,13 @@ func (b *Blob) leaseCommonPut(headers map[string]string, expectedStatus int, opt
if err != nil {
return nil, err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err := checkRespCode(resp.statusCode, []int{expectedStatus}); err != nil {
if err := checkRespCode(resp, []int{expectedStatus}); err != nil {
return nil, err
}
return resp.headers, nil
return resp.Header, nil
}
// LeaseOptions includes options for all operations regarding leasing blobs

View File

@@ -78,13 +78,16 @@ func (m *Message) Put(options *PutMessageOptions) error {
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
err = xmlUnmarshal(resp.body, m)
defer readAndCloseBody(resp.Body)
err = checkRespCode(resp, []int{http.StatusCreated})
if err != nil {
return err
}
return checkRespCode(resp.statusCode, []int{http.StatusCreated})
err = xmlUnmarshal(resp.Body, m)
if err != nil {
return err
}
return nil
}
// UpdateMessageOptions is the set of options can be specified for Update Messsage
@@ -125,10 +128,10 @@ func (m *Message) Update(options *UpdateMessageOptions) error {
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
m.PopReceipt = resp.headers.Get("x-ms-popreceipt")
nextTimeStr := resp.headers.Get("x-ms-time-next-visible")
m.PopReceipt = resp.Header.Get("x-ms-popreceipt")
nextTimeStr := resp.Header.Get("x-ms-time-next-visible")
if nextTimeStr != "" {
nextTime, err := time.Parse(time.RFC1123, nextTimeStr)
if err != nil {
@@ -137,7 +140,7 @@ func (m *Message) Update(options *UpdateMessageOptions) error {
m.NextVisible = TimeRFC1123(nextTime)
}
return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
return checkRespCode(resp, []int{http.StatusNoContent})
}
// Delete operation deletes the specified message.
@@ -157,8 +160,8 @@ func (m *Message) Delete(options *QueueServiceOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusNoContent})
}
type putMessageRequest struct {

View File

@@ -121,9 +121,8 @@ func (b *Blob) modifyRange(blobRange BlobRange, bytes io.Reader, options *PutPag
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusCreated})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusCreated})
}
// GetPageRangesOptions includes the options for a get page ranges operation
@@ -161,12 +160,12 @@ func (b *Blob) GetPageRanges(options *GetPageRangesOptions) (GetPageRangesRespon
if err != nil {
return out, err
}
defer resp.body.Close()
defer readAndCloseBody(resp.Body)
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
return out, err
}
err = xmlUnmarshal(resp.body, &out)
err = xmlUnmarshal(resp.Body, &out)
return out, err
}

View File

@@ -16,7 +16,6 @@ package storage
import (
"encoding/xml"
"errors"
"fmt"
"io"
"net/http"
@@ -92,8 +91,8 @@ func (q *Queue) Create(options *QueueServiceOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusCreated})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusCreated})
}
// Delete operation permanently deletes the specified queue.
@@ -112,8 +111,8 @@ func (q *Queue) Delete(options *QueueServiceOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusNoContent})
}
// Exists returns true if a queue with given name exists.
@@ -121,10 +120,11 @@ func (q *Queue) Exists() (bool, error) {
uri := q.qsc.client.getEndpoint(queueServiceName, q.buildPath(), url.Values{"comp": {"metadata"}})
resp, err := q.qsc.client.exec(http.MethodGet, uri, q.qsc.client.getStandardHeaders(), nil, q.qsc.auth)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusOK || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusOK, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusOK || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusOK, nil
}
err = getErrorFromResponse(resp)
}
return false, err
}
@@ -148,8 +148,8 @@ func (q *Queue) SetMetadata(options *QueueServiceOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusNoContent})
}
// GetMetadata operation retrieves user-defined metadata and queue
@@ -175,13 +175,13 @@ func (q *Queue) GetMetadata(options *QueueServiceOptions) error {
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err := checkRespCode(resp, []int{http.StatusOK}); err != nil {
return err
}
aproxMessagesStr := resp.headers.Get(http.CanonicalHeaderKey(approximateMessagesCountHeader))
aproxMessagesStr := resp.Header.Get(http.CanonicalHeaderKey(approximateMessagesCountHeader))
if aproxMessagesStr != "" {
aproxMessages, err := strconv.ParseUint(aproxMessagesStr, 10, 64)
if err != nil {
@@ -190,7 +190,7 @@ func (q *Queue) GetMetadata(options *QueueServiceOptions) error {
q.AproxMessageCount = aproxMessages
}
q.Metadata = getMetadataFromHeaders(resp.headers)
q.Metadata = getMetadataFromHeaders(resp.Header)
return nil
}
@@ -241,10 +241,10 @@ func (q *Queue) GetMessages(options *GetMessagesOptions) ([]Message, error) {
if err != nil {
return []Message{}, err
}
defer readAndCloseBody(resp.body)
defer resp.Body.Close()
var out messages
err = xmlUnmarshal(resp.body, &out)
err = xmlUnmarshal(resp.Body, &out)
if err != nil {
return []Message{}, err
}
@@ -284,10 +284,10 @@ func (q *Queue) PeekMessages(options *PeekMessagesOptions) ([]Message, error) {
if err != nil {
return []Message{}, err
}
defer readAndCloseBody(resp.body)
defer resp.Body.Close()
var out messages
err = xmlUnmarshal(resp.body, &out)
err = xmlUnmarshal(resp.Body, &out)
if err != nil {
return []Message{}, err
}
@@ -314,8 +314,8 @@ func (q *Queue) ClearMessages(options *QueueServiceOptions) error {
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusNoContent})
}
// SetPermissions sets up queue permissions
@@ -341,13 +341,8 @@ func (q *Queue) SetPermissions(permissions QueuePermissions, options *SetQueuePe
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil {
return errors.New("Unable to set permissions")
}
return nil
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusNoContent})
}
func generateQueueACLpayload(policies []QueueAccessPolicy) (io.Reader, int, error) {
@@ -409,14 +404,14 @@ func (q *Queue) GetPermissions(options *GetQueuePermissionOptions) (*QueuePermis
if err != nil {
return nil, err
}
defer resp.body.Close()
defer resp.Body.Close()
var ap AccessPolicy
err = xmlUnmarshal(resp.body, &ap.SignedIdentifiersList)
err = xmlUnmarshal(resp.Body, &ap.SignedIdentifiersList)
if err != nil {
return nil, err
}
return buildQueueAccessPolicy(ap, &resp.headers), nil
return buildQueueAccessPolicy(ap, &resp.Header), nil
}
func buildQueueAccessPolicy(ap AccessPolicy, headers *http.Header) *QueuePermissions {

View File

@@ -75,10 +75,10 @@ func (s *Share) CreateIfNotExists(options *FileRequestOptions) (bool, error) {
params := prepareOptions(options)
resp, err := s.fsc.createResourceNoClose(s.buildPath(), resourceShare, params, extraheaders)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusCreated || resp.statusCode == http.StatusConflict {
if resp.statusCode == http.StatusCreated {
s.updateEtagAndLastModified(resp.headers)
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusCreated || resp.StatusCode == http.StatusConflict {
if resp.StatusCode == http.StatusCreated {
s.updateEtagAndLastModified(resp.Header)
return true, nil
}
return false, s.FetchAttributes(nil)
@@ -103,9 +103,9 @@ func (s *Share) Delete(options *FileRequestOptions) error {
func (s *Share) DeleteIfExists(options *FileRequestOptions) (bool, error) {
resp, err := s.fsc.deleteResourceNoClose(s.buildPath(), resourceShare, options)
if resp != nil {
defer readAndCloseBody(resp.body)
if resp.statusCode == http.StatusAccepted || resp.statusCode == http.StatusNotFound {
return resp.statusCode == http.StatusAccepted, nil
defer readAndCloseBody(resp.Body)
if resp.StatusCode == http.StatusAccepted || resp.StatusCode == http.StatusNotFound {
return resp.StatusCode == http.StatusAccepted, nil
}
}
return false, err

View File

@@ -77,14 +77,14 @@ func (c Client) getServiceProperties(service string, auth authentication) (*Serv
if err != nil {
return nil, err
}
defer resp.body.Close()
defer resp.Body.Close()
if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err := checkRespCode(resp, []int{http.StatusOK}); err != nil {
return nil, err
}
var out ServiceProperties
err = xmlUnmarshal(resp.body, &out)
err = xmlUnmarshal(resp.Body, &out)
if err != nil {
return nil, err
}
@@ -126,6 +126,6 @@ func (c Client) setServiceProperties(props ServiceProperties, service string, au
if err != nil {
return err
}
readAndCloseBody(resp.body)
return checkRespCode(resp.statusCode, []int{http.StatusAccepted})
defer readAndCloseBody(resp.Body)
return checkRespCode(resp, []int{http.StatusAccepted})
}

View File

@@ -97,13 +97,13 @@ func (t *Table) Get(timeout uint, ml MetadataLevel) error {
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer resp.Body.Close()
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
return err
}
respBody, err := ioutil.ReadAll(resp.body)
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
@@ -143,20 +143,20 @@ func (t *Table) Create(timeout uint, ml MetadataLevel, options *TableOptions) er
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer resp.Body.Close()
if ml == EmptyPayload {
if err := checkRespCode(resp.statusCode, []int{http.StatusNoContent}); err != nil {
if err := checkRespCode(resp, []int{http.StatusNoContent}); err != nil {
return err
}
} else {
if err := checkRespCode(resp.statusCode, []int{http.StatusCreated}); err != nil {
if err := checkRespCode(resp, []int{http.StatusCreated}); err != nil {
return err
}
}
if ml != EmptyPayload {
data, err := ioutil.ReadAll(resp.body)
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
@@ -186,9 +186,9 @@ func (t *Table) Delete(timeout uint, options *TableOptions) error {
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
return checkRespCode(resp, []int{http.StatusNoContent})
}
// QueryOptions includes options for a query entities operation.
@@ -269,9 +269,9 @@ func (t *Table) SetPermissions(tap []TableAccessPolicy, timeout uint, options *T
if err != nil {
return err
}
defer readAndCloseBody(resp.body)
defer readAndCloseBody(resp.Body)
return checkRespCode(resp.statusCode, []int{http.StatusNoContent})
return checkRespCode(resp, []int{http.StatusNoContent})
}
func generateTableACLPayload(policies []TableAccessPolicy) (io.Reader, int, error) {
@@ -301,14 +301,14 @@ func (t *Table) GetPermissions(timeout int, options *TableOptions) ([]TableAcces
if err != nil {
return nil, err
}
defer resp.body.Close()
defer resp.Body.Close()
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
return nil, err
}
var ap AccessPolicy
err = xmlUnmarshal(resp.body, &ap.SignedIdentifiersList)
err = xmlUnmarshal(resp.Body, &ap.SignedIdentifiersList)
if err != nil {
return nil, err
}
@@ -325,13 +325,13 @@ func (t *Table) queryEntities(uri string, headers map[string]string, ml Metadata
if err != nil {
return nil, err
}
defer resp.body.Close()
defer resp.Body.Close()
if err = checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err = checkRespCode(resp, []int{http.StatusOK}); err != nil {
return nil, err
}
data, err := ioutil.ReadAll(resp.body)
data, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@@ -346,7 +346,7 @@ func (t *Table) queryEntities(uri string, headers map[string]string, ml Metadata
}
entities.table = t
contToken := extractContinuationTokenFromHeaders(resp.headers)
contToken := extractContinuationTokenFromHeaders(resp.Header)
if contToken == nil {
entities.NextLink = nil
} else {

View File

@@ -163,15 +163,15 @@ func (t *TableBatch) ExecuteBatch() error {
if err != nil {
return err
}
defer resp.body.Close()
defer readAndCloseBody(resp.resp.Body)
if err = checkRespCode(resp.statusCode, []int{http.StatusAccepted}); err != nil {
if err = checkRespCode(resp.resp, []int{http.StatusAccepted}); err != nil {
// check which batch failed.
operationFailedMessage := t.getFailedOperation(resp.odata.Err.Message.Value)
requestID, date, version := getDebugHeaders(resp.headers)
requestID, date, version := getDebugHeaders(resp.resp.Header)
return AzureStorageServiceError{
StatusCode: resp.statusCode,
StatusCode: resp.resp.StatusCode,
Code: resp.odata.Err.Code,
RequestID: requestID,
Date: date,

View File

@@ -145,13 +145,13 @@ func (t *TableServiceClient) queryTables(uri string, headers map[string]string,
if err != nil {
return nil, err
}
defer resp.body.Close()
defer resp.Body.Close()
if err := checkRespCode(resp.statusCode, []int{http.StatusOK}); err != nil {
if err := checkRespCode(resp, []int{http.StatusOK}); err != nil {
return nil, err
}
respBody, err := ioutil.ReadAll(resp.body)
respBody, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
@@ -166,7 +166,7 @@ func (t *TableServiceClient) queryTables(uri string, headers map[string]string,
}
out.tsc = t
nextLink := resp.headers.Get(http.CanonicalHeaderKey(headerXmsContinuation))
nextLink := resp.Header.Get(http.CanonicalHeaderKey(headerXmsContinuation))
if nextLink == "" {
out.NextLink = nil
} else {

View File

@@ -209,6 +209,11 @@ func (t *TimeRFC1123) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error
return nil
}
// MarshalXML marshals using time.RFC1123.
func (t *TimeRFC1123) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
return e.EncodeElement(time.Time(*t).Format(time.RFC1123), start)
}
// returns a map of custom metadata values from the specified HTTP header
func getMetadataFromHeaders(header http.Header) map[string]string {
metadata := make(map[string]string)

View File

@@ -1,19 +0,0 @@
package storage
// Copyright 2017 Microsoft Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
var (
sdkVersion = "v12.4.0-beta"
)