Example #1
0
        /// <summary>
        /// Implements the FetchAttributes method. The attributes are updated immediately.
        /// </summary>
        /// <param name="blob">The blob object that is calling this method.</param>
        /// <param name="attributes">The blob's attributes.</param>
        /// <param name="accessCondition">An object that represents the access conditions for the blob. If null, no condition is used.</param>
        /// <param name="options">An object that specifies additional options for the request.</param>
        /// <returns>A <see cref="RESTCommand"/> that fetches the attributes.</returns>
        internal static RESTCommand <NullType> FetchAttributesImpl(ICloudBlob blob, BlobAttributes attributes, AccessCondition accessCondition, BlobRequestOptions options)
        {
            RESTCommand <NullType> getCmd = new RESTCommand <NullType>(blob.ServiceClient.Credentials, attributes.StorageUri);

            options.ApplyToStorageCommand(getCmd);
            getCmd.CommandLocationMode = CommandLocationMode.PrimaryOrSecondary;
            getCmd.Handler             = blob.ServiceClient.AuthenticationHandler;
            getCmd.BuildClient         = HttpClientFactory.BuildHttpClient;
            getCmd.BuildRequest        = (cmd, uri, builder, cnt, serverTimeout, ctx) => BlobHttpRequestMessageFactory.GetProperties(uri, serverTimeout, attributes.SnapshotTime, accessCondition, cnt, ctx);
            getCmd.PreProcessResponse  = (cmd, resp, ex, ctx) =>
            {
                HttpResponseParsers.ProcessExpectedStatusCodeNoException(HttpStatusCode.OK, resp, NullType.Value, cmd, ex);
                CloudBlobSharedImpl.UpdateAfterFetchAttributes(attributes, resp, false);
                return(NullType.Value);
            };

            return(getCmd);
        }
Example #2
0
        /// <summary>
        /// Implements the FetchAttributes method. The attributes are updated immediately.
        /// </summary>
        /// <param name="blobUri">The URI of the blob.</param>
        /// <param name="accessCondition">An <see cref="AccessCondition"/> object that represents the access conditions for the blob. If <c>null</c>, no condition is used.</param>
        /// <param name="options">A <see cref="BlobRequestOptions"/> object that specifies any additional options for the request.</param>
        /// <returns>A <see cref="RESTCommand"/> that fetches the attributes.</returns>
        private RESTCommand <ICloudBlob> GetBlobReferenceImpl(Uri blobUri, AccessCondition accessCondition, BlobRequestOptions options)
        {
            // If the blob Uri contains SAS credentials, we need to use those
            // credentials instead of this service client's stored credentials.
            StorageCredentials parsedCredentials;
            DateTimeOffset?    parsedSnapshot;

            blobUri = NavigationHelper.ParseBlobQueryAndVerify(blobUri, out parsedCredentials, out parsedSnapshot);
            CloudBlobClient client = parsedCredentials != null ? new CloudBlobClient(this.BaseUri, parsedCredentials) : this;

            RESTCommand <ICloudBlob> getCmd = new RESTCommand <ICloudBlob>(client.Credentials, blobUri);

            getCmd.ApplyRequestOptions(options);
            getCmd.Handler            = client.AuthenticationHandler;
            getCmd.BuildClient        = HttpClientFactory.BuildHttpClient;
            getCmd.BuildRequest       = (cmd, cnt, ctx) => BlobHttpRequestMessageFactory.GetProperties(cmd.Uri, cmd.ServerTimeoutInSeconds, parsedSnapshot, accessCondition, cnt, ctx);
            getCmd.PreProcessResponse = (cmd, resp, ex, ctx) =>
            {
                HttpResponseParsers.ProcessExpectedStatusCodeNoException(HttpStatusCode.OK, resp, null /* retVal */, cmd, ex, ctx);

                BlobAttributes attributes = new BlobAttributes()
                {
                    Uri          = blobUri,
                    SnapshotTime = parsedSnapshot,
                };

                CloudBlobSharedImpl.UpdateAfterFetchAttributes(attributes, resp, false);

                switch (attributes.Properties.BlobType)
                {
                case BlobType.BlockBlob:
                    return(new CloudBlockBlob(attributes, client));

                case BlobType.PageBlob:
                    return(new CloudPageBlob(attributes, client));

                default:
                    throw new InvalidOperationException();
                }
            };

            return(getCmd);
        }
        /// <summary>
        /// Implementation for the Exists method.
        /// </summary>
        /// <param name="blob">The blob.</param>
        /// <param name="attributes">The attributes.</param>
        /// <param name="options">An object that specifies additional options for the request.</param>
        /// <returns>
        /// A <see cref="RESTCommand{T}" /> that checks existence.
        /// </returns>
        internal static RESTCommand <bool> ExistsImpl(ICloudBlob blob, BlobAttributes attributes, BlobRequestOptions options)
        {
            RESTCommand <bool> getCmd = new RESTCommand <bool>(blob.ServiceClient.Credentials, attributes.Uri);

            getCmd.ApplyRequestOptions(options);
            getCmd.BuildRequestDelegate = (uri, builder, serverTimeout, ctx) => BlobHttpWebRequestFactory.GetProperties(uri, serverTimeout, attributes.SnapshotTime, null /* accessCondition */, ctx);
            getCmd.SignRequest          = blob.ServiceClient.AuthenticationHandler.SignRequest;
            getCmd.PreProcessResponse   = (cmd, resp, ex, ctx) =>
            {
                if (resp.StatusCode == HttpStatusCode.NotFound)
                {
                    return(false);
                }

                HttpResponseParsers.ProcessExpectedStatusCodeNoException(HttpStatusCode.OK, resp, true, cmd, ex);
                CloudBlobSharedImpl.UpdateAfterFetchAttributes(attributes, resp, false);
                return(true);
            };

            return(getCmd);
        }
