예제 #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="WebRequester"/> class.
        /// </summary>
        /// <param name="createHandler"></param>
        /// <param name="options"></param>
        /// <param name="contentType">Type of the content.</param>
        public WebRequester(Func <string, HttpMessageHandler> createHandler, RequestOptions options, string contentType = "application/x-protobuf")
        {
            options.Validate();

            _createHttpClient = () =>
            {
                var httpClient = new HttpClient(createHandler(GetType().FullName), false)
                {
                    BaseAddress = options.BaseUri
                };

                if (options.Timeout > TimeSpan.Zero)
                {
                    httpClient.Timeout = options.Timeout;
                }

                httpClient.DefaultRequestHeaders.Accept.TryParseAdd(contentType);

                if (options.AdditionalHeaders != null)
                {
                    foreach (var kv in options.AdditionalHeaders)
                    {
                        httpClient.DefaultRequestHeaders.TryAddWithoutValidation(kv.Key, kv.Value);
                    }
                }

                return(httpClient);
            };
        }
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task <Response> IssueWebRequestAsync(
            string endpoint, string query, string method, Stream input, RequestOptions options)
        {
            options.Validate();
            Stopwatch  watch   = Stopwatch.StartNew();
            UriBuilder builder = new UriBuilder(
                _credentials.ClusterUri.Scheme,
                _credentials.ClusterUri.Host,
                options.Port,
                options.AlternativeEndpoint + endpoint);

            if (query != null)
            {
                builder.Query = query;
            }

            Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, builder.Uri);
            HttpWebRequest httpWebRequest = WebRequest.CreateHttp(builder.Uri);

            httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
            httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
            httpWebRequest.Timeout         = options.TimeoutMillis;
            httpWebRequest.KeepAlive       = options.KeepAlive;
            httpWebRequest.Credentials     = _credentialCache;
            httpWebRequest.PreAuthenticate = true;
            httpWebRequest.Method          = method;
            httpWebRequest.Accept          = _contentType;
            httpWebRequest.ContentType     = _contentType;
            // This allows 304 (NotModified) requests to catch
            //https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowautoredirect(v=vs.110).aspx
            httpWebRequest.AllowAutoRedirect = false;

            if (options.AdditionalHeaders != null)
            {
                foreach (var kv in options.AdditionalHeaders)
                {
                    httpWebRequest.Headers.Add(kv.Key, kv.Value);
                }
            }

            if (input != null)
            {
                // expecting the caller to seek to the beginning or to the location where it needs to be copied from
                using (Stream req = await httpWebRequest.GetRequestStreamAsync())
                {
                    await input.CopyToAsync(req);
                }
            }

            var response = (await httpWebRequest.GetResponseAsync()) as HttpWebResponse;

            return(new Response()
            {
                WebResponse = response,
                RequestLatency = watch.Elapsed
            });
        }
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task<Response> IssueWebRequestAsync(
            string endpoint, string query, string method, Stream input, RequestOptions options)
        {
            options.Validate();
            Stopwatch watch = Stopwatch.StartNew();
            UriBuilder builder = new UriBuilder(
                _credentials.ClusterUri.Scheme,
                _credentials.ClusterUri.Host,
                options.Port,
                options.AlternativeEndpoint + endpoint);

            if (query != null)
            {
                builder.Query = query;
            }
            
            Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, builder.Uri);
            HttpWebRequest httpWebRequest = WebRequest.CreateHttp(builder.Uri);
            httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
            httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
            httpWebRequest.Timeout = options.TimeoutMillis;
            httpWebRequest.KeepAlive = options.KeepAlive;
            httpWebRequest.Credentials = _credentialCache;
            httpWebRequest.PreAuthenticate = true;
            httpWebRequest.Method = method;
            httpWebRequest.Accept = _contentType;
            httpWebRequest.ContentType = _contentType;
            // This allows 304 (NotModified) requests to catch
            //https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowautoredirect(v=vs.110).aspx
            httpWebRequest.AllowAutoRedirect = false;

            if (options.AdditionalHeaders != null)
            {
                foreach (var kv in options.AdditionalHeaders)
                {
                    httpWebRequest.Headers.Add(kv.Key, kv.Value);
                }
            }

            if (input != null)
            {
                // expecting the caller to seek to the beginning or to the location where it needs to be copied from
                using (Stream req = await httpWebRequest.GetRequestStreamAsync())
                {
                    await input.CopyToAsync(req);
                }
            }

            var response = (await httpWebRequest.GetResponseAsync()) as HttpWebResponse;
            return new Response()
            {
                WebResponse = response,
                RequestLatency = watch.Elapsed
            };
        }
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="method">The method.</param>
        /// <param name="query">The query.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task<Response> IssueWebRequestAsync(
            string endpoint, string method, string query, Stream input, RequestOptions options)
        {
            options.Validate();
            Stopwatch watch = Stopwatch.StartNew();
            UriBuilder builder = new UriBuilder(
                _credentials.ClusterUri.Scheme,
                _credentials.ClusterUri.Host,
                options.Port,
                options.AlternativeEndpoint + endpoint);

            if (query != null)
            {
                builder.Query = query;
            }

            Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, builder.Uri);
            HttpWebRequest httpWebRequest = WebRequest.CreateHttp(builder.Uri);
            httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
            httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
            httpWebRequest.Timeout = options.TimeoutMillis;
            httpWebRequest.KeepAlive = options.KeepAlive;
            httpWebRequest.Credentials = _credentialCache;
            httpWebRequest.PreAuthenticate = true;
            httpWebRequest.Method = method;
            httpWebRequest.Accept = _contentType;
            httpWebRequest.ContentType = _contentType;

            if (options.AdditionalHeaders != null)
            {
                foreach (var kv in options.AdditionalHeaders)
                {
                    httpWebRequest.Headers.Add(kv.Key, kv.Value);
                }
            }

            if (input != null)
            {
                // seek to the beginning, so we copy everything in this buffer
                input.Seek(0, SeekOrigin.Begin);
                using (Stream req = httpWebRequest.GetRequestStream())
                {
                    await input.CopyToAsync(req);
                }
            }

            var response = (await httpWebRequest.GetResponseAsync()) as HttpWebResponse;
            return new Response()
            {
                WebResponse = response,
                RequestLatency = watch.Elapsed
            };
        }
