Esempio n. 1
0
        public async Task HttpClient_IncludesContentLengthHeaderOnExpectedHttpVerbs(HttpMethod httpMethod)
        {
            BatchSharedKeyCredential creds = new BatchSharedKeyCredential(ClientUnitTestCommon.DummyAccountName, ClientUnitTestCommon.DummyAccountKey);

            HttpRequestMessage message = new HttpRequestMessage(httpMethod, url);

            message.Headers.Add("client-request-id", Guid.NewGuid().ToString());

            await creds.ProcessHttpRequestAsync(message, CancellationToken.None);

            Assert.NotNull(message.Headers.Authorization);

            var settings = new WebListenerSettings()
            {
                Authentication = { Schemes = AuthenticationSchemes.None },
                UrlPrefixes    = { url }
            };

            using (WebListener listener = new WebListener(settings))
            {
                listener.Start();
                Task listenTask = AcceptAndAssertAsync(httpMethod, listener, AssertRequestHasExpectedContentLength);

                HttpClient client = new HttpClient();
                await client.SendAsync(message);

                await listenTask;
            }
        }
Esempio n. 2
0
        public static async Task Run(string[] args)
        {
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add("http://localhost:8080");

            using (WebListener listener = new WebListener(settings))
            {
                listener.Start();

                Console.WriteLine("Running...");
                while (true)
                {
                    RequestContext context = await listener.AcceptAsync();

                    Console.WriteLine("Accepted");

                    // Context:
                    // context.User;
                    // context.DisconnectToken
                    // context.Dispose()
                    // context.Abort();

                    // Request
                    // context.Request.ProtocolVersion
                    // context.Request.Headers
                    // context.Request.Method
                    // context.Request.Body
                    // Content-Length - long?
                    // Content-Type - string
                    // IsSecureConnection
                    // HasEntityBody


                    // Response
                    byte[] bytes = Encoding.ASCII.GetBytes("Hello World: " + DateTime.Now);

                    if (context.IsWebSocketRequest)
                    {
                        Console.WriteLine("WebSocket");
                        WebSocket webSocket = await context.AcceptWebSocketAsync();

                        await webSocket.SendAsync(new ArraySegment <byte>(bytes, 0, bytes.Length), WebSocketMessageType.Text, true, CancellationToken.None);

                        await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Goodbye", CancellationToken.None);

                        webSocket.Dispose();
                    }
                    else
                    {
                        Console.WriteLine("Hello World");
                        context.Response.ContentLength = bytes.Length;
                        context.Response.ContentType   = "text/plain";

                        context.Response.Body.Write(bytes, 0, bytes.Length);
                        context.Dispose();
                    }
                }
            }
        }
Esempio n. 3
0
        static async void ProcessRequest()
        {
            int count    = 0;
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add("http://localhost:9000");
            using (WebListener listener = new WebListener(settings))
            {
                listener.Start();
                while (true)
                {
                    var context = await listener.AcceptAsync();

                    byte[] bytes = Encoding.ASCII.GetBytes(
                        "ConnectionId" + context.Request.ToString() +
                        "\nHeaders" + context.Request.Headers
                        + "\n" + DateTime.Now);
                    context.Response.ContentLength = bytes.Length;
                    context.Response.ContentType   = "text/plain";
                    await context.Response.Body.WriteAsync(bytes, 0, bytes.Length);

                    context.Dispose();
                    Console.WriteLine("Request==>{0}", ++count);
                }
            }
        }
Esempio n. 4
0
        /// <summary>
        /// Starts the service if it's not already running.
        /// </summary>
        public static void Start()
        {
            lock (syncLock)
            {
                if (listener != null)
                {
                    return; // Already running.
                }

                try
                {
                    var settings = new WebListenerSettings();

                    settings.UrlPrefixes.Add($"http://localhost:{KubeHelper.ClientConfig.DesktopServicePort}/");

                    listener = new WebListener(settings);
                    listener.Start();

                    // Handle received requests in a background task.

                    Task.Run(() => RequestProcessor());
                }
                catch
                {
                    listener = null;
                    throw;
                }
            }
        }
        /// <summary>
        /// Captures the requests.
        /// </summary>
        /// <param name="count">The counter variable.</param>
        /// <returns>A <see cref="Task"/> representing any asynchronous operation.</returns>
        public static async Task <IList <JsonElement> > CaptureRequestsAsync(int count)
        {
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add(TestWebHook);

            var result = new List <JsonElement>();

            using (var listener = new WebListener(settings))
            {
                listener.Start();

                while (count-- > 0)
                {
                    using (var requestContext = await listener.AcceptAsync().WithTimeout(TimeSpan.FromSeconds(6)).ConfigureAwait(false))
                    {
                        var body = ReadBodyStream(requestContext.Request.Body);
                        result.Add(body);
                        requestContext.Response.StatusCode = 204;
                    }
                }
            }

            return(result);
        }