Example #4
0
        /// <summary>
        /// Implements the Exists method. The attributes are updated immediately.
        /// </summary>
        /// <param name="blob">The blob object that is calling this method.</param>
        /// <param name="attributes">The blob's attributes.</param>
        /// <param name="options">An object that specifies additional options for the request.</param>
        /// <param name="primaryOnly">If <c>true</c>, the command will be executed against the primary location.</param>
        /// <returns>A <see cref="RESTCommand"/> that checks existence.</returns>
        internal static RESTCommand <bool> ExistsImpl(ICloudBlob blob, BlobAttributes attributes, BlobRequestOptions options, bool primaryOnly)
        {
            RESTCommand <bool> getCmd = new RESTCommand <bool>(blob.ServiceClient.Credentials, attributes.StorageUri);

            options.ApplyToStorageCommand(getCmd);
            getCmd.CommandLocationMode = primaryOnly ? CommandLocationMode.PrimaryOnly : CommandLocationMode.PrimaryOrSecondary;
            getCmd.Handler             = blob.ServiceClient.AuthenticationHandler;
            getCmd.BuildClient         = HttpClientFactory.BuildHttpClient;
            getCmd.BuildRequest        = (cmd, uri, builder, cnt, serverTimeout, ctx) => BlobHttpRequestMessageFactory.GetProperties(uri, serverTimeout, attributes.SnapshotTime, null /* accessCondition */, cnt, ctx);
            getCmd.PreProcessResponse  = (cmd, resp, ex, ctx) =>
            {
                if (resp.StatusCode == HttpStatusCode.NotFound)
                {
                    return(false);
                }

                HttpResponseParsers.ProcessExpectedStatusCodeNoException(HttpStatusCode.OK, resp, true, cmd, ex);
                CloudBlobSharedImpl.UpdateAfterFetchAttributes(attributes, resp, false);
                return(true);
            };

            return(getCmd);
        }
        /// <summary>
        /// Implements getting the stream without specifying a range.
        /// </summary>
        /// <param name="blob">The blob.</param>
        /// <param name="attributes">The attributes.</param>
        /// <param name="destStream">The destination stream.</param>
        /// <param name="offset">The offset.</param>
        /// <param name="length">The length.</param>
        /// <param name="accessCondition">An object that represents the access conditions for the blob. If null, no condition is used.</param>
        /// <param name="options">An object that specifies any additional options for the request.</param>
        /// <returns>
        /// A <see cref="RESTCommand{T}" /> that gets the stream.
        /// </returns>
        internal static RESTCommand <NullType> GetBlobImpl(ICloudBlob blob, BlobAttributes attributes, Stream destStream, long?offset, long?length, AccessCondition accessCondition, BlobRequestOptions options)
        {
            string          lockedETag            = null;
            AccessCondition lockedAccessCondition = null;

            bool   isRangeGet             = offset.HasValue;
            bool   arePropertiesPopulated = false;
            string storedMD5 = null;

            long startingOffset = offset.HasValue ? offset.Value : 0;
            long?startingLength = length;

            RESTCommand <NullType> getCmd = new RESTCommand <NullType>(blob.ServiceClient.Credentials, attributes.Uri);

            getCmd.ApplyRequestOptions(options);
            getCmd.RetrieveResponseStream        = true;
            getCmd.DestinationStream             = destStream;
            getCmd.CalculateMd5ForResponseStream = !options.DisableContentMD5Validation.Value;
            getCmd.BuildRequestDelegate          = (uri, builder, serverTimeout, ctx) =>
                                                   BlobHttpWebRequestFactory.Get(uri, serverTimeout, attributes.SnapshotTime, offset, length, options.UseTransactionalMD5.Value, accessCondition, ctx);
            getCmd.SignRequest    = blob.ServiceClient.AuthenticationHandler.SignRequest;
            getCmd.RecoveryAction = (cmd, ex, ctx) =>
            {
                if ((lockedAccessCondition == null) && !string.IsNullOrEmpty(lockedETag))
                {
                    lockedAccessCondition = AccessCondition.GenerateIfMatchCondition(lockedETag);
                    if (accessCondition != null)
                    {
                        lockedAccessCondition.LeaseId = accessCondition.LeaseId;
                    }
                }

                if (cmd.StreamCopyState != null)
                {
                    offset = startingOffset + cmd.StreamCopyState.Length;
                    if (startingLength.HasValue)
                    {
                        length = startingLength.Value - cmd.StreamCopyState.Length;
                    }
                }

                getCmd.BuildRequestDelegate = (uri, builder, serverTimeout, context) =>
                                              BlobHttpWebRequestFactory.Get(uri, serverTimeout, attributes.SnapshotTime, offset, length, options.UseTransactionalMD5.Value && !arePropertiesPopulated, lockedAccessCondition ?? accessCondition, context);
            };

            getCmd.PreProcessResponse = (cmd, resp, ex, ctx) =>
            {
                HttpResponseParsers.ProcessExpectedStatusCodeNoException(offset.HasValue ? HttpStatusCode.PartialContent : HttpStatusCode.OK, resp, NullType.Value, cmd, ex, ctx);

                if (!arePropertiesPopulated)
                {
                    CloudBlobSharedImpl.UpdateAfterFetchAttributes(attributes, resp, isRangeGet);
                    storedMD5 = resp.Headers[HttpResponseHeader.ContentMd5];

                    if (!options.DisableContentMD5Validation.Value &&
                        options.UseTransactionalMD5.Value &&
                        string.IsNullOrEmpty(storedMD5))
                    {
                        throw new StorageException(
                                  cmd.CurrentResult,
                                  SR.MD5NotPresentError,
                                  null)
                              {
                                  IsRetryable = false
                              };
                    }

                    lockedETag             = attributes.Properties.ETag;
                    arePropertiesPopulated = true;
                }

                return(NullType.Value);
            };

            getCmd.PostProcessResponse = (cmd, resp, ex, ctx) =>
            {
                long validateLength = startingLength.HasValue ? startingLength.Value : (attributes.Properties.Length - startingOffset);
                HttpResponseParsers.ValidateResponseStreamMd5AndLength(validateLength, storedMD5, cmd, cmd.StreamCopyState);
                return(NullType.Value);
            };

            return(getCmd);
        }
Example #6
0
        /// <summary>
        /// Implements getting the blob.
        /// </summary>
        /// <param name="blob">The blob object that is calling this method.</param>
        /// <param name="attributes">The blob's attributes.</param>
        /// <param name="destStream">The target stream.</param>
        /// <param name="offset">The offset at which to begin downloading the blob, in bytes.</param>
        /// <param name="length">The length of the data to download from the blob, in bytes.</param>
        /// <param name="accessCondition">An object that represents the access conditions for the blob. If null, no condition is used.</param>
        /// <param name="options">An object that specifies additional options for the request.</param>
        /// <returns>A <see cref="SynchronousTask"/> that gets the stream.</returns>
        internal static RESTCommand <NullType> GetBlobImpl(ICloudBlob blob, BlobAttributes attributes, Stream destStream, long?offset, long?length, AccessCondition accessCondition, BlobRequestOptions options)
        {
            string          lockedETag            = null;
            AccessCondition lockedAccessCondition = null;

            bool   isRangeGet             = offset.HasValue;
            bool   arePropertiesPopulated = false;
            string storedMD5 = null;

            long startingOffset = offset.HasValue ? offset.Value : 0;
            long?startingLength = length;
            long?validateLength = null;

            RESTCommand <NullType> getCmd = new RESTCommand <NullType>(blob.ServiceClient.Credentials, attributes.StorageUri);

            options.ApplyToStorageCommand(getCmd);
            getCmd.CommandLocationMode           = CommandLocationMode.PrimaryOrSecondary;
            getCmd.RetrieveResponseStream        = true;
            getCmd.DestinationStream             = destStream;
            getCmd.CalculateMd5ForResponseStream = !options.DisableContentMD5Validation.Value;
            getCmd.Handler        = blob.ServiceClient.AuthenticationHandler;
            getCmd.BuildClient    = HttpClientFactory.BuildHttpClient;
            getCmd.BuildRequest   = (cmd, uri, builder, cnt, serverTimeout, ctx) => BlobHttpRequestMessageFactory.Get(uri, serverTimeout, attributes.SnapshotTime, offset, length, options.UseTransactionalMD5.Value, accessCondition, cnt, ctx);
            getCmd.RecoveryAction = (cmd, ex, ctx) =>
            {
                if ((lockedAccessCondition == null) && !string.IsNullOrEmpty(lockedETag))
                {
                    lockedAccessCondition = AccessCondition.GenerateIfMatchCondition(lockedETag);
                    if (accessCondition != null)
                    {
                        lockedAccessCondition.LeaseId = accessCondition.LeaseId;
                    }
                }

                if (cmd.StreamCopyState != null)
                {
                    offset = startingOffset + cmd.StreamCopyState.Length;
                    if (startingLength.HasValue)
                    {
                        length = startingLength.Value - cmd.StreamCopyState.Length;
                    }
                }

                getCmd.BuildRequest = (command, uri, builder, cnt, serverTimeout, context) => BlobHttpRequestMessageFactory.Get(uri, serverTimeout, attributes.SnapshotTime, offset, length, options.UseTransactionalMD5.Value && !arePropertiesPopulated, lockedAccessCondition ?? accessCondition, cnt, context);
            };

            getCmd.PreProcessResponse = (cmd, resp, ex, ctx) =>
            {
                HttpResponseParsers.ProcessExpectedStatusCodeNoException(offset.HasValue ? HttpStatusCode.PartialContent : HttpStatusCode.OK, resp, NullType.Value, cmd, ex);

                if (!arePropertiesPopulated)
                {
                    CloudBlobSharedImpl.UpdateAfterFetchAttributes(attributes, resp, isRangeGet);

                    if (resp.Content.Headers.ContentMD5 != null)
                    {
                        storedMD5 = Convert.ToBase64String(resp.Content.Headers.ContentMD5);
                    }

                    if (!options.DisableContentMD5Validation.Value &&
                        options.UseTransactionalMD5.Value &&
                        string.IsNullOrEmpty(storedMD5))
                    {
                        throw new StorageException(
                                  cmd.CurrentResult,
                                  SR.MD5NotPresentError,
                                  null)
                              {
                                  IsRetryable = false
                              };
                    }

                    // If the download fails and Get Blob needs to resume the download, going to the
                    // same storage location is important to prevent a possible ETag mismatch.
                    getCmd.CommandLocationMode = cmd.CurrentResult.TargetLocation == StorageLocation.Primary ? CommandLocationMode.PrimaryOnly : CommandLocationMode.SecondaryOnly;
                    lockedETag     = attributes.Properties.ETag;
                    validateLength = resp.Content.Headers.ContentLength;

                    arePropertiesPopulated = true;
                }

                return(NullType.Value);
            };

            getCmd.PostProcessResponse = (cmd, resp, ctx) =>
            {
                HttpResponseParsers.ValidateResponseStreamMd5AndLength(validateLength, storedMD5, cmd);
                return(Task.FromResult(NullType.Value));
            };

            return(getCmd);
        }