Specifies the settings for an HTTP REST request.
The base implementation does not specify values for the RequestSettings.ContentType or RequestSettings.Accept properties. In most cases, these should be properly set for the particular application either manually or in the constructor of a derived class (e.g. JsonRequestSettings).
        public override Response Stream(Uri url, HttpMethod method, Func<HttpWebResponse, bool, Response> responseBuilderCallback, Stream content, int bufferSize, long maxReadLength, Dictionary<string, string> headers, Dictionary<string, string> queryStringParameters, RequestSettings settings, Action<long> progressUpdated)
        {
            try
            {
                return DoStream(url, method, responseBuilderCallback, content, bufferSize, maxReadLength, 
                    headers, queryStringParameters, settings, progressUpdated, false);
            }
            catch (ProtocolViolationException)
            {
                ServicePoint servicePoint = ServicePointManager.FindServicePoint(url);
                if (servicePoint.ProtocolVersion < HttpVersion.Version11)
                {
                    // this is a workaround for issue #333
                    // https://github.com/openstacknetsdk/openstack.net/issues/333
                    // http://stackoverflow.com/a/22976809/138304
                    int maxIdleTime = servicePoint.MaxIdleTime;
                    servicePoint.MaxIdleTime = 0;
                    System.Threading.Thread.Sleep(1000);
                    servicePoint.MaxIdleTime = maxIdleTime;
                }

                return DoStream(url, method, responseBuilderCallback, content, bufferSize, maxReadLength, headers, 
                    queryStringParameters, settings, progressUpdated, true);
            }
        }
        private Response DoStream(Uri url, HttpMethod method, Func<HttpWebResponse, bool, Response> responseBuilderCallback, 
            Stream content, int bufferSize, long maxReadLength, Dictionary<string, string> headers, 
            Dictionary<string, string> queryStringParameters, RequestSettings settings, 
            Action<long> progressUpdated, bool allowWriteStreamBuffering)
        {
            if (url == null)
                throw new ArgumentNullException("url");
            if (content == null)
                throw new ArgumentNullException("content");
            if (bufferSize <= 0)
                throw new ArgumentOutOfRangeException("bufferSize");
            if (maxReadLength < 0)
                throw new ArgumentOutOfRangeException("maxReadLength");

            return ExecuteRequest(url, method, responseBuilderCallback, headers, queryStringParameters, settings, (req) =>
            {
                long bytesWritten = 0;

                if (method == HttpMethod.GET)
                {
                    req.Timeout = _readRequestTimeout;
                    req.ReadWriteTimeout = _readRequestTimeout;
                }
                else
                {
                    req.Timeout = _writeRequestTimeout;
                    req.ReadWriteTimeout = _writeRequestTimeout;
                }

                //Console.WriteLine("TO----> " + req.Timeout.ToString() );

                if (settings.ChunkRequest || maxReadLength > 0)
                {
                    req.SendChunked = settings.ChunkRequest;
                    req.AllowWriteStreamBuffering = allowWriteStreamBuffering;
                    req.ContentLength = maxReadLength > 0 && content.Length > maxReadLength ? maxReadLength : content.Length;
                }

                using (Stream stream = req.GetRequestStream())
                {
                    var buffer = new byte[bufferSize];
                    int count;
                    while (!req.HaveResponse && (count = content.Read(buffer, 0, maxReadLength > 0 ? (int)Math.Min(bufferSize, maxReadLength - bytesWritten) : bufferSize)) > 0)
                    {
                        bytesWritten += count;

                        stream.Write(buffer, 0, count);

                        if (progressUpdated != null)
                            progressUpdated(bytesWritten);

                        if (maxReadLength > 0 && bytesWritten >= maxReadLength)
                            break;
                    }
                }

                return "[STREAM CONTENT]";
            });
        }
        /// <inheritdoc/>
        public virtual Response <T> Execute <T, TBody>(string url, HttpMethod method, TBody body, Dictionary <string, string> headers, Dictionary <string, string> queryStringParameters, RequestSettings settings)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentException("url cannot be empty");
            }

            return(Execute <T, TBody>(new Uri(url), method, body, headers, queryStringParameters, settings));
        }
        /// <summary>
        /// Executes a REST request indirectly via a callback function <paramref name="executeCallback"/>,
        /// and using a user-defined callback function <paramref name="responseBuilderCallback"/> for
        /// constructing the resulting <see cref="Response"/> object.
        /// </summary>
        /// <remarks>
        /// The callback method <paramref name="executeCallback"/> is responsible for setting the body
        /// of the request, if any, before executing the request. The callback method returns a string
        /// representation of the body of the final request when available, otherwise returns a string
        /// indicating the body is no longer available (e.g. was sent as a stream, or is binary). The
        /// result is only required for passing as an argument to <see cref="IRequestLogger.Log"/>.
        ///
        /// <para>The Boolean argument to <paramref name="responseBuilderCallback"/> indicates whether
        /// or not an exception was thrown while executing the request. The value is <c>true</c>
        /// if an exception occurred, otherwise <c>false</c>.</para>
        /// </remarks>
        /// <param name="url">The base URI.</param>
        /// <param name="method">The HTTP method to use for the request.</param>
        /// <param name="responseBuilderCallback">A user-specified function used to construct the resulting <see cref="Response"/>
        /// object from the <see cref="HttpWebResponse"/> and a Boolean value specifying whether or not a <see cref="WebException"/>
        /// was thrown during the request. If this value is <c>null</c>, a default method is used to construct
        /// the resulting <see cref="Response"/> object.</param>
        /// <param name="headers">
        /// A collection of custom HTTP headers to include with the request. If the value is
        /// <c>null</c>, no custom headers are added to the HTTP request.
        /// </param>
        /// <param name="queryStringParameters">
        /// A collection of parameters to add to the query string portion of the request URI.
        /// If the value is <c>null</c>, no parameters are added to the query string.
        /// </param>
        /// <param name="settings">
        /// The settings to use for the request. If the value is <c>null</c>, the default settings returned
        /// by <see cref="DefaultRequestSettings"/> will be used for the request.
        /// </param>
        /// <param name="executeCallback"></param>
        /// <returns>Returns a <see cref="Response"/> object containing the HTTP status code, headers,
        /// and body from the REST response.</returns>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="url"/> is <c>null</c>.
        /// <para>-or-</para>
        /// <para>If <paramref name="executeCallback"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="NotSupportedException">If <paramref name="method"/> is not supported by the service.</exception>
        /// <exception cref="ArgumentException">If <paramref name="headers"/> contains an nvalid Range header value. It must one of the following formats: bytes=0-16 or 0-16 or 16.</exception>
        public virtual Response ExecuteRequest(Uri url, HttpMethod method, Func <HttpWebResponse, bool, Response> responseBuilderCallback, Dictionary <string, string> headers, Dictionary <string, string> queryStringParameters, RequestSettings settings, Func <HttpWebRequest, string> executeCallback)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }
            if (executeCallback == null)
            {
                throw new ArgumentNullException("executeCallback");
            }

            url = _urlBuilder.Build(url, queryStringParameters);

            if (settings == null)
            {
                settings = DefaultRequestSettings;
            }

            return(_retryLogic.Execute(() =>
            {
                Response response;

                var startTime = DateTimeOffset.UtcNow;

                string requestBodyText = null;
                try
                {
                    var req = WebRequest.Create(url) as HttpWebRequest;
                    req.Method = method.ToString();
                    req.ContentType = settings.ContentType;
                    req.Accept = settings.Accept;
                    if (settings.ContentLength > 0 || settings.AllowZeroContentLength)
                    {
                        req.ContentLength = settings.ContentLength;
                    }

                    if (settings.ConnectionLimit != null)
                    {
                        req.ServicePoint.ConnectionLimit = settings.ConnectionLimit.Value;
                    }

                    req.Timeout = (int)settings.Timeout.TotalMilliseconds;

                    if (!string.IsNullOrEmpty(settings.UserAgent))
                    {
                        req.UserAgent = settings.UserAgent;
                    }

                    if (settings.Credentials != null)
                    {
                        req.Credentials = settings.Credentials;
                    }

                    if (headers != null)
                    {
                        foreach (var header in headers)
                        {
                            // Range cannot be set explicitly, and AddRange must be used instead because ... Microsoft says so.
                            if (header.Key.ToLower() == "range")
                            {
                                ApplyRangeHeader(req, header.Value);
                                continue;
                            }

                            req.Headers.Add(header.Key, header.Value);
                        }
                    }

                    requestBodyText = executeCallback(req);

                    using (var resp = req.GetResponse() as HttpWebResponse)
                    {
                        if (responseBuilderCallback != null)
                        {
                            response = responseBuilderCallback(resp, false);
                        }
                        else
                        {
                            response = BuildWebResponse(resp);
                        }
                    }
                }
                catch (WebException ex)
                {
                    if (ex.Response == null)
                    {
                        throw;
                    }

                    using (var resp = ex.Response as HttpWebResponse)
                    {
                        if (responseBuilderCallback != null)
                        {
                            response = responseBuilderCallback(resp, true);
                        }
                        else
                        {
                            response = BuildWebResponse(resp);
                        }
                    }
                }
                var endTime = DateTimeOffset.UtcNow;

                // Log the request
                if (_logger != null)
                {
                    _logger.Log(method, url.OriginalString, headers, requestBodyText, response, startTime, endTime, settings.ExtendedLoggingData);
                }

                if (response != null && settings.ResponseActions != null && settings.ResponseActions.ContainsKey(response.StatusCode))
                {
                    var action = settings.ResponseActions[response.StatusCode];
                    if (action != null)
                    {
                        action(response);
                    }
                }

                return response;
            }, settings.Non200SuccessCodes, settings.RetryCount, settings.RetryDelay));
        }
        /// <summary>
        /// Executes a REST request with a <see cref="System.IO.Stream"/> <paramref name="content"/>
        /// and user-defined callback function for constructing the resulting <see cref="Response"/>
        /// object.
        /// </summary>
        /// <param name="url">The base URI.</param>
        /// <param name="method">The HTTP method to use for the request.</param>
        /// <param name="responseBuilderCallback">A user-specified function used to construct the resulting <see cref="Response"/>
        /// object from the <see cref="HttpWebResponse"/> and a Boolean value specifying whether or not a <see cref="WebException"/>
        /// was thrown during the request. If this value is <c>null</c>, this method is equivalent to calling
        /// <see cref="Stream(Uri, HttpMethod, Stream, int, long, Dictionary{string, string}, Dictionary{string, string}, RequestSettings, Action{long})"/>.</param>
        /// <param name="content">A stream providing the body of the request.</param>
        /// <param name="bufferSize">
        /// The size of the buffer used for copying data from <paramref name="content"/> to the
        /// HTTP request stream.
        /// </param>
        /// <param name="maxReadLength">
        /// The maximum number of bytes to send with the request. This parameter is optional.
        /// If the value is 0, the request will include all data from <paramref name="content"/>.
        /// </param>
        /// <param name="headers">
        /// A collection of custom HTTP headers to include with the request. This parameter is
        /// optional. If the value is <c>null</c>, no custom headers are added to the HTTP request.
        /// </param>
        /// <param name="queryStringParameters">
        /// A collection of parameters to add to the query string portion of the request URI.
        /// This parameter is optional. If the value is <c>null</c>, no parameters are added
        /// to the query string.
        /// </param>
        /// <param name="settings">
        /// The settings to use for the request. This parameters is optional. If the value is
        /// <c>null</c>, an implementation-specific set of default settings will be used for the request.
        /// </param>
        /// <param name="progressUpdated">
        /// A user-defined callback function for reporting progress of the send operation.
        /// This parameter is optional. If the value is <c>null</c>, the method does not report
        /// progress updates to the caller.
        /// </param>
        /// <returns>Returns a <see cref="Response"/> object containing the HTTP status code, headers,
        /// and body from the REST response.</returns>
        /// <exception cref="ArgumentNullException">
        /// If <paramref name="url"/> is <c>null</c>.
        /// <para>-or-</para>
        /// <para>If <paramref name="content"/> is <c>null</c>.</para>
        /// </exception>
        /// <exception cref="ArgumentOutOfRangeException">
        /// If <paramref name="bufferSize"/> is less than or equal to zero.
        /// <para>-or-</para>
        /// <para>If <paramref name="maxReadLength"/> is less than zero.</para>
        /// </exception>
        /// <exception cref="NotSupportedException">If <paramref name="method"/> is not supported by the service.</exception>
        public virtual Response Stream(Uri url, HttpMethod method, Func <HttpWebResponse, bool, Response> responseBuilderCallback, Stream content, int bufferSize, long maxReadLength, Dictionary <string, string> headers, Dictionary <string, string> queryStringParameters, RequestSettings settings, Action <long> progressUpdated)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }
            if (content == null)
            {
                throw new ArgumentNullException("content");
            }
            if (bufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException("bufferSize");
            }
            if (maxReadLength < 0)
            {
                throw new ArgumentOutOfRangeException("maxReadLength");
            }

            return(ExecuteRequest(url, method, responseBuilderCallback, headers, queryStringParameters, settings, (req) =>
            {
                long bytesWritten = 0;

                if (settings.ChunkRequest || maxReadLength > 0)
                {
                    req.SendChunked = settings.ChunkRequest;
                    req.AllowWriteStreamBuffering = false;

                    req.ContentLength = content.Length > maxReadLength ? maxReadLength : content.Length;
                }

                using (Stream stream = req.GetRequestStream())
                {
                    var buffer = new byte[bufferSize];
                    int count;
                    while ((count = content.Read(buffer, 0, maxReadLength > 0 ? (int)Math.Min(bufferSize, maxReadLength - bytesWritten) : bufferSize)) > 0)
                    {
                        bytesWritten += count;
                        stream.Write(buffer, 0, count);

                        if (progressUpdated != null)
                        {
                            progressUpdated(bytesWritten);
                        }

                        if (maxReadLength > 0 && bytesWritten >= maxReadLength)
                        {
                            break;
                        }
                    }
                }

                return "[STREAM CONTENT]";
            }));
        }
        /// <inheritdoc/>
        public virtual Response Stream(Uri url, HttpMethod method, Stream content, int bufferSize, long maxReadLength, Dictionary <string, string> headers, Dictionary <string, string> queryStringParameters, RequestSettings settings, Action <long> progressUpdated)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }
            if (content == null)
            {
                throw new ArgumentNullException("content");
            }
            if (bufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException("bufferSize");
            }
            if (maxReadLength < 0)
            {
                throw new ArgumentOutOfRangeException("maxReadLength");
            }

            return(Stream(url, method, null, content, bufferSize, maxReadLength, headers, queryStringParameters, settings, progressUpdated));
        }
        /// <inheritdoc/>
        public virtual Response <T> Stream <T>(string url, HttpMethod method, Stream content, int bufferSize, long maxReadLength, Dictionary <string, string> headers, Dictionary <string, string> queryStringParameters, RequestSettings settings, Action <long> progressUpdated)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }
            if (content == null)
            {
                throw new ArgumentNullException("content");
            }
            if (string.IsNullOrEmpty(url))
            {
                throw new ArgumentException("url cannot be empty");
            }
            if (bufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException("bufferSize");
            }
            if (maxReadLength < 0)
            {
                throw new ArgumentOutOfRangeException("maxReadLength");
            }

            return(Stream <T>(new Uri(url), method, content, bufferSize, maxReadLength, headers, queryStringParameters, settings, progressUpdated)  as Response <T>);
        }
        /// <inheritdoc/>
        public virtual Response Execute(Uri url, HttpMethod method, Func <HttpWebResponse, bool, Response> responseBuilderCallback, string body, Dictionary <string, string> headers, Dictionary <string, string> queryStringParameters, RequestSettings settings)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            return(ExecuteRequest(url, method, responseBuilderCallback, headers, queryStringParameters, settings, (req) =>
            {
                // Encode the parameters as form data:
                if (!string.IsNullOrEmpty(body))
                {
                    byte[] formData = UTF8Encoding.UTF8.GetBytes(body);
                    req.ContentLength = formData.Length;

                    // Send the request:
                    using (Stream post = req.GetRequestStream())
                    {
                        post.Write(formData, 0, formData.Length);
                    }
                }

                return body;
            }));
        }
        /// <inheritdoc/>
        public virtual Response Execute(Uri url, HttpMethod method, string body, Dictionary <string, string> headers, Dictionary <string, string> queryStringParameters, RequestSettings settings)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            return(Execute(url, method, null, body, headers, queryStringParameters, settings));
        }
        /// <inheritdoc/>
        public virtual Response Execute <TBody>(Uri url, HttpMethod method, TBody body, Dictionary <string, string> headers, Dictionary <string, string> queryStringParameters, RequestSettings settings)
        {
            if (url == null)
            {
                throw new ArgumentNullException("url");
            }

            var rawBody = _stringSerializer.Serialize(body);

            return(Execute(url, method, rawBody, headers, queryStringParameters, settings));
        }