< Summary

Class:Azure.Messaging.ServiceBus.Management.HttpRequestAndResponse
Assembly:Azure.Messaging.ServiceBus
File(s):C:\Git\azure-sdk-for-net\sdk\servicebus\Azure.Messaging.ServiceBus\src\Management\HttpRequestAndResponse.cs
Covered lines:143
Uncovered lines:11
Coverable lines:154
Total lines:302
Line coverage:92.8% (143 of 154)
Covered branches:38
Total branches:48
Branch coverage:79.1% (38 of 48)

Metrics

MethodCyclomatic complexity Line coverage Branch coverage
.ctor(...)-100%100%
ThrowIfRequestFailedAsync()-100%100%
GetToken(...)-100%100%
GetTokenAsync()-85.71%50%
GetEntitiesPageAsync()-92.31%66.67%
GetEntityAsync()-100%100%
PutEntityAsync()-73.33%40%
DeleteEntityAsync()-100%100%
SendHttpRequestAsync()-100%100%
ReadAsString()-100%100%
GetPort(...)-66.67%50%

File(s)

C:\Git\azure-sdk-for-net\sdk\servicebus\Azure.Messaging.ServiceBus\src\Management\HttpRequestAndResponse.cs

#LineLine coverage
 1// Copyright (c) Microsoft Corporation. All rights reserved.
 2// Licensed under the MIT License.
 3
 4using System.IO;
 5using Azure.Core;
 6using System;
 7using System.Net;
 8using System.Text;
 9using System.Threading;
 10using System.Threading.Tasks;
 11using Azure.Messaging.ServiceBus.Authorization;
 12using Azure.Messaging.ServiceBus.Primitives;
 13using Azure.Core.Pipeline;
 14using System.Collections.Generic;
 15using System.Globalization;
 16
 17namespace Azure.Messaging.ServiceBus.Management
 18{
 19    internal class HttpRequestAndResponse
 20    {
 21        private readonly HttpPipeline _pipeline;
 22        private readonly string _fullyQualifiedNamespace;
 23        private readonly TokenCredential _tokenCredential;
 24        private readonly int _port;
 25        private readonly ClientDiagnostics _diagnostics;
 26
 27        /// <summary>
 28        /// Initializes a new <see cref="HttpRequestAndResponse"/> which can be used to send http request and response.
 29        /// </summary>
 4630        public HttpRequestAndResponse(
 4631            HttpPipeline pipeline,
 4632            ClientDiagnostics diagnostics,
 4633            TokenCredential tokenCredential,
 4634            string fullyQualifiedNamespace)
 35        {
 4636            _pipeline = pipeline;
 4637            _diagnostics = diagnostics;
 4638            _tokenCredential = tokenCredential;
 4639            _fullyQualifiedNamespace = fullyQualifiedNamespace;
 4640            _port = GetPort(_fullyQualifiedNamespace);
 4641        }
 42
 43
 44        internal async Task ThrowIfRequestFailedAsync(Request request, Response response)
 45        {
 35646            if ((response.Status >= 200) && (response.Status < 400))
 47            {
 28848                return;
 49            }
 6850            RequestFailedException ex = await _diagnostics.CreateRequestFailedExceptionAsync(response).ConfigureAwait(fa
 6851            if (response.Status == (int)HttpStatusCode.Unauthorized)
 52            {
 253                throw new ServiceBusException(
 254                    ex.Message,
 255                    ServiceBusFailureReason.Unauthorized,
 256                    innerException: ex);
 57            }
 58
 6659            if (response.Status == (int)HttpStatusCode.NotFound)
 60            {
 3861                throw new ServiceBusException(
 3862                    ex.Message,
 3863                    ServiceBusFailureReason.MessagingEntityNotFound,
 3864                    innerException: ex);
 65            }
 66
 2867            if (response.Status == (int)HttpStatusCode.Conflict)
 68            {
 1869                if (request.Method.Equals(RequestMethod.Delete))
 70                {
 271                    throw new ServiceBusException(true, ex.Message, innerException: ex);
 72                }
 73
 1674                if (request.Method.Equals(RequestMethod.Put) && request.Headers.TryGetValue("If-Match", out _))
 75                {
 76                    // response.RequestMessage.Headers.IfMatch.Count > 0 is true for UpdateEntity scenario
 277                    throw new ServiceBusException(
 278                        true,
 279                        ex.Message,
 280                        innerException: ex);
 81                }
 82
 1483                throw new ServiceBusException(
 1484                    ex.Message,
 1485                    ServiceBusFailureReason.MessagingEntityAlreadyExists,
 1486                    innerException: ex);
 87            }
 88
 1089            if (response.Status == (int)HttpStatusCode.Forbidden)
 90            {
 491                if (ex.Message.Contains(ManagementClientConstants.ForbiddenInvalidOperationSubCode))
 92                {
 293                    throw new InvalidOperationException(ex.Message, ex);
 94                }
 95
 296                throw new ServiceBusException(
 297                    ex.Message,
 298                    ServiceBusFailureReason.QuotaExceeded,
 299                    innerException: ex);
 100            }
 101
 6102            if (response.Status == (int)HttpStatusCode.BadRequest)
 103            {
 2104                throw new ArgumentException(ex.Message, ex);
 105            }
 106
 4107            if (response.Status == (int)HttpStatusCode.ServiceUnavailable)
 108            {
 2109                throw new ServiceBusException(
 2110                    ex.Message,
 2111                    ServiceBusFailureReason.ServiceBusy,
 2112                    innerException: ex);
 113            }
 114
 2115            throw new ServiceBusException(
 2116                true,
 2117                $"{ex.Message}; response status code: {response.Status}",
 2118                innerException: ex);
 288119        }
 120
 121        private Task<string> GetToken(Uri requestUri) =>
 320122            GetTokenAsync(requestUri.GetLeftPart(UriPartial.Path));
 123
 124        public async Task<string> GetTokenAsync(string requestUri)
 125        {
 320126            var scope = requestUri;
 320127            var credential = (ServiceBusTokenCredential)_tokenCredential;
 320128            if (!credential.IsSharedAccessSignatureCredential)
 129            {
 0130                scope = Constants.DefaultScope;
 131            }
 320132            AccessToken token = await _tokenCredential.GetTokenAsync(new TokenRequestContext(new[] { scope }), Cancellat
 320133            return token.Token;
 320134        }
 135
 136        public async Task<Page<T>> GetEntitiesPageAsync<T>(
 137            string path,
 138            string nextSkip,
 139            Func<string, IReadOnlyList<T>> parseFunction,
 140            CancellationToken cancellationToken)
 141        {
 20142            int skip = 0;
 20143            int maxCount = 100;
 20144            if (nextSkip != null)
 145            {
 0146                skip = int.Parse(nextSkip, CultureInfo.InvariantCulture);
 147            }
 20148            Response response = await GetEntityAsync(path, $"$skip={skip}&$top={maxCount}", false, cancellationToken).Co
 20149            string result = await ReadAsString(response).ConfigureAwait(false);
 150
 20151            IReadOnlyList<T> description = parseFunction.Invoke(result);
 20152            skip += maxCount;
 20153            nextSkip = skip.ToString(CultureInfo.InvariantCulture);
 154
 20155            if (description.Count < maxCount || description.Count == 0)
 156            {
 20157                nextSkip = null;
 158            }
 20159            return Page<T>.FromValues(description, nextSkip, response);
 20160        }
 161
 162        public async Task<Response> GetEntityAsync(
 163            string entityPath,
 164            string query,
 165            bool enrich,
 166            CancellationToken cancellationToken)
 167        {
 128168            var queryString = $"{ManagementClientConstants.apiVersionQuery}&enrich={enrich}";
 128169            if (query != null)
 170            {
 20171                queryString = queryString + "&" + query;
 172            }
 128173            Uri uri = new UriBuilder(_fullyQualifiedNamespace)
 128174            {
 128175                Path = entityPath,
 128176                Scheme = Uri.UriSchemeHttps,
 128177                Port = _port,
 128178                Query = queryString
 128179            }.Uri;
 180
 128181            RequestUriBuilder requestUriBuilder = new RequestUriBuilder();
 128182            requestUriBuilder.Reset(uri);
 183
 128184            Request request = _pipeline.CreateRequest();
 128185            request.Method = RequestMethod.Get;
 128186            request.Uri = requestUriBuilder;
 128187            Response response = await SendHttpRequestAsync(request, cancellationToken).ConfigureAwait(false);
 188
 116189            return response;
 116190        }
 191
 192        public async Task<Response> PutEntityAsync(
 193            string entityPath,
 194            string requestBody,
 195            bool isUpdate,
 196            string forwardTo,
 197            string fwdDeadLetterTo,
 198            CancellationToken cancellationToken)
 199        {
 136200            Uri uri = new UriBuilder(_fullyQualifiedNamespace)
 136201            {
 136202                Path = entityPath,
 136203                Port = _port,
 136204                Scheme = Uri.UriSchemeHttps,
 136205                Query = $"{ManagementClientConstants.apiVersionQuery}"
 136206            }.Uri;
 136207            var requestUriBuilder = new RequestUriBuilder();
 136208            requestUriBuilder.Reset(uri);
 209
 136210            Request request = _pipeline.CreateRequest();
 136211            request.Method = RequestMethod.Put;
 136212            request.Uri = requestUriBuilder;
 136213            request.Content = RequestContent.Create(Encoding.UTF8.GetBytes(requestBody));
 136214            request.Headers.Add("Content-Type", ManagementClientConstants.AtomContentType);
 215
 136216            if (isUpdate)
 217            {
 32218                request.Headers.Add("If-Match", "*");
 219            }
 220
 136221            var credential = (ServiceBusTokenCredential)_tokenCredential;
 136222            if (!string.IsNullOrWhiteSpace(forwardTo))
 223            {
 0224                var token = await GetTokenAsync(forwardTo).ConfigureAwait(false);
 0225                request.Headers.Add(
 0226                    ManagementClientConstants.ServiceBusSupplementartyAuthorizationHeaderName,
 0227                    credential.IsSharedAccessSignatureCredential == true ? token : $"Bearer { token }");
 228            }
 229
 136230            if (!string.IsNullOrWhiteSpace(fwdDeadLetterTo))
 231            {
 0232                var token = await GetTokenAsync(fwdDeadLetterTo).ConfigureAwait(false);
 0233                request.Headers.Add(
 0234                    ManagementClientConstants.ServiceBusDlqSupplementaryAuthorizationHeaderName,
 0235                    credential.IsSharedAccessSignatureCredential == true ? token : $"Bearer { token }");
 236            }
 237
 136238            Response response = await SendHttpRequestAsync(request, cancellationToken).ConfigureAwait(false);
 239
 112240            return response;
 112241        }
 242
 243        public async Task<Response> DeleteEntityAsync(
 244            string entityPath,
 245            CancellationToken cancellationToken)
 246        {
 72247            Uri uri = new UriBuilder(_fullyQualifiedNamespace)
 72248            {
 72249                Path = entityPath,
 72250                Scheme = Uri.UriSchemeHttps,
 72251                Port = _port,
 72252                Query = ManagementClientConstants.apiVersionQuery
 72253            }.Uri;
 72254            var requestUriBuilder = new RequestUriBuilder();
 72255            requestUriBuilder.Reset(uri);
 256
 72257            Request request = _pipeline.CreateRequest();
 72258            request.Uri = requestUriBuilder;
 72259            request.Method = RequestMethod.Delete;
 260
 72261            Response response = await SendHttpRequestAsync(request, cancellationToken).ConfigureAwait(false);
 262
 60263            return response;
 60264        }
 265
 266        private async Task<Response> SendHttpRequestAsync(
 267            Request request,
 268            CancellationToken cancellationToken)
 269        {
 336270            var credential = (ServiceBusTokenCredential)_tokenCredential;
 336271            if (credential.IsSharedAccessSignatureCredential)
 272            {
 320273                var token = await GetToken(request.Uri.ToUri()).ConfigureAwait(false);
 320274                request.Headers.Add("Authorization", token);
 275            }
 276
 336277            Response response = await _pipeline.SendRequestAsync(request, cancellationToken).ConfigureAwait(false);
 278
 336279            await ThrowIfRequestFailedAsync(request, response).ConfigureAwait(false);
 288280            return response;
 288281        }
 282
 283        private static async Task<string> ReadAsString(Response response)
 284        {
 285            string exceptionMessage;
 20286            using StreamReader reader = new StreamReader(response.ContentStream);
 20287            exceptionMessage = await reader.ReadToEndAsync().ConfigureAwait(false);
 20288            return exceptionMessage;
 20289        }
 290
 291        private static int GetPort(string endpoint)
 292        {
 293            // used for internal testing
 46294            if (endpoint.EndsWith("onebox.windows-int.net", StringComparison.InvariantCultureIgnoreCase))
 295            {
 0296                return 4446;
 297            }
 298
 46299            return -1;
 300        }
 301    }
 302}