Esempio n. 6
0
        private void StartHttpListener()
        {
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add(Configuration.RedirectUrl);
            WebListener = new WebListener(settings);

            WebListener.Start();
        }
        public HttpReceiver(string httpAddress, int port)
        {
            _port    = port;
            _address = httpAddress;
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add($"{_address}:{_port}");
            _webListener = new WebListener(settings);
        }
        /// <summary>
        /// Initializes the Httplistener to listen to a particular port of localhost
        /// </summary>
        /// <param name="port"></param>
        public MockWebServer(int port)
        {
            _threadWorker = new Thread(Run);
            _list         = new Queue <MockResponse>();
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add("http://" + Host + ":" + port + "/");
            _webListener = new WebListener(settings);
        }
Esempio n. 9
0
 public void Start()
 {
     var settings = new WebListenerSettings();
     settings.UrlPrefixes.Add((string)urlPrefix);
     stopTokenSource = new CancellationTokenSource();
     listener = new WebListener(settings);
     listener.Start();
     workerTask = Task.Run(Listen);
     client = new HttpClient();
 }
Esempio n. 10
0
        private async static Task SignInAsync()
        {
            // create a redirect URI using an available port on the loopback address.
            string redirectUri = string.Format("http://127.0.0.1:7890/");

            // create an HttpListener to listen for requests on that redirect URI.
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add(redirectUri);
            var http = new WebListener(settings);

            http.Start();
            Console.WriteLine("Listening..");

            var options = new OidcClientOptions
            {
                Authority    = _authority,
                ClientId     = "native.hybrid",
                RedirectUri  = redirectUri,
                Scope        = "openid profile api",
                FilterClaims = true,
                LoadProfile  = true,
                Flow         = OidcClientOptions.AuthenticationFlow.Hybrid
            };

            var serilog = new LoggerConfiguration()
                          .MinimumLevel.Verbose()
                          .Enrich.FromLogContext()
                          .WriteTo.LiterateConsole(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}")
                          .CreateLogger();

            options.LoggerFactory.AddSerilog(serilog);

            var client = new OidcClient(options);
            var state  = await client.PrepareLoginAsync();

            OpenBrowser(state.StartUrl);

            var context = await http.AcceptAsync();

            var formData = GetRequestPostData(context.Request);

            if (formData == null)
            {
                Console.WriteLine("Invalid response");
                return;
            }

            await SendResponseAsync(context.Response);

            var result = await client.ProcessResponseAsync(formData, state);

            ShowResult(result);
        }
Esempio n. 11
0
        public async Task SignInAsync(AuthenticationOptions authOptions)
        {
            // create a redirect URI using an available port on the loopback address.
            var redirectUri = "http://127.0.0.1:7890/";

            // create an HttpListener to listen for requests on that redirect URI.
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add(redirectUri);
            using (var http = new WebListener(settings))
            {
                http.Start();

                var options = new OidcClientOptions
                {
                    Authority    = authOptions.Url,
                    ClientId     = authOptions.ClientId,
                    ClientSecret = authOptions.ClientSecret,
                    RedirectUri  = redirectUri,
                    Scope        = "openid profile auth_api.Internal",
                    FilterClaims = true,
                    LoadProfile  = true,
                    Flow         = OidcClientOptions.AuthenticationFlow.Hybrid
                };

                var client = new OidcClient(options);
                var state  = await client.PrepareLoginAsync();

                OpenBrowser(state.StartUrl);

                var context = await http.AcceptAsync();

                var formData = GetRequestPostData(context.Request);

                if (formData == null)
                {
                    throw new AuthenticationException("Invalid response");
                }

                await SendResponseAsync(context.Response);

                var result = await client.ProcessResponseAsync(formData, state);

                if (result.IsError)
                {
                    throw new AuthenticationException(result.Error);
                }

                m_authTokenProvider.AuthToken = result.AccessToken;
            }
        }
