private static void SetManagedHandlerProperty(HttpClientHandler handler, string name, object value) { // TODO #23166: Use the managed API for ConnectionIdleTimeout when it's exposed object managedHandler = handler.GetType().GetField("_managedHandler", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(handler); managedHandler.GetType().GetProperty(name).SetValue(managedHandler, value); }
/// <summary> /// sets the ip endpoint to use for the connections estabilished by this HttpClientHandler /// </summary> /// <param name="handler"></param> /// <param name="biep"></param> public static void SetServicePointOptions(this HttpClientHandler handler, BindIPEndPoint biep) { if (handler == null) { throw new ArgumentNullException("handler cannot be null"); } var field = handler.GetType().GetField("_startRequest", BindingFlags.NonPublic | BindingFlags.Instance); // Fieldname has a _ due to being private if (field == null) { throw new ArgumentNullException($"Field _startRequest not found in handler type {handler.GetType()}"); } var startRequest = field.GetValue(handler) as Action <object>; if (startRequest == null) { throw new ArgumentNullException("startRequest value is null"); } Action <object> newStartRequest = obj => { var webReqField = obj.GetType().GetField("webRequest", BindingFlags.NonPublic | BindingFlags.Instance); if (webReqField == null) { throw new ArgumentNullException($"webRequest is not set on type {obj.GetType()}"); } var webRequest = webReqField.GetValue(obj) as HttpWebRequest; if (webRequest == null) { throw new ArgumentNullException($"webRequest is null"); } webRequest.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(biep); startRequest(obj); //call original action }; field.SetValue(handler, newStartRequest); //replace original 'startRequest' with the one above }
public HandlerWrapper(HttpClientHandler handler) { this.handlerType = handler.GetType().Name; this.handler = handler; }
// NOTE: this method replicates the logic that the base ServiceClient uses except that it doesn't insert the RetryDelegatingHandler // and it does insert the WatcherDelegatingHandler. we don't want the RetryDelegatingHandler because it has a very broad definition // of what requests have failed. it considers everything outside 2xx to be failed, including 1xx (e.g. 101 Switching Protocols) and // 3xx. in particular, this prevents upgraded connections and certain generic/custom requests from working. private void CreateHttpClient(DelegatingHandler[] handlers, KubernetesClientConfiguration config) { FirstMessageHandler = HttpClientHandler = CreateRootHandler(); #if NET5_0 // https://github.com/kubernetes-client/csharp/issues/587 // let user control if tcp keep alive until better fix if (config.TcpKeepAlive) { // https://github.com/kubernetes-client/csharp/issues/533 // net5 only // this is a temp fix to attach SocketsHttpHandler to HttpClient in order to set SO_KEEPALIVE // https://tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/ // // _underlyingHandler is not a public accessible field // src of net5 HttpClientHandler and _underlyingHandler field defined here // https://github.com/dotnet/runtime/blob/79ae74f5ca5c8a6fe3a48935e85bd7374959c570/src/libraries/System.Net.Http/src/System/Net/Http/HttpClientHandler.cs#L22 // // Should remove after better solution var sh = new SocketsHttpHandler(); sh.ConnectCallback = async(context, token) => { var socket = new Socket(SocketType.Stream, ProtocolType.Tcp) { NoDelay = true, }; socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); var host = context.DnsEndPoint.Host; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // https://github.com/dotnet/runtime/issues/24917 // GetHostAddresses will return {host} if host is an ip var ips = Dns.GetHostAddresses(host); if (ips.Length == 0) { throw new Exception($"{host} DNS lookup failed"); } host = ips[new Random().Next(ips.Length)].ToString(); } await socket.ConnectAsync(host, context.DnsEndPoint.Port, token).ConfigureAwait(false); return(new NetworkStream(socket, ownsSocket: true)); }; // set HttpClientHandler's cert callback before replace _underlyingHandler // force HttpClientHandler use our callback InitializeFromConfig(config); var p = HttpClientHandler.GetType().GetField("_underlyingHandler", BindingFlags.NonPublic | BindingFlags.Instance); p.SetValue(HttpClientHandler, (sh)); } #endif if (handlers == null || handlers.Length == 0) { // ensure we have at least one DelegatingHandler so AppendDelegatingHandler will work FirstMessageHandler = new ForwardingHandler(HttpClientHandler); } else { for (int i = handlers.Length - 1; i >= 0; i--) { DelegatingHandler handler = handlers[i]; while (handler.InnerHandler is DelegatingHandler d) { handler = d; } handler.InnerHandler = FirstMessageHandler; FirstMessageHandler = handlers[i]; } } AppendDelegatingHandler <WatcherDelegatingHandler>(); HttpClient = new HttpClient(FirstMessageHandler, false); }