/// <summary>
 /// Add a header to this request.
 /// </summary>
 /// <param name="builder">The builder we're working on.</param>
 /// <param name="name">The header name to add to this request.</param>
 /// <param name="value">The header value (for <paramref name="name"/>) to add to this request.</param>
 /// <returns>The request builder for chaining.</returns>
 public static IRequestBuilder AddHeader(this IRequestBuilder builder, string name, string value)
 {
     if (!string.IsNullOrEmpty(name))
     {
         try
         {
             builder.Message.Headers.Add(name, value);
         }
         catch (Exception e)
         {
             var wrapper = new HttpClientException("Unable to set header: " + name + " to '" + value + "'", builder.Message.RequestUri, e);
             builder.GetSettings().OnException(builder, new HttpExceptionArgs(builder, wrapper));
         }
     }
     return(builder);
 }
        /// <summary>
        /// Adds headers to this request.
        /// </summary>
        /// <param name="builder">The builder we're working on.</param>
        /// <param name="headers">The headers to add to this request.</param>
        /// <returns>The request builder for chaining.</returns>
        public static IRequestBuilder AddHeaders(this IRequestBuilder builder, IDictionary <string, string> headers)
        {
            if (headers == null)
            {
                return(builder);
            }

            var pHeaders = builder.Message.Headers;

            foreach (var kv in headers)
            {
                try
                {
                    //pHeaders.Add(kv.Key, kv.Value);
                    switch (kv.Key)
                    {
                    //    certain headers must be accessed via the named property on the WebRequest
                    case "Accept": pHeaders.Accept.ParseAdd(kv.Value); break;

                    //    case "Connection": break;
                    //    case "proxy-connection": break;
                    //    case "Proxy-Connection": break;
                    //    case "Content-Length": break;
                    case "Content-Type": builder.Message.Content.Headers.ContentType = new MediaTypeHeaderValue(kv.Value); break;

                    //    case "Host": break;
                    //    case "If-Modified-Since": pHeaders.IfModifiedSince = DateTime.ParseExact(kv.Value, "R", CultureInfo.InvariantCulture); break;
                    //    case "Referer": pHeaders.Referrer = new Uri(kv.Value); break;
                    //    case "User-Agent": pHeaders.UserAgent.ParseAdd("Stack Exchange (Proxy)"); break;
                    default: pHeaders.Add(kv.Key, kv.Value); break;
                    }
                }
                catch (Exception e)
                {
                    var wrapper = new HttpClientException("Unable to set header: " + kv.Key + " to '" + kv.Value + "'", builder.Message.RequestUri, e);
                    builder.GetSettings().OnException(builder, new HttpExceptionArgs(builder, wrapper));
                }
            }
            return(builder);
        }
Ejemplo n.º 3
0
        internal static async Task <HttpCallResponse <T> > SendAsync <T>(IRequestBuilder <T> builder, HttpMethod method, CancellationToken cancellationToken = default)
        {
            // default to global settings
            var settings = builder.GetSettings();

            settings.OnBeforeSend(builder, builder.Inner);

            var request = builder.Inner.Message;

            request.Method = method;

            Exception           exception = null;
            HttpResponseMessage response  = null;

            try
            {
                using (settings.ProfileRequest?.Invoke(request))
                    using (request)
                    {
                        // Get the pool
                        var pool = builder.Inner.ClientPool ?? settings.ClientPool;

                        var completionOption = builder.Inner.BufferResponse ? HttpCompletionOption.ResponseContentRead : HttpCompletionOption.ResponseHeadersRead;

                        // Send the request
                        using (response = await pool.Get(builder.Inner).SendAsync(request, completionOption, cancellationToken))
                        {
                            // If we haven't ignored it, throw and we'll log below
                            // This isn't ideal cntrol flow behavior, but it's the only way to get proper stacks
                            if (!response.IsSuccessStatusCode && !builder.Inner.IgnoredResponseStatuses.Contains(response.StatusCode))
                            {
                                exception = new HttpClientException($"Response code was {(int)response.StatusCode} ({response.StatusCode}) from {response.RequestMessage.RequestUri}: {response.ReasonPhrase}", response.StatusCode, response.RequestMessage.RequestUri);
                                stackTraceString.SetValue(exception, new StackTrace(true).ToString());
                            }
                            else
                            {
                                var data = await builder.Handler(response);

                                return(HttpCallResponse.Create(response, data));
                            }
                        }
                    }
            }
            catch (OperationCanceledException ex)
            {
                exception = cancellationToken.IsCancellationRequested
                    ? new HttpClientException("HttpClient request cancelled by token request.", builder.Inner.Message.RequestUri, ex)
                    : new HttpClientException("HttpClient request timed out. Timeout: " + builder.Inner.Timeout.TotalMilliseconds.ToString("N0") + "ms", builder.Inner.Message.RequestUri, ex);
            }
            catch (Exception ex)
            {
                exception = ex;
            }

            // Use the response if we have it - request if not
            var result = response != null
                ? HttpCallResponse.Create <T>(response, exception)
                : HttpCallResponse.Create <T>(request, exception);

            // Add caller member bits to the exception data regardless of where it's eventually logged.
            (builder.Inner as HttpBuilder)?.AddExceptionData(exception);

            // If we're told not to log at all, don't log
            if (builder.Inner.LogErrors)
            {
                var args = new HttpExceptionArgs(builder.Inner, exception);
                builder.Inner.OnBeforeExceptionLog(args);

                if (!args.AbortLogging)
                {
                    settings.OnException(builder, args);
                }
            }

            return(result);
        }