Esempio n. 12
0
        private static async Task <string> Authorize()
        {
            var patreonApi = new PatreonApi(clientId, clientSecret, redirectURI);

            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add("http://localhost:3000");

            var uri =
                patreonApi.BuildAuthorizeEndpoint(new List <string>( )
            {
                "identity", "identity.memberships", "campaigns", "campaigns.members"
            });

            string queryString = string.Empty;

            using (WebListener listener = new WebListener(settings))
            {
                listener.Start();

                // Opens request in the browser.
                OpenBrowser(uri.ToString());

                using (var context = await listener.AcceptAsync())
                {
                    byte[] bytes = Encoding.ASCII.GetBytes("<html><head><meta http-equiv=\'refresh\'></head><body>Success</body></html>");
                    context.Response.ContentLength = bytes.Length;
                    context.Response.ContentType   = "text/html";

                    await context.Response.Body.WriteAsync(bytes, 0, bytes.Length);

                    queryString = context.Request.QueryString;
                }
            }

            var queryDictionary = HttpUtility.ParseQueryString(queryString);

            // Checks for errors.
            if (queryDictionary.GetValues("error")?.FirstOrDefault() != null)
            {
                return(string.Empty);
            }
            if (queryDictionary.GetValues("code")?.FirstOrDefault() == null)
            {
                return(string.Empty);
            }

            // extracts the code
            return(queryDictionary.GetValues("code").FirstOrDefault());
        }
Esempio n. 13
0
        private async static Task SignInAsync()
        {
            // create a redirect URI using an available port on the loopback address.
            string redirectUri = string.Format("http://127.0.0.1:45656");

            // create an HttpListener to listen for requests on that redirect URI.
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add(redirectUri);
            var http = new WebListener(settings);

            http.Start();
            Console.WriteLine("Listening..");

            var options = new OidcClientOptions
            {
                Authority    = _authority,
                ClientId     = "oidcMVCApp",
                ClientSecret = "ProCodeGuide",
                RedirectUri  = redirectUri,
                Scope        = "weatherApi.read openid profile",
                FilterClaims = true,
                LoadProfile  = true,
            };

            var client = new OidcClient(options);
            var state  = await client.PrepareLoginAsync();

            Console.WriteLine($"State: {System.Text.Json.JsonSerializer.Serialize(state)}");

            OpenBrowser(state.StartUrl);

            var context = await http.AcceptAsync();

            var formData = GetRequestPostData(context.Request);

            if (formData == null)
            {
                Console.WriteLine("Invalid response");
                return;
            }

            await SendResponseAsync(context.Response);

            var result = await client.ProcessResponseAsync(context.Request.RawUrl, state);

            ShowResult(result);
        }
Esempio n. 14
0
        private async static Task SignInAsync()
        {
            string redirectUri = string.Format("http://127.0.0.1:7890/");
            var    settings    = new WebListenerSettings();

            settings.UrlPrefixes.Add(redirectUri);
            var http = new WebListener(settings);

            http.Start();

            var options = new OidcClientOptions
            {
                Authority    = _authority,
                ClientId     = "demo-app",
                RedirectUri  = redirectUri,
                Scope        = "openid",
                FilterClaims = true,
                LoadProfile  = true,
                Flow         = OidcClientOptions.AuthenticationFlow.AuthorizationCode,
                Policy       = new Policy()
                {
                    RequireAccessTokenHash = false
                }
            };

            var client = new OidcClient(options);
            var state  = await client.PrepareLoginAsync();

            OpenBrowser(state.StartUrl);

            var context = await http.AcceptAsync();

            var formData = GetRequestPostData(context.Request);

            if (formData == null)
            {
                Console.WriteLine("Invalid response");
                return;
            }

            await SendResponseAsync(context.Response);

            var result = await client.ProcessResponseAsync(formData, state);

            ShowResult(result);
        }
        private void ListenThread(object obj)
        {
            var settings  = new WebListenerSettings();
            var urlPrefix = $"http://{this.host}:{this.port}/";

            // File.WriteAllText("C:\\Temp\\UrlPrefixes.txt", urlPrefix);
            settings.UrlPrefixes.Add(urlPrefix);

            this.listener = new WebListener(settings);
            this.listener.Start();

            while (this.threadRunning)
            {
                var task = listener.AcceptAsync();

                task.ContinueWith(o =>
                {
                    if (o.IsFaulted)
                    {
                        return;
                    }

                    var context = o.Result;
                    if (context.Request.Method == "GET")
                    {
                        HandleGetRequest(context);
                    }
                    if (context.Request.Method == "POST")
                    {
                        HandlePostRequest(context);
                    }
                    if (context.Request.Method == "PUT")
                    {
                        HandlePutRequest(context);
                    }
                    if (context.Request.Method == "OPTIONS")
                    {
                        HandleOptionsRequest(context);
                    }
                    if (context.Request.Method == "DELETE")
                    {
                        HandleDeleteRequest(context);
                    }
                }).Wait();
            }
        }