예제 #5
0
        static async Task Main(string[] args)
        {
            var  options  = new RequestOptions();
            bool showHelp = false;

            OptionSet os = new OptionSet()
            {
                { "h|?|help", "Displays the help", v => showHelp = true },
                { "r|repository=", "Github repository to consider.", r => options.Repository = r },
                { "t|token=", "Token to use to communicate with Github via OctoKit", t => options.Pat = t },
                { "d|days=", "Show mentions in last given Days (Default 14)", d => options.Days = Int32.Parse(d) },
                { "l|label=", "Show mentions on issues with given Label (Default ci-failure)", l => options.Label = l },
                { "c|count=", "Show given top cross referenced items (Default 10)", c => options.Count = Int32.Parse(c) },
            };

            try {
                IList <string> unprocessed = os.Parse(args);
            } catch (Exception e) {
                Console.Error.WriteLine("Could not parse the command line arguments: {0}", e.Message);
                return;
            }

            if (showHelp)
            {
                ShowHelp(os);
                return;
            }

            options.Validate();

            var crossRefCount = await Issues.Create(options).Find();

            foreach (var issue in crossRefCount.OrderBy(x => x.ReferenceCount).Reverse().Take(options.Count))
            {
                Console.WriteLine($"{issue.ID} {issue.Title} {issue.ReferenceCount}");
            }
        }
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="query">The query to append.</param>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task <Response> IssueWebRequestAsync(
            string endpoint, string query, string method, Stream input, RequestOptions options)
        {
            options.Validate();
            var watch   = Stopwatch.StartNew();
            var builder = new UriBuilder(
                _credentials.ClusterUri.Scheme,
                _credentials.ClusterUri.Host,
                options.Port,
                options.AlternativeEndpoint + endpoint);

            if (query != null)
            {
                builder.Query = query;
            }

            Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, builder.Uri);
            var httpWebRequest = WebRequest.CreateHttp(builder.Uri);

            httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
            httpWebRequest.Timeout         = options.TimeoutMillis; // This has no influence for calls that are made Async
            httpWebRequest.KeepAlive       = options.KeepAlive;
            httpWebRequest.Credentials     = _credentialCache;
            httpWebRequest.PreAuthenticate = true;
            httpWebRequest.Method          = method;
            httpWebRequest.Accept          = _contentType;
            httpWebRequest.ContentType     = _contentType;
            // This allows 304 (NotModified) requests to catch
            //https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowautoredirect(v=vs.110).aspx
            httpWebRequest.AllowAutoRedirect = false;

            if (options.AdditionalHeaders != null)
            {
                foreach (var kv in options.AdditionalHeaders)
                {
                    httpWebRequest.Headers.Add(kv.Key, kv.Value);
                }
            }

            long remainingTime = options.TimeoutMillis;

            if (input != null)
            {
                // expecting the caller to seek to the beginning or to the location where it needs to be copied from
                Stream req = null;
                try
                {
                    req = await httpWebRequest.GetRequestStreamAsync().WithTimeout(
                        TimeSpan.FromMilliseconds(remainingTime),
                        "Waiting for RequestStream");

                    remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                    if (remainingTime <= 0)
                    {
                        remainingTime = 0;
                    }

                    await input.CopyToAsync(req).WithTimeout(
                        TimeSpan.FromMilliseconds(remainingTime),
                        "Waiting for CopyToAsync",
                        CancellationToken.None);
                }
                catch (TimeoutException)
                {
                    httpWebRequest.Abort();
                    throw;
                }
                finally
                {
                    if (req != null)
                    {
                        req.Close();
                    }
                }
            }

            try
            {
                remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                if (remainingTime <= 0)
                {
                    remainingTime = 0;
                }

                var response = (HttpWebResponse)await httpWebRequest.GetResponseAsync().WithTimeout(
                    TimeSpan.FromMilliseconds(remainingTime),
                    "Waiting for GetResponseAsync");

                return(new Response
                {
                    WebResponse = response,
                    RequestLatency = watch.Elapsed
                });
            }
            catch (TimeoutException)
            {
                httpWebRequest.Abort();
                throw;
            }
        }
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task<Response> IssueWebRequestAsync(string endpoint, string query, string method, Stream input, RequestOptions options)
        {
            options.Validate();
            Stopwatch watch = Stopwatch.StartNew();
            Trace.CorrelationManager.ActivityId = Guid.NewGuid();
            var balancedEndpoint = _balancer.GetEndpoint();

            // Grab the host. Use the alternative host if one is specified
            string host = (options.AlternativeHost != null) ? options.AlternativeHost : balancedEndpoint.Host;

            UriBuilder builder = new UriBuilder(
                balancedEndpoint.Scheme,
                host,
                options.Port,
                options.AlternativeEndpoint + endpoint);

            if (query != null)
            {
                builder.Query = query;
            }

            var target = builder.Uri;

            try
            {
                Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, target);

                HttpWebRequest httpWebRequest = WebRequest.CreateHttp(target);
                httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
                httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
                httpWebRequest.Timeout = options.TimeoutMillis; // This has no influence for calls that are made Async
                httpWebRequest.KeepAlive = options.KeepAlive;
                httpWebRequest.Credentials = _credentialCache;
                httpWebRequest.PreAuthenticate = true;
                httpWebRequest.Method = method;
                httpWebRequest.Accept = _contentType;
                httpWebRequest.ContentType = _contentType;
                // This allows 304 (NotModified) requests to catch
                //https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowautoredirect(v=vs.110).aspx
                httpWebRequest.AllowAutoRedirect = false;

                if (options.AdditionalHeaders != null)
                {
                    foreach (var kv in options.AdditionalHeaders)
                    {
                        httpWebRequest.Headers.Add(kv.Key, kv.Value);
                    }
                }
                long remainingTime = options.TimeoutMillis;

                if (input != null)
                {
                    // expecting the caller to seek to the beginning or to the location where it needs to be copied from
                    Stream req = null;
                    try
                    {
                        req = await httpWebRequest.GetRequestStreamAsync().WithTimeout(
                                                    TimeSpan.FromMilliseconds(remainingTime),
                                                    "Waiting for RequestStream");

                        remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                        if (remainingTime <= 0)
                        {
                            remainingTime = 0;
                        }

                        await input.CopyToAsync(req).WithTimeout(
                                    TimeSpan.FromMilliseconds(remainingTime),
                                    "Waiting for CopyToAsync",
                                    CancellationToken.None);
                    }
                    catch (TimeoutException)
                    {
                        httpWebRequest.Abort();
                        throw;
                    }
                    finally
                    {
                        req?.Close();
                    }
                }

                try
                {
                    remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                    if (remainingTime <= 0)
                    {
                        remainingTime = 0;
                    }

                    Debug.WriteLine("Waiting for response for request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, target);

                    HttpWebResponse response = (HttpWebResponse)await httpWebRequest.GetResponseAsync().WithTimeout(
                                                                    TimeSpan.FromMilliseconds(remainingTime),
                                                                    "Waiting for GetResponseAsync");

                    Debug.WriteLine("Web request {0} to endpoint {1} successful!", Trace.CorrelationManager.ActivityId, target);

                    return new Response()
                    {
                        WebResponse = response,
                        RequestLatency = watch.Elapsed,
                        PostRequestAction = (r) =>
                        {
                            if (r.WebResponse.StatusCode == HttpStatusCode.OK || r.WebResponse.StatusCode == HttpStatusCode.Created || r.WebResponse.StatusCode == HttpStatusCode.NotModified)
                            {
                                _balancer.RecordSuccess(balancedEndpoint);
                            }
                            else
                            {
                                _balancer.RecordFailure(balancedEndpoint);
                            }
                        }
                    };
                }
                catch (TimeoutException)
                {
                    httpWebRequest.Abort();
                    throw;
                }
            }
            catch(WebException we)
            {
                // 404 is valid response
                var resp = we.Response as HttpWebResponse;
                if(resp.StatusCode == HttpStatusCode.NotFound)
                {
                    _balancer.RecordSuccess(balancedEndpoint);
                    Debug.WriteLine("Web request {0} to endpoint {1} successful!", Trace.CorrelationManager.ActivityId, target);
                }
                else
                {
                    _balancer.RecordFailure(balancedEndpoint);
                    Debug.WriteLine("Web request {0} to endpoint {1} failed!", Trace.CorrelationManager.ActivityId, target);
                }
                throw we;
            }
            catch (Exception e)
            {
                _balancer.RecordFailure(balancedEndpoint);
                Debug.WriteLine("Web request {0} to endpoint {1} failed!", Trace.CorrelationManager.ActivityId, target);
                throw e;
            }
        }
