private static HttpRequestMessage SetAuthentication(HttpRequestMessage pushMessageDeliveryRequest, PushSubscription subscription, VapidAuthentication authentication, VapidAuthenticationScheme authenticationScheme)
        {
            Uri    endpointUri = new Uri(subscription.Endpoint);
            string audience    = endpointUri.Scheme + @"://" + endpointUri.Host;

            if (authenticationScheme == VapidAuthenticationScheme.WebPush)
            {
                VapidAuthentication.WebPushSchemeHeadersValues webPushSchemeHeadersValues = authentication.GetWebPushSchemeHeadersValues(audience);

                pushMessageDeliveryRequest.Headers.Authorization = new AuthenticationHeaderValue(WEBPUSH_AUTHENTICATION_SCHEME, webPushSchemeHeadersValues.AuthenticationHeaderValueParameter);
                pushMessageDeliveryRequest.Headers.Add(CRYPTO_KEY_HEADER_NAME, webPushSchemeHeadersValues.CryptoKeyHeaderValue);
            }
            else
            {
                pushMessageDeliveryRequest.Headers.Authorization = new AuthenticationHeaderValue(VAPID_AUTHENTICATION_SCHEME, authentication.GetVapidSchemeAuthenticationHeaderValueParameter(audience));
            }

            return(pushMessageDeliveryRequest);
        }
        /// <summary>
        /// Requests delivery of push message by push service as an asynchronous operation.
        /// </summary>
        /// <param name="subscription">The push service subscription.</param>
        /// <param name="message">The push message.</param>
        /// <param name="authentication">The authentication details.</param>
        /// <param name="authenticationScheme">The <see cref="VapidAuthenticationScheme"/> to use.</param>
        /// <param name="cancellationToken">The cancellation token to cancel operation.</param>
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task RequestPushMessageDeliveryAsync(PushSubscription subscription, PushMessage message, VapidAuthentication authentication, VapidAuthenticationScheme authenticationScheme, CancellationToken cancellationToken)
        {
            HttpRequestMessage  pushMessageDeliveryRequest         = PreparePushMessageDeliveryRequest(subscription, message, authentication, authenticationScheme);
            HttpResponseMessage pushMessageDeliveryRequestResponse = null;

            try
            {
                pushMessageDeliveryRequestResponse = await _httpClient.SendAsync(pushMessageDeliveryRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

                int retriesAfterCount = 0;
                while (ShouldRetryAfter(pushMessageDeliveryRequestResponse, retriesAfterCount, out TimeSpan delay))
                {
                    pushMessageDeliveryRequest.Dispose();
                    pushMessageDeliveryRequestResponse.Dispose();

                    await Task.Delay(delay, cancellationToken);

                    pushMessageDeliveryRequest         = PreparePushMessageDeliveryRequest(subscription, message, authentication, authenticationScheme);
                    pushMessageDeliveryRequestResponse = await _httpClient.SendAsync(pushMessageDeliveryRequest, HttpCompletionOption.ResponseHeadersRead, cancellationToken);

                    retriesAfterCount++;
                }

                await HandlePushMessageDeliveryRequestResponse(pushMessageDeliveryRequestResponse, subscription);
            }
            finally
            {
                pushMessageDeliveryRequest.Dispose();
                pushMessageDeliveryRequestResponse?.Dispose();
            }
        }
        private HttpRequestMessage PreparePushMessageDeliveryRequest(PushSubscription subscription, PushMessage message, VapidAuthentication authentication, VapidAuthenticationScheme authenticationScheme)
        {
            authentication = authentication ?? DefaultAuthentication;
            if (authentication == null)
            {
                throw new InvalidOperationException("The VAPID authentication information is not available");
            }

            HttpRequestMessage pushMessageDeliveryRequest = new HttpRequestMessage(HttpMethod.Post, subscription.Endpoint)
            {
                Headers =
                {
                    { TTL_HEADER_NAME, (message.TimeToLive ?? DefaultTimeToLive).ToString(CultureInfo.InvariantCulture) }
                }
            };

            pushMessageDeliveryRequest = SetAuthentication(pushMessageDeliveryRequest, subscription, authentication, authenticationScheme);
            pushMessageDeliveryRequest = SetUrgency(pushMessageDeliveryRequest, message);
            pushMessageDeliveryRequest = SetTopic(pushMessageDeliveryRequest, message);
            pushMessageDeliveryRequest = SetContent(pushMessageDeliveryRequest, subscription, message);

            return(pushMessageDeliveryRequest);
        }
 /// <summary>
 /// Requests delivery of push message by push service as an asynchronous operation.
 /// </summary>
 /// <param name="subscription">The push service subscription.</param>
 /// <param name="message">The push message.</param>
 /// <param name="authentication">The authentication details.</param>
 /// <param name="authenticationScheme">The <see cref="VapidAuthenticationScheme"/> to use.</param>
 /// <returns>The task object representing the asynchronous operation.</returns>
 public Task RequestPushMessageDeliveryAsync(PushSubscription subscription, PushMessage message, VapidAuthentication authentication, VapidAuthenticationScheme authenticationScheme)
 {
     return(RequestPushMessageDeliveryAsync(subscription, message, authentication, authenticationScheme, CancellationToken.None));
 }