1package blobs 2 3import ( 4 "context" 5 "net/http" 6 "strings" 7 8 "github.com/Azure/go-autorest/autorest" 9 "github.com/Azure/go-autorest/autorest/azure" 10 "github.com/Azure/go-autorest/autorest/validation" 11 "github.com/tombuildsstuff/giovanni/storage/internal/endpoints" 12 "github.com/tombuildsstuff/giovanni/storage/internal/metadata" 13) 14 15type PutPageBlobInput struct { 16 CacheControl *string 17 ContentDisposition *string 18 ContentEncoding *string 19 ContentLanguage *string 20 ContentMD5 *string 21 ContentType *string 22 LeaseID *string 23 MetaData map[string]string 24 25 BlobContentLengthBytes int64 26 BlobSequenceNumber *int64 27 AccessTier *AccessTier 28} 29 30// PutPageBlob is a wrapper around the Put API call (with a stricter input object) 31// which creates a new block blob, or updates the content of an existing page blob. 32func (client Client) PutPageBlob(ctx context.Context, accountName, containerName, blobName string, input PutPageBlobInput) (result autorest.Response, err error) { 33 if accountName == "" { 34 return result, validation.NewError("blobs.Client", "PutPageBlob", "`accountName` cannot be an empty string.") 35 } 36 if containerName == "" { 37 return result, validation.NewError("blobs.Client", "PutPageBlob", "`containerName` cannot be an empty string.") 38 } 39 if strings.ToLower(containerName) != containerName { 40 return result, validation.NewError("blobs.Client", "PutPageBlob", "`containerName` must be a lower-cased string.") 41 } 42 if blobName == "" { 43 return result, validation.NewError("blobs.Client", "PutPageBlob", "`blobName` cannot be an empty string.") 44 } 45 if input.BlobContentLengthBytes == 0 || input.BlobContentLengthBytes%512 != 0 { 46 return result, validation.NewError("blobs.Client", "PutPageBlob", "`input.BlobContentLengthBytes` must be aligned to a 512-byte boundary.") 47 } 48 49 req, err := client.PutPageBlobPreparer(ctx, accountName, containerName, blobName, input) 50 if err != nil { 51 err = autorest.NewErrorWithError(err, "blobs.Client", "PutPageBlob", nil, "Failure preparing request") 52 return 53 } 54 55 resp, err := client.PutPageBlobSender(req) 56 if err != nil { 57 result = autorest.Response{Response: resp} 58 err = autorest.NewErrorWithError(err, "blobs.Client", "PutPageBlob", resp, "Failure sending request") 59 return 60 } 61 62 result, err = client.PutPageBlobResponder(resp) 63 if err != nil { 64 err = autorest.NewErrorWithError(err, "blobs.Client", "PutPageBlob", resp, "Failure responding to request") 65 return 66 } 67 68 return 69} 70 71// PutPageBlobPreparer prepares the PutPageBlob request. 72func (client Client) PutPageBlobPreparer(ctx context.Context, accountName, containerName, blobName string, input PutPageBlobInput) (*http.Request, error) { 73 pathParameters := map[string]interface{}{ 74 "containerName": autorest.Encode("path", containerName), 75 "blobName": autorest.Encode("path", blobName), 76 } 77 78 headers := map[string]interface{}{ 79 "x-ms-blob-type": string(PageBlob), 80 "x-ms-version": APIVersion, 81 82 // For a page blob or an page blob, the value of this header must be set to zero, 83 // as Put Blob is used only to initialize the blob 84 "Content-Length": 0, 85 86 // This header specifies the maximum size for the page blob, up to 8 TB. 87 // The page blob size must be aligned to a 512-byte boundary. 88 "x-ms-blob-content-length": input.BlobContentLengthBytes, 89 } 90 91 if input.AccessTier != nil { 92 headers["x-ms-access-tier"] = string(*input.AccessTier) 93 } 94 if input.BlobSequenceNumber != nil { 95 headers["x-ms-blob-sequence-number"] = *input.BlobSequenceNumber 96 } 97 98 if input.CacheControl != nil { 99 headers["x-ms-blob-cache-control"] = *input.CacheControl 100 } 101 if input.ContentDisposition != nil { 102 headers["x-ms-blob-content-disposition"] = *input.ContentDisposition 103 } 104 if input.ContentEncoding != nil { 105 headers["x-ms-blob-content-encoding"] = *input.ContentEncoding 106 } 107 if input.ContentLanguage != nil { 108 headers["x-ms-blob-content-language"] = *input.ContentLanguage 109 } 110 if input.ContentMD5 != nil { 111 headers["x-ms-blob-content-md5"] = *input.ContentMD5 112 } 113 if input.ContentType != nil { 114 headers["x-ms-blob-content-type"] = *input.ContentType 115 } 116 if input.LeaseID != nil { 117 headers["x-ms-lease-id"] = *input.LeaseID 118 } 119 120 headers = metadata.SetIntoHeaders(headers, input.MetaData) 121 122 preparer := autorest.CreatePreparer( 123 autorest.AsPut(), 124 autorest.WithBaseURL(endpoints.GetBlobEndpoint(client.BaseURI, accountName)), 125 autorest.WithPathParameters("/{containerName}/{blobName}", pathParameters), 126 autorest.WithHeaders(headers)) 127 return preparer.Prepare((&http.Request{}).WithContext(ctx)) 128} 129 130// PutPageBlobSender sends the PutPageBlob request. The method will close the 131// http.Response Body if it receives an error. 132func (client Client) PutPageBlobSender(req *http.Request) (*http.Response, error) { 133 return autorest.SendWithSender(client, req, 134 azure.DoRetryWithRegistration(client.Client)) 135} 136 137// PutPageBlobResponder handles the response to the PutPageBlob request. The method always 138// closes the http.Response Body. 139func (client Client) PutPageBlobResponder(resp *http.Response) (result autorest.Response, err error) { 140 err = autorest.Respond( 141 resp, 142 client.ByInspecting(), 143 azure.WithErrorUnlessStatusCode(http.StatusCreated), 144 autorest.ByClosing()) 145 result = autorest.Response{Response: resp} 146 147 return 148} 149