예제 #8
0
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task <Response> IssueWebRequestAsync(
            string method, Stream input, RequestOptions options)
        {
            options.Validate();
            Stopwatch  watch   = Stopwatch.StartNew();
            UriBuilder builder = new UriBuilder(
                "http",
                options.AlternativeHost,
                options.Port,
                options.AlternativeEndpoint);

            Debug.WriteLine("Issuing request to endpoint {0}", builder.Uri);
            HttpWebRequest httpWebRequest = WebRequest.CreateHttp(builder.Uri);

            //httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
            httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
            httpWebRequest.Timeout         = options.TimeoutMillis;
            httpWebRequest.KeepAlive       = options.KeepAlive;
            httpWebRequest.Credentials     = null;
            httpWebRequest.PreAuthenticate = true;
            httpWebRequest.Method          = method;
            httpWebRequest.Accept          = _contentType;
            httpWebRequest.ContentType     = _contentType;

            if (options.AdditionalHeaders != null)
            {
                foreach (var kv in options.AdditionalHeaders)
                {
                    httpWebRequest.Headers.Add(kv.Key, kv.Value);
                }
            }

            long remainingTime = options.TimeoutMillis;

            if (input != null)
            {
                // expecting the caller to seek to the beginning or to the location where it needs to be copied from
                Stream req = null;
                try
                {
                    req = await httpWebRequest.GetRequestStreamAsync().WithTimeout(
                        TimeSpan.FromMilliseconds(remainingTime),
                        "Waiting for RequestStream");

                    remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                    if (remainingTime <= 0)
                    {
                        remainingTime = 0;
                    }

                    await input.CopyToAsync(req).WithTimeout(
                        TimeSpan.FromMilliseconds(remainingTime),
                        "Waiting for CopyToAsync",
                        CancellationToken.None);
                }
                catch (TimeoutException)
                {
                    httpWebRequest.Abort();
                    throw;
                }
                finally
                {
                    if (req != null)
                    {
                        req.Close();
                    }
                }
            }

            try
            {
                remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                if (remainingTime <= 0)
                {
                    remainingTime = 0;
                }

                HttpWebResponse response = (HttpWebResponse)await httpWebRequest.GetResponseAsync().WithTimeout(
                    TimeSpan.FromMilliseconds(remainingTime),
                    "Waiting for GetResponseAsync");

                return(new Response()
                {
                    WebResponse = response,
                    RequestLatency = watch.Elapsed
                });
            }
            catch (Exception ex)
            {
                if (ex is WebException)
                {
                    WebException we   = (WebException)ex;
                    var          resp = we.Response as HttpWebResponse;
                    return(new Response()
                    {
                        WebResponse = resp,
                        RequestLatency = watch.Elapsed
                    });
                }
                else
                {
                    httpWebRequest.Abort();
                    throw;
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task <Response> IssueWebRequestAsync(string endpoint, string query, string method, Stream input,
                                                          RequestOptions options)
        {
            options.Validate();
            var watch = Stopwatch.StartNew();

            Trace.CorrelationManager.ActivityId = Guid.NewGuid();
            var balancedEndpoint = _balancer.GetEndpoint();

            // Grab the host. Use the alternative host if one is specified
            var host = options.AlternativeHost != null ? options.AlternativeHost : balancedEndpoint.Host;

            var builder = new UriBuilder(
                balancedEndpoint.Scheme,
                host,
                options.Port,
                options.AlternativeEndpoint + endpoint);

            if (query != null)
            {
                builder.Query = query;
            }

            var target = builder.Uri;

            try
            {
                Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, target);

                var httpWebRequest = WebRequest.CreateHttp(target);
                //httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
                //httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
                httpWebRequest.Timeout         = options.TimeoutMillis; // This has no influence for calls that are made Async
                httpWebRequest.KeepAlive       = options.KeepAlive;
                httpWebRequest.Credentials     = _credentialCache;
                httpWebRequest.PreAuthenticate = true;
                httpWebRequest.Method          = method;
                httpWebRequest.Accept          = _contentType;
                httpWebRequest.ContentType     = _contentType;
                // This allows 304 (NotModified) requests to catch
                //https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowautoredirect(v=vs.110).aspx
                httpWebRequest.AllowAutoRedirect = false;

                if (options.AdditionalHeaders != null)
                {
                    foreach (var kv in options.AdditionalHeaders)
                    {
                        httpWebRequest.Headers.Add(kv.Key, kv.Value);
                    }
                }
                long remainingTime = options.TimeoutMillis;

                if (input != null)
                {
                    // expecting the caller to seek to the beginning or to the location where it needs to be copied from
                    Stream req = null;
                    try
                    {
                        req = await httpWebRequest.GetRequestStreamAsync().WithTimeout(
                            TimeSpan.FromMilliseconds(remainingTime),
                            "Waiting for RequestStream");

                        remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                        if (remainingTime <= 0)
                        {
                            remainingTime = 0;
                        }

                        await input.CopyToAsync(req).WithTimeout(
                            TimeSpan.FromMilliseconds(remainingTime),
                            "Waiting for CopyToAsync",
                            CancellationToken.None);
                    }
                    catch (TimeoutException)
                    {
                        httpWebRequest.Abort();
                        throw;
                    }
                    finally
                    {
                        if (req != null)
                        {
                            req.Close();
                        }
                    }
                }

                try
                {
                    remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                    if (remainingTime <= 0)
                    {
                        remainingTime = 0;
                    }

                    Debug.WriteLine("Waiting for response for request {0} to endpoint {1}",
                                    Trace.CorrelationManager.ActivityId, target);

                    var response = (HttpWebResponse)await httpWebRequest.GetResponseAsync().WithTimeout(
                        TimeSpan.FromMilliseconds(remainingTime),
                        "Waiting for GetResponseAsync");

                    Debug.WriteLine("Web request {0} to endpoint {1} successful!", Trace.CorrelationManager.ActivityId,
                                    target);

                    return(new Response
                    {
                        WebResponse = response,
                        RequestLatency = watch.Elapsed,
                        PostRequestAction = r =>
                        {
                            if (r.WebResponse.StatusCode == HttpStatusCode.OK ||
                                r.WebResponse.StatusCode == HttpStatusCode.Created ||
                                r.WebResponse.StatusCode == HttpStatusCode.NotModified)
                            {
                                _balancer.RecordSuccess(balancedEndpoint);
                            }
                            else
                            {
                                _balancer.RecordFailure(balancedEndpoint);
                            }
                        }
                    });
                }
                catch (TimeoutException)
                {
                    httpWebRequest.Abort();
                    throw;
                }
            }
            catch (WebException we)
            {
                // 404 is valid response
                var resp = we.Response as HttpWebResponse;
                if (resp.StatusCode == HttpStatusCode.NotFound)
                {
                    _balancer.RecordSuccess(balancedEndpoint);
                    Debug.WriteLine("Web request {0} to endpoint {1} successful!", Trace.CorrelationManager.ActivityId,
                                    target);
                }
                else
                {
                    _balancer.RecordFailure(balancedEndpoint);
                    Debug.WriteLine("Web request {0} to endpoint {1} failed!", Trace.CorrelationManager.ActivityId,
                                    target);
                }

                throw we;
            }
            catch (Exception e)
            {
                _balancer.RecordFailure(balancedEndpoint);
                Debug.WriteLine("Web request {0} to endpoint {1} failed!", Trace.CorrelationManager.ActivityId, target);
                throw e;
            }
        }
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task<Response> IssueWebRequestAsync(
            string method, Stream input, RequestOptions options)
        {
            options.Validate();
            Stopwatch watch = Stopwatch.StartNew();
            UriBuilder builder = new UriBuilder(
                "http",
                options.AlternativeHost,
                options.Port,
                options.AlternativeEndpoint);
            Debug.WriteLine("Issuing request to endpoint {0}", builder.Uri);
            HttpWebRequest httpWebRequest = WebRequest.CreateHttp(builder.Uri);
            //httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
            httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
            httpWebRequest.Timeout = options.TimeoutMillis;
            httpWebRequest.KeepAlive = options.KeepAlive;
            httpWebRequest.Credentials = null;
            httpWebRequest.PreAuthenticate = true;
            httpWebRequest.Method = method;
            httpWebRequest.Accept = _contentType;
            httpWebRequest.ContentType = _contentType;

            if (options.AdditionalHeaders != null)
            {
                foreach (var kv in options.AdditionalHeaders)
                {
                    httpWebRequest.Headers.Add(kv.Key, kv.Value);
                }
            }

            long remainingTime = options.TimeoutMillis;
            if (input != null)
            {
                // expecting the caller to seek to the beginning or to the location where it needs to be copied from
                Stream req = null;
                try
                {
                    req = await httpWebRequest.GetRequestStreamAsync().WithTimeout(
                                                TimeSpan.FromMilliseconds(remainingTime),
                                                "Waiting for RequestStream");

                    remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                    if (remainingTime <= 0)
                    {
                        remainingTime = 0;
                    }

                    await input.CopyToAsync(req).WithTimeout(
                                TimeSpan.FromMilliseconds(remainingTime),
                                "Waiting for CopyToAsync",
                                CancellationToken.None);
                }
                catch (TimeoutException)
                {
                    httpWebRequest.Abort();
                    throw;
                }
                finally
                {
                    if (req != null)
                    {
                        req.Close();
                    }
                }
            }

            try
            {
                remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                if (remainingTime <= 0)
                {
                    remainingTime = 0;
                }

                HttpWebResponse response = (HttpWebResponse)await httpWebRequest.GetResponseAsync().WithTimeout(
                                                                TimeSpan.FromMilliseconds(remainingTime),
                                                                "Waiting for GetResponseAsync");
                return new Response()
                {
                    WebResponse = response,
                    RequestLatency = watch.Elapsed
                };
            }
            catch (Exception ex)
            {
                if (ex is WebException)
                {
                    WebException we = (WebException)ex;
                    var resp = we.Response as HttpWebResponse;
                    return new Response()
                    {
                        WebResponse = resp,
                        RequestLatency = watch.Elapsed
                    };
                }
                else
                {
                    httpWebRequest.Abort();
                    throw;
                }
            }

        }
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task<Response> IssueWebRequestAsync(string endpoint, string method, Stream input, RequestOptions options)
        {
            options.Validate();
            Stopwatch watch = Stopwatch.StartNew();
            Trace.CorrelationManager.ActivityId = Guid.NewGuid();
            var balancedEndpoint = _balancer.GetEndpoint();

            UriBuilder builder = new UriBuilder(
                balancedEndpoint.Scheme,
                balancedEndpoint.Host,
                options.Port,
                options.AlternativeEndpoint + endpoint);

            var target = builder.Uri;

            try
            {
                Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, target);

                HttpWebRequest httpWebRequest = WebRequest.CreateHttp(target);
                httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
                httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
                httpWebRequest.Timeout = options.TimeoutMillis;
                httpWebRequest.KeepAlive = options.KeepAlive;
                httpWebRequest.Credentials = _credentialCache;
                httpWebRequest.PreAuthenticate = true;
                httpWebRequest.Method = method;
                httpWebRequest.Accept = _contentType;
                httpWebRequest.ContentType = _contentType;

                if (options.AdditionalHeaders != null)
                {
                    foreach (var kv in options.AdditionalHeaders)
                    {
                        httpWebRequest.Headers.Add(kv.Key, kv.Value);
                    }
                }

                if (input != null)
                {
                    // seek to the beginning, so we copy everything in this buffer
                    input.Seek(0, SeekOrigin.Begin);
                    using (Stream req = httpWebRequest.GetRequestStream())
                    {
                        await input.CopyToAsync(req);
                    }
                }

                Debug.WriteLine("Waiting for response for request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, target);

                var response = (await httpWebRequest.GetResponseAsync()) as HttpWebResponse;

                Debug.WriteLine("Web request {0} to endpoint {1} successful!", Trace.CorrelationManager.ActivityId, target);

                return new Response()
                {
                    WebResponse = response,
                    RequestLatency = watch.Elapsed,
                    PostRequestAction = (r) =>
                    {
                        if (r.WebResponse.StatusCode == HttpStatusCode.OK || r.WebResponse.StatusCode == HttpStatusCode.Created)
                        {
                            _balancer.RecordSuccess(balancedEndpoint);
                        }
                        else
                        {
                            _balancer.RecordFailure(balancedEndpoint);
                        }
                    }
                };
            }
            catch (Exception e)
            {
                _balancer.RecordFailure(balancedEndpoint);
                Debug.WriteLine("Web request {0} to endpoint {1} failed!", Trace.CorrelationManager.ActivityId, target);
                throw e;
            }
        }
        /// <summary>
        /// Issues the web request asynchronous.
        /// </summary>
        /// <param name="endpoint">The endpoint.</param>
        /// <param name="query">The query to append.</param>
        /// <param name="method">The method.</param>
        /// <param name="input">The input.</param>
        /// <param name="options">request options</param>
        /// <returns></returns>
        public async Task<Response> IssueWebRequestAsync(
            string endpoint, string query, string method, Stream input, RequestOptions options)
        {
            options.Validate();
            Stopwatch watch = Stopwatch.StartNew();
            UriBuilder builder = new UriBuilder(
                _credentials.ClusterUri.Scheme,
                _credentials.ClusterUri.Host,
                options.Port,
                options.AlternativeEndpoint + endpoint);

            if (query != null)
            {
                builder.Query = query;
            }
            
            Debug.WriteLine("Issuing request {0} to endpoint {1}", Trace.CorrelationManager.ActivityId, builder.Uri);
            HttpWebRequest httpWebRequest = WebRequest.CreateHttp(builder.Uri);
            httpWebRequest.ServicePoint.ReceiveBufferSize = options.ReceiveBufferSize;
            httpWebRequest.ServicePoint.UseNagleAlgorithm = options.UseNagle;
            httpWebRequest.Timeout = options.TimeoutMillis; // This has no influence for calls that are made Async
            httpWebRequest.KeepAlive = options.KeepAlive;
            httpWebRequest.Credentials = _credentialCache;
            httpWebRequest.PreAuthenticate = true;
            httpWebRequest.Method = method;
            httpWebRequest.Accept = _contentType;
            httpWebRequest.ContentType = _contentType;
            // This allows 304 (NotModified) requests to catch
            //https://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.allowautoredirect(v=vs.110).aspx
            httpWebRequest.AllowAutoRedirect = false;

            if (options.AdditionalHeaders != null)
            {
                foreach (var kv in options.AdditionalHeaders)
                {
                    httpWebRequest.Headers.Add(kv.Key, kv.Value);
                }
            }
            
            long remainingTime = options.TimeoutMillis;

            if (input != null)
            {
                // expecting the caller to seek to the beginning or to the location where it needs to be copied from
                Stream req = null;
                try
                {
                    req = await httpWebRequest.GetRequestStreamAsync().WithTimeout(
                                                TimeSpan.FromMilliseconds(remainingTime),
                                                "Waiting for RequestStream");

                    remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                    if(remainingTime <= 0)
                    {
                        remainingTime = 0;
                    }

                    await input.CopyToAsync(req).WithTimeout(
                                TimeSpan.FromMilliseconds(remainingTime),
                                "Waiting for CopyToAsync",
                                CancellationToken.None);
                }
                catch (TimeoutException)
                {
                    httpWebRequest.Abort();
                    throw;
                }
                finally
                {
                    req?.Close();
                }
            }

            try
            {
                remainingTime = options.TimeoutMillis - watch.ElapsedMilliseconds;
                if (remainingTime <= 0)
                {
                    remainingTime = 0;
                }

                HttpWebResponse response = (HttpWebResponse) await httpWebRequest.GetResponseAsync().WithTimeout(
                                                                TimeSpan.FromMilliseconds(remainingTime),
                                                                "Waiting for GetResponseAsync");
                return new Response()
                {
                    WebResponse = response,
                    RequestLatency = watch.Elapsed
                };
            }
            catch (TimeoutException)
            {
                httpWebRequest.Abort();
                throw;
            }
        }