internal static async Task <TransactionalBatchResponse> FromResponseMessageAsync( ResponseMessage responseMessage, ServerBatchRequest serverRequest, CosmosSerializerCore serializer, bool shouldPromoteOperationStatus, ITrace trace, CancellationToken cancellationToken) { using (ITrace createResponseTrace = trace.StartChild("Create Trace", TraceComponent.Batch, TraceLevel.Info)) { using (responseMessage) { TransactionalBatchResponse response = null; if (responseMessage.Content != null) { Stream content = responseMessage.Content; // Shouldn't be the case practically, but handle it for safety. if (!responseMessage.Content.CanSeek) { content = new MemoryStream(); await responseMessage.Content.CopyToAsync(content); } if (content.ReadByte() == (int)HybridRowVersion.V1) { content.Position = 0; response = await TransactionalBatchResponse.PopulateFromContentAsync( content, responseMessage, serverRequest, serializer, trace, shouldPromoteOperationStatus); if (response == null) { // Convert any payload read failures as InternalServerError response = new TransactionalBatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.ServerResponseDeserializationFailure, responseMessage.Headers, trace, serverRequest.Operations, serializer); } } } if (response == null) { response = new TransactionalBatchResponse( responseMessage.StatusCode, responseMessage.Headers.SubStatusCode, responseMessage.ErrorMessage, responseMessage.Headers, trace, serverRequest.Operations, serializer); } if (response.results == null || response.results.Count != serverRequest.Operations.Count) { if (responseMessage.IsSuccessStatusCode) { // Server should be guaranteeing number of results equal to operations when // batch request is successful - so fail as InternalServerError if this is not the case. response = new TransactionalBatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.InvalidServerResponse, responseMessage.Headers, trace, serverRequest.Operations, serializer); } // When the overall response status code is TooManyRequests, propagate the RetryAfter into the individual operations. int retryAfterMilliseconds = 0; if ((int)responseMessage.StatusCode == (int)StatusCodes.TooManyRequests) { if (!responseMessage.Headers.TryGetValue(HttpConstants.HttpHeaders.RetryAfterInMilliseconds, out string retryAfter) || retryAfter == null || !int.TryParse(retryAfter, out retryAfterMilliseconds)) { retryAfterMilliseconds = 0; } } response.CreateAndPopulateResults(serverRequest.Operations, trace, retryAfterMilliseconds); } return(response); } } }
internal static async Task <TransactionalBatchResponse> FromResponseMessageAsync( ResponseMessage responseMessage, ServerBatchRequest serverRequest, CosmosSerializerCore serializer, bool shouldPromoteOperationStatus, bool shouldPerformDecryption, CancellationToken cancellationToken) { using (responseMessage) { TransactionalBatchResponse response = null; if (responseMessage.Content != null) { Stream content = responseMessage.Content; // Shouldn't be the case practically, but handle it for safety. if (!responseMessage.Content.CanSeek) { content = new MemoryStream(); await responseMessage.Content.CopyToAsync(content); } if (content.ReadByte() == (int)HybridRowVersion.V1) { content.Position = 0; response = await TransactionalBatchResponse.PopulateFromContentAsync( content, responseMessage, serverRequest, serializer, shouldPromoteOperationStatus); if (response == null) { // Convert any payload read failures as InternalServerError response = new TransactionalBatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.ServerResponseDeserializationFailure, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, responseMessage.DiagnosticsContext, serverRequest.Operations, serializer); } } } if (response == null) { response = new TransactionalBatchResponse( responseMessage.StatusCode, responseMessage.Headers.SubStatusCode, responseMessage.ErrorMessage, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, responseMessage.DiagnosticsContext, serverRequest.Operations, serializer); } if (response.results == null || response.results.Count != serverRequest.Operations.Count) { if (responseMessage.IsSuccessStatusCode) { // Server should be guaranteeing number of results equal to operations when // batch request is successful - so fail as InternalServerError if this is not the case. response = new TransactionalBatchResponse( HttpStatusCode.InternalServerError, SubStatusCodes.Unknown, ClientResources.InvalidServerResponse, responseMessage.Headers.RequestCharge, responseMessage.Headers.RetryAfter, responseMessage.Headers.ActivityId, responseMessage.DiagnosticsContext, serverRequest.Operations, serializer); } // When the overall response status code is TooManyRequests, propagate the RetryAfter into the individual operations. int retryAfterMilliseconds = 0; if ((int)responseMessage.StatusCode == (int)StatusCodes.TooManyRequests) { if (!responseMessage.Headers.TryGetValue(HttpConstants.HttpHeaders.RetryAfterInMilliseconds, out string retryAfter) || retryAfter == null || !int.TryParse(retryAfter, out retryAfterMilliseconds)) { retryAfterMilliseconds = 0; } } response.CreateAndPopulateResults(serverRequest.Operations, retryAfterMilliseconds); } else if (shouldPerformDecryption) { for (int index = 0; index < serverRequest.Operations.Count; index++) { ContainerCore containerCore = serverRequest.Operations[index].ContainerCore; TransactionalBatchOperationResult result = response.results[index]; result.ResourceStream = await containerCore.ClientContext.DecryptItemAsync( result.ResourceStream, (DatabaseCore)containerCore.Database, responseMessage.DiagnosticsContext, cancellationToken); } } return(response); } }