Esempio n. 16
0
        public static async Task Run(string[] args)
        {
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add($"http://{args[1]}:80");

            using (WebListener listener = new WebListener(settings))
            {
                using (var sem = new Semaphore(0, 1, $"{args[1]}"))
                {
                    sem.Release();
                    listener.Start();
                }

                Console.WriteLine("{0} started", DateTime.UtcNow.ToString("o"));
                while (true)
                {
                    RequestContext context = await listener.AcceptAsync();

                    Console.WriteLine("{0} accepted", DateTime.UtcNow.ToString("o"));

                    // Response
                    var html  = Path.Combine(_path, "index.html");
                    var bytes = File.ReadAllBytes(html);

                    if (context.Request.Path != "/")
                    {
                        StringBuilder strb = new StringBuilder();
                        foreach (ProcessModule module in Process.GetCurrentProcess().Modules)
                        {
                            strb.AppendLine(module.FileName);
                        }
                        bytes = Encoding.UTF8.GetBytes(strb.ToString());
                    }

                    //Console.WriteLine("Hello World");
                    context.Response.ContentLength = bytes.Length;
                    context.Response.ContentType   = "text/plain";

                    context.Response.Body.Write(bytes, 0, bytes.Length);
                    context.Dispose();
                }
            }
        }
Esempio n. 17
0
        private static async Task SignInAsync()
        {
            // create an HttpListener to listen for requests on that redirect URI.
            string redirectUri = string.Format("http://127.0.0.1:7890");

            WebListenerSettings settings = new WebListenerSettings();

            settings.UrlPrefixes.Add(redirectUri);
            WebListener http = new WebListener(settings);

            http.Start();
            Console.WriteLine("Listening..");

            OidcClientOptions options = new OidcClientOptions
            {
                Authority    = "https://localhost:62189/identity",
                RedirectUri  = redirectUri,
                ClientId     = "console",
                ClientSecret = "peng",
                Scope        = "openid offline_access",
                Flow         = OidcClientOptions.AuthenticationFlow.Hybrid
            };

            OidcClient     client = new OidcClient(options);
            AuthorizeState state  = await client.PrepareLoginAsync();

            OpenBrowser(state.StartUrl);

            RequestContext context = await http.AcceptAsync();

            string formData = GetRequestPostData(context.Request);

            if (formData == null)
            {
                Console.WriteLine("Invalid response");
                return;
            }

            await SendResponseAsync(context.Response);

            LoginResult result = await client.ProcessResponseAsync(formData, state);

            ShowResult(result);
        }
Esempio n. 18
0
        /// <summary>
        /// Constuctor.
        /// </summary>
        /// <param name="urlPrefix">Specifies the URL prefixes to be served.</param>
        /// <param name="handler">The custom asynchronous request handler.</param>
        public MockHttpServer(string urlPrefix, Func <RequestContext, Task> handler)
        {
            Covenant.Requires <ArgumentNullException>(urlPrefix != null, nameof(urlPrefix));
            Covenant.Requires <ArgumentNullException>(handler != null, nameof(handler));

            if (!NeonHelper.IsWindows)
            {
                throw new NotImplementedException($"[{nameof(MockHttpServer)}] works only on Windows.");
            }

            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add(urlPrefix);

            this.handler  = handler;
            this.listener = new WebListener(settings);
            this.listener.Start();

            // Handle received requests in a background task.

            Task.Run(() => RequestProcessor());
        }
