internal static void AddAuthenticationHeaders(HttpPipelineRequest request, Uri uri, HttpVerb method, ReadOnlyMemory <byte> content, byte[] secret, string credential)
        {
            string contentHash = null;

            using (var alg = SHA256.Create())
            {
                // TODO (pri 3): ToArray should nopt be called here. Instead, TryGetArray, or PipelineContent should do hashing on the fly
                contentHash = Convert.ToBase64String(alg.ComputeHash(content.ToArray()));
            }

            using (var hmac = new HMACSHA256(secret))
            {
                var host         = uri.Host;
                var pathAndQuery = uri.PathAndQuery;

                string         verb          = method.ToString().ToUpper();
                DateTimeOffset utcNow        = DateTimeOffset.UtcNow;
                var            utcNowString  = utcNow.ToString("r");
                var            stringToSign  = $"{verb}\n{pathAndQuery}\n{utcNowString};{host};{contentHash}";
                var            signature     = Convert.ToBase64String(hmac.ComputeHash(Encoding.ASCII.GetBytes(stringToSign))); // Calculate the signature
                string         signedHeaders = "date;host;x-ms-content-sha256";                                                 // Semicolon separated header names

                // TODO (pri 3): should date header writing be moved out from here?
                request.AddHeader("Date", utcNowString);
                request.AddHeader("x-ms-content-sha256", contentHash);
                request.AddHeader("Authorization", $"HMAC-SHA256 Credential={credential}, SignedHeaders={signedHeaders}, Signature={signature}");
            }
        }
        public async Task RequestContentIsLoggedAsText()
        {
            var response      = new MockResponse(500);
            var mockTransport = new MockTransport(response);

            var    pipeline = new HttpPipeline(mockTransport, new [] { LoggingPolicy.Shared });
            string requestId;

            using (HttpPipelineRequest request = pipeline.CreateRequest())
            {
                request.SetRequestLine(HttpPipelineMethod.Get, new Uri("https://contoso.a.io"));
                request.Content = HttpPipelineRequestContent.Create(Encoding.UTF8.GetBytes("Hello world"));
                request.AddHeader(new HttpHeader("Content-Type", "text/json"));
                requestId = request.RequestId;

                await pipeline.SendRequestAsync(request, CancellationToken.None);
            }

            var e = _listener.SingleEventById(RequestContentTextEvent);

            Assert.AreEqual(EventLevel.Verbose, e.Level);
            Assert.AreEqual("RequestContentText", e.EventName);
            Assert.AreEqual(requestId, e.GetProperty <string>("requestId"));
            Assert.AreEqual("Hello world", e.GetProperty <string>("content"));

            CollectionAssert.IsEmpty(_listener.EventsById(ResponseContentEvent));
        }
        private static Task <Response> SendTestRequestAsync(HttpPipeline pipeline, long offset)
        {
            using (HttpPipelineRequest request = pipeline.CreateRequest())
            {
                request.SetRequestLine(HttpPipelineMethod.Get, new Uri("http://example.com"));
                request.AddHeader("Range", "bytes=" + offset);

                return(pipeline.SendRequestAsync(request, CancellationToken.None));
            }
        }
        // TODO (pri 3): do all the methods that call this accept revisions?
        static void AddOptionsHeaders(RequestOptions options, HttpPipelineRequest request)
        {
            if (options == null)
            {
                return;
            }

            if (options.ETag.IfMatch != default)
            {
                request.AddHeader(IfMatchName, $"\"{options.ETag.IfMatch}\"");
            }

            if (options.ETag.IfNoneMatch != default)
            {
                request.AddHeader(IfNoneMatch, $"\"{options.ETag.IfNoneMatch}\"");
            }

            if (options.Revision.HasValue)
            {
                var dateTime = options.Revision.Value.UtcDateTime.ToString(AcceptDateTimeFormat);
                request.AddHeader(AcceptDatetimeHeader, dateTime);
            }
        }
        public async Task SendingRequestProducesEvents()
        {
            var response = new MockResponse(500);

            response.SetContent(new byte[] { 6, 7, 8, 9, 0 });
            response.AddHeader(new HttpHeader("Custom-Response-Header", "Improved value"));

            var mockTransport = new MockTransport(response);

            var    pipeline = new HttpPipeline(mockTransport, new [] { LoggingPolicy.Shared });
            string requestId;

            using (HttpPipelineRequest request = pipeline.CreateRequest())
            {
                request.SetRequestLine(HttpPipelineMethod.Get, new Uri("https://contoso.a.io"));
                request.AddHeader("Date", "3/26/2019");
                request.AddHeader("Custom-Header", "Value");
                request.Content = HttpPipelineRequestContent.Create(new byte[] { 1, 2, 3, 4, 5 });
                requestId       = request.RequestId;

                await pipeline.SendRequestAsync(request, CancellationToken.None);
            }

            var e = _listener.SingleEventById(RequestEvent);

            Assert.AreEqual(EventLevel.Informational, e.Level);
            Assert.AreEqual("Request", e.EventName);
            Assert.AreEqual(requestId, e.GetProperty <string>("requestId"));
            Assert.AreEqual("https://contoso.a.io/", e.GetProperty <string>("uri"));
            Assert.AreEqual("GET", e.GetProperty <string>("method"));
            StringAssert.Contains($"Date:3/26/2019{Environment.NewLine}", e.GetProperty <string>("headers"));
            StringAssert.Contains($"Custom-Header:Value{Environment.NewLine}", e.GetProperty <string>("headers"));

            e = _listener.SingleEventById(RequestContentEvent);
            Assert.AreEqual(EventLevel.Verbose, e.Level);
            Assert.AreEqual("RequestContent", e.EventName);
            Assert.AreEqual(requestId, e.GetProperty <string>("requestId"));
            CollectionAssert.AreEqual(new byte[] { 1, 2, 3, 4, 5 }, e.GetProperty <byte[]>("content"));

            e = _listener.SingleEventById(ResponseEvent);
            Assert.AreEqual(EventLevel.Informational, e.Level);
            Assert.AreEqual("Response", e.EventName);
            Assert.AreEqual(requestId, e.GetProperty <string>("requestId"));
            Assert.AreEqual(e.GetProperty <int>("status"), 500);
            StringAssert.Contains($"Custom-Response-Header:Improved value{Environment.NewLine}", e.GetProperty <string>("headers"));

            e = _listener.SingleEventById(ResponseContentEvent);
            Assert.AreEqual(EventLevel.Verbose, e.Level);
            Assert.AreEqual("ResponseContent", e.EventName);
            Assert.AreEqual(requestId, e.GetProperty <string>("requestId"));
            CollectionAssert.AreEqual(new byte[] { 6, 7, 8, 9, 0 }, e.GetProperty <byte[]>("content"));

            e = _listener.SingleEventById(ErrorResponseEvent);
            Assert.AreEqual(EventLevel.Error, e.Level);
            Assert.AreEqual("ErrorResponse", e.EventName);
            Assert.AreEqual(requestId, e.GetProperty <string>("requestId"));
            Assert.AreEqual(e.GetProperty <int>("status"), 500);
            StringAssert.Contains($"Custom-Response-Header:Improved value{Environment.NewLine}", e.GetProperty <string>("headers"));

            e = _listener.SingleEventById(ErrorResponseContentEvent);
            Assert.AreEqual(EventLevel.Informational, e.Level);
            Assert.AreEqual("ErrorResponseContent", e.EventName);
            Assert.AreEqual(requestId, e.GetProperty <string>("requestId"));
            CollectionAssert.AreEqual(new byte[] { 6, 7, 8, 9, 0 }, e.GetProperty <byte[]>("content"));
        }
 static void AddClientRequestID(HttpPipelineRequest request)
 {
     request.AddHeader(ClientRequestIdHeader, Guid.NewGuid().ToString());
     request.AddHeader(EchoClientRequestId, "true");
 }