/// <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); }
/// <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); }
/// <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); }
/// <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); }