Esempio n. 19
0
        private async static Task SignInAsync()
        {
            // create a redirect URI using an available port on the loopback address.
            string redirectUri = string.Format("http://127.0.0.1:7890/");

            // create an HttpListener to listen for requests on that redirect URI.
            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add(redirectUri);
            var http = new WebListener(settings);

            http.Start();
            Console.WriteLine("Listening..");

            var options = new OidcClientOptions
            {
                Authority    = _authority,
                ClientId     = "native.hybrid",
                RedirectUri  = redirectUri,
                Scope        = "openid profile offline_access read api",
                ClientSecret = "secret",
                FilterClaims = true,
                LoadProfile  = true,
                Flow         = OidcClientOptions.AuthenticationFlow.Hybrid
            };

            var serilog = new LoggerConfiguration()
                          .MinimumLevel.Verbose()
                          .Enrich.FromLogContext()
                          .WriteTo.LiterateConsole(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message}{NewLine}{Exception}{NewLine}")
                          .CreateLogger();

            options.LoggerFactory.AddSerilog(serilog);

            var client = new OidcClient(options);
            var state  = await client.PrepareLoginAsync();

            OpenBrowser(state.StartUrl);

            var context = await http.AcceptAsync();

            var formData = GetRequestPostData(context.Request);

            if (formData == null)
            {
                Console.WriteLine("Invalid response");
                return;
            }

            await SendResponseAsync(context.Response);

            var result = await client.ProcessResponseAsync(formData, state);

            options.Policy.ForceIntrospectionForAccessToken = true;
            //-- Test POP generation
            var testPop = client.CreatePopToken(new IdentityModel.OidcClient.Pop.EncodingParameters(options, result.AccessToken)
            {
                Method = "GET"
            }.ToJwtPayload(), result.PopTokenKey).ToSignedB64String();

            Console.WriteLine($"Generated PoP Token: {testPop}");

            //--Test validation...
            var testValidate = await client.ValidatePopToken(testPop, false, "read", "secret");

            Console.WriteLine($"PoP Token Valid: {!testValidate.IsError}");

            //--Test refresh
            var refreshResult = await client.RefreshTokenAsync(result.RefreshToken);

            var refreshValidate = client.CreatePopToken(new IdentityModel.OidcClient.Pop.EncodingParameters(options, refreshResult.AccessToken)
            {
                Method = "GET"
            }.ToJwtPayload(), refreshResult.PopTokenKey).ToSignedB64String();
            var refreshValid = await client.ValidatePopToken(refreshValidate, false, "read", "secret");

            var oldValidate = client.CreatePopToken(new IdentityModel.OidcClient.Pop.EncodingParameters(options, result.AccessToken)
            {
                Method = "GET"
            }.ToJwtPayload(), result.PopTokenKey).ToSignedB64String();
            var oldValid = await client.ValidatePopToken(oldValidate, false, "read", "secret");

            Console.WriteLine($"Generated PoP Token after refresh: {testPop}");
            Console.WriteLine($"PoP Token (using refreshed access token) Valid: {!refreshValid.IsError}");
            Console.WriteLine($"PoP Token (using old access token) Valid: {!oldValid.IsError}"); //Depending on how implemented - this should not work for an old token after the refresh token has been used.

            //--Revoke the tokens.
            var revokeClient = new TokenRevocationClient($"{options.Authority}/connect/revocation", options.ClientId, options.ClientSecret);
            var revokeResult = await revokeClient.RevokeRefreshTokenAsync(refreshResult.RefreshToken);

            Console.WriteLine($"Token revocation succeeded: {!revokeResult.IsError}");

            ShowResult(result);
        }
Esempio n. 20
0
        /// <summary>
        /// Constructs a reverse proxy.
        /// </summary>
        /// <param name="localPort">The local port.</param>
        /// <param name="remotePort">The remote port.</param>
        /// <param name="remoteHost">Optionally specifies the remote hostname or IP address.</param>
        /// <param name="remoteTls">Optionally indicates that the remote endpoint required TLS.</param>
        /// <param name="validCertificate">
        /// Optionally specifies an acceptable server certificate.  This can be used 
        /// as a way to allow access for a specific self-signed certificate.  Passing 
        /// a certificate implies <paramref name="remoteTls"/><c>=true</c>.
        /// </param>
        /// <param name="clientCertificate">
        /// Optionally specifies a client certificate.  Passing a certificate implies
        /// <paramref name="remoteTls"/><c>=true</c>.
        /// </param>
        /// <param name="requestHandler">Optional request hook.</param>
        /// <param name="responseHandler">Optional response hook.</param>
        public ReverseProxy(
            int                     localPort,
            int                     remotePort,
            string                  remoteHost        = "localhost",
            bool                    remoteTls         = false,
            X509Certificate2        validCertificate  = null,
            X509Certificate2        clientCertificate = null,
            Action<RequestContext>  requestHandler    = null, 
            Action<RequestContext>  responseHandler   = null)
        {
            Covenant.Requires<ArgumentException>(NetHelper.IsValidPort(localPort));
            Covenant.Requires<ArgumentException>(NetHelper.IsValidPort(remotePort));

            if (validCertificate != null || clientCertificate != null)
            {
                remoteTls = true;
            }

            if (!NeonHelper.IsWindows)
            {
                throw new NotSupportedException($"[{nameof(ReverseProxy)}] is supported only on Windows.");
            }

            this.localPort       = localPort;
            this.remotePort      = remotePort;
            this.requestHandler  = requestHandler;
            this.responseHandler = responseHandler;

            // Create the client.

            var remoteScheme = remoteTls ? "https" : "http";

            // $todo(jeff.lill):
            //
            // Enable this when we upgrade to .NET Standard 2.1
            //
            //      https://github.com/nforgeio/neonKUBE/issues/new

#if NETSTANDARD_21
            var httpHandler  =
                new SocketsHttpHandler()
                {
                    AllowAutoRedirect           = false,
                    AutomaticDecompression      = DecompressionMethods.All,
                    ConnectTimeout              = TimeSpan.FromSeconds(5),
                    MaxConnectionsPerServer     = 100,
                    PooledConnectionIdleTimeout = TimeSpan.FromSeconds(10),
                    PooledConnectionLifetime    = TimeSpan.FromSeconds(60),
                    ResponseDrainTimeout        = TimeSpan.FromSeconds(10),
                };

            if (clientCertificate != null)
            {
                // This option lets the operating system decide what versions
                // of SSL/TLS and certificates/keys to allow.

                httpHandler.SslOptions.EnabledSslProtocols = SslProtocols.None;

                httpHandler.SslOptions.ClientCertificates = new X509CertificateCollection();
                httpHandler.SslOptions.ClientCertificates.Add(clientCertificate);

                httpHandler.SslOptions.LocalCertificateSelectionCallback =
                    (sender, targetHost, localCertificates, remoteCertificate, acceptableIssuers) =>
                    {
                        return clientCertificate;
                    };

            if (remoteTls)
            {
                httpHandler.SslOptions.RemoteCertificateValidationCallback =
                    (request, remoteCertificate, chain, policyErrors) =>
                    {
                        var remoteCertificate2 = (X509Certificate2)remoteCertificate;

                        // If this proxy instance was passed a server certificate,
                        // we're going to require that the remote certificate
                        // thumbprint matches that one.
                        //
                        // Otherwise, we're going to require that the remote
                        // certificate has been validated by the operating
                        // system.

                        if (validCertificate != null)
                        {
                            return remoteCertificate2.Thumbprint == validCertificate.Thumbprint;
                        }
                        else
                        {
                            return policyErrors == SslPolicyErrors.None;
                        }
                    };
            }
#else
            var httpHandler = new HttpClientHandler()
            {
                    AllowAutoRedirect       = false,
                    AutomaticDecompression  = DecompressionMethods.Deflate | DecompressionMethods.GZip,
                    MaxConnectionsPerServer = 100,
            };

            if (remoteTls)
            {
                httpHandler.ServerCertificateCustomValidationCallback =
                    (request, remoteCertificate, chain, policyErrors) =>
                    {
                        var remoteCertificate2 = (X509Certificate2)remoteCertificate;

                        // If this proxy instance was passed a server certificate,
                        // we're going to require that the remote certificate
                        // thumbprint matches that one.
                        //
                        // Otherwise, we're going to require that the remote
                        // certificate has been validated by the operating
                        // system.

                        if (validCertificate != null)
                        {
                            return remoteCertificate2.Thumbprint == validCertificate.Thumbprint;
                        }
                        else
                        {
                            return policyErrors == SslPolicyErrors.None;
                        }
                    };
            }
#endif

            client = new HttpClient(httpHandler, disposeHandler: true)
            {
                 BaseAddress = new Uri($"{remoteScheme}://{remoteHost}:{remotePort}/")
            };

            // Initialize the buffer pool.  We're going to use this to share
            // bufferes across requests to reduce pressure on the garbage 
            // collector.

            bufferPool = new Queue<byte[]>();

            // Crank up the HTTP listener.

            var settings = new WebListenerSettings();

            settings.UrlPrefixes.Add($"http://localhost:{localPort}/");

            this.listener = new WebListener(settings);
            this.listener.Start();

            // Handle received requests in a background task.

            Task.Run(() => RequestProcessor());
        }