/// <summary>
        /// Handles the error in the given response. 
        /// <para/>
        /// This method is only called when HasError() method has returned <see langword="true"/>.
        /// </summary>
        /// <remarks>
        /// This implementation throws appropriate exception if the response status code 
        /// is a client code error (4xx) or a server code error (5xx). 
        /// </remarks>
        /// <param name="requestUri">The request URI.</param>
        /// <param name="requestMethod">The request method.</param>
        /// <param name="response">The response message with the error.</param>
        public override void HandleError(Uri requestUri, HttpMethod requestMethod, HttpResponseMessage<byte[]> response)
        {
			if (response == null) throw new ArgumentNullException("response");

            var type = (int)response.StatusCode / 100;
            switch (type)
            {
            	case 4:
            		HandleClientErrors(response);
            		break;
            	case 5:
            		HandleServerErrors(response.StatusCode);
            		break;
            }

            // if not otherwise handled, do default handling and wrap with StackExchangeApiException
            try
            {
                base.HandleError(requestUri, requestMethod, response);
            }
            catch (Exception ex)
            {
                throw new StackExchangeApiException("Error consuming StackExchange REST API.", ex);
            }
        }
        private void HandleClientErrors(HttpResponseMessage<byte[]> response) 
        {
		    JsonValue errorValue = this.ExtractErrorDetailsFromResponse(response);
		    if (errorValue == null) 
            {
			    return; // unexpected error body, can't be handled here
		    }
            string errorText = errorValue.ContainsName("error") 
                ? errorValue.GetValue<string>("error") 
                : response.StatusDescription;

            switch (response.StatusCode)
            {
                case HttpStatusCode.BadRequest:
                    throw new DropboxApiException(errorText, DropboxApiError.BadParameter);
                case HttpStatusCode.Unauthorized:
                    throw new DropboxApiException(errorText, DropboxApiError.NotAuthorized);
                case HttpStatusCode.Forbidden:
                    throw new DropboxApiException(errorText, DropboxApiError.OperationNotPermitted);
                case HttpStatusCode.NotFound:
                    throw new DropboxApiException(errorText, DropboxApiError.PathNotFound);
                case HttpStatusCode.NotAcceptable:
                    throw new DropboxApiException(errorText, DropboxApiError.TooManyEntries);
                case HttpStatusCode.LengthRequired:
                    throw new DropboxApiException(errorText, DropboxApiError.ChunkedEncodingNotSupported);
                case HttpStatusCode.UnsupportedMediaType:
                    throw new DropboxApiException(errorText, DropboxApiError.ThumbnailNotSupported);
            }
	    }
        private static readonly Encoding DEFAULT_CHARSET = new UTF8Encoding(false); // Remove byte Order Mask (BOM)

        /// <summary>
        /// Handles the error in the given response. 
        /// <para/>
        /// This method is only called when HasError() method has returned <see langword="true"/>.
        /// </summary>
        /// <remarks>
        /// This implementation throws appropriate exception if the response status code 
        /// is a client code error (4xx) or a server code error (5xx). 
        /// </remarks>
        /// <param name="requestUri">The request URI.</param>
        /// <param name="requestMethod">The request method.</param>
        /// <param name="response">The response message with the error.</param>
        public override void HandleError(Uri requestUri, HttpMethod requestMethod, HttpResponseMessage<byte[]> response)
        {
            int type = (int)response.StatusCode / 100;
            if (type == 4)
            {
                if (response.StatusCode == HttpStatusCode.NotFound)
                {
                    string path = requestUri.AbsolutePath;
                    if (path.EndsWith("blocks/exists.json") ||
                        path.EndsWith("lists/members/show.json") ||
                        path.EndsWith("lists/subscribers/show.json"))
                    {
                        // Special cases: API binding will handle this
                        return;
                    }
                }
                this.HandleClientErrors(response);
            }
            else if (type == 5)
            {
                this.HandleServerErrors(response.StatusCode);
            }

            // if not otherwise handled, do default handling and wrap with TwitterApiException
            try
            {
                base.HandleError(requestUri, requestMethod, response);
            }
            catch (Exception ex)
            {
                throw new TwitterApiException("Error consuming Twitter REST API.", ex);
            }
        }
        /// <summary>
        /// Handles the error in the given response. 
        /// <para/>
        /// This method is only called when HasError() method has returned <see langword="true"/>.
        /// </summary>
        /// <remarks>
        /// This implementation throws appropriate exception if the response status code 
        /// is a client code error (4xx) or a server code error (5xx). 
        /// </remarks>
        /// <param name="requestUri">The request URI.</param>
        /// <param name="requestMethod">The request method.</param>
        /// <param name="response">The response message with the error.</param>
        public override void HandleError(Uri requestUri, HttpMethod requestMethod, HttpResponseMessage<byte[]> response)
        {
            var data = System.Text.Encoding.UTF8.GetString(response.Body, 0, response.Body.Length);

            if (response == null) throw new ArgumentNullException("response");

            var type = (int)response.StatusCode / 100;
            switch (type)
            {
                case 4:
                    HandleClientErrors(response.StatusCode);
                    break;
                case 5:
                    HandleServerErrors(response.StatusCode);
                    break;
            }

            // if not otherwise handled, do default handling and wrap with ElanceApiException
            try
            {
                base.HandleError(requestUri, requestMethod, response);
            }
            catch (Exception ex)
            {
                throw new ElanceApiException("Error consuming Elance REST API.", ex);
            }
        }
		private void HandleClientErrors(HttpResponseMessage<byte[]> response)
		{
			if (response == null) throw new ArgumentNullException("response");

			var errorText = ExtractErrorDetailsFromResponse(response);

			throw new StackExchangeApiException(
				"The server indicated a client error has occured and returned the following HTTP status code: " + response.StatusCode +
				Environment.NewLine + Environment.NewLine +
				errorText,
				StackExchangeApiError.ClientError);
		}
 /// <summary>
 /// Throws an exception if the response status code is a client code error (4xx) 
 /// or a server code error (5xx). 
 /// This method is only called when <see cref="M:HasError"/> has returned <see langword="true"/>.
 /// </summary>
 /// <param name="response">The response message with the error</param>
 /// <exception cref="HttpClientErrorException">If the response status code is a client error (4xx).</exception>
 /// <exception cref="HttpServerErrorException">If the response status code is a server error (4xx).</exception>
 public virtual void HandleError(HttpResponseMessage<byte[]> response)
 {
     int type = (int)response.StatusCode / 100;
     switch (type)
     {
         case 4:
             throw new HttpClientErrorException(response);
         case 5:
             throw new HttpServerErrorException(response);
         default:
             throw new HttpResponseException(response);
     }
 }
        private static readonly Encoding DEFAULT_CHARSET = new UTF8Encoding(false); // Remove byte Order Mask (BOM)

        /// <summary>
        /// Handles the error in the given response. 
        /// <para/>
        /// This method is only called when HasError() method has returned <see langword="true"/>.
        /// </summary>
        /// <remarks>
        /// This implementation throws appropriate exception if the response status code 
        /// is a client code error (4xx) or a server code error (5xx). 
        /// </remarks>
        /// <param name="requestUri">The request URI.</param>
        /// <param name="requestMethod">The request method.</param>
        /// <param name="response">The response message with the error.</param>
        public override void HandleError(Uri requestUri, HttpMethod requestMethod, HttpResponseMessage<byte[]> response)
        {
            int type = (int)response.StatusCode / 100;
            if (type == 4)
            {
                this.HandleClientErrors(response);
            }
            else if (type == 5)
            {
                this.HandleServerErrors(response.StatusCode);
            }

            // if not otherwise handled, do default handling and wrap with DropboxApiException
            try
            {
                base.HandleError(requestUri, requestMethod, response);
            }
            catch (Exception ex)
            {
                throw new DropboxApiException("Error consuming Dropbox REST API.", ex);
            }
        }
        private JsonValue ExtractErrorDetailsFromResponse(HttpResponseMessage<byte[]> response) 
        {
            if (response.Body == null)
            {
                return null;
            }
            MediaType contentType = response.Headers.ContentType;
            Encoding charset = (contentType != null && contentType.CharSet != null) ? contentType.CharSet : DEFAULT_CHARSET;
            string errorDetails = charset.GetString(response.Body, 0, response.Body.Length);
		    
            JsonValue result;
            return JsonValue.TryParse(errorDetails, out result) ? result : null;
	    }
		private string ExtractErrorDetailsFromResponse(HttpResponseMessage<byte[]> response)
		{
			if (response.Body == null)
			{
				return null;
			}
			var contentType = response.Headers.ContentType;
			var charset = (contentType != null && contentType.CharSet != null) ? contentType.CharSet : DefaultCharset;

			var stream = new MemoryStream(response.Body);
			var gZipStream = new GZipStream(stream, CompressionMode.Decompress);

			var responseUncompressed = new byte[response.Body.Length * 10];
			var size = gZipStream.Read(responseUncompressed, 0, responseUncompressed.Length);

			return charset.GetString(responseUncompressed, 0, size);
		}
 /// <summary>
 /// Creates a new instance of <see cref="HttpServerErrorException"/> 
 /// based on an HTTP response message.
 /// </summary>
 /// <param name="requestUri">The HTTP request URI.</param>
 /// <param name="requestMethod">The HTTP request method.</param>
 /// <param name="response">The HTTP response message.</param>
 public HttpServerErrorException(Uri requestUri, HttpMethod requestMethod, HttpResponseMessage<byte[]> response)
     : base(requestUri, requestMethod, response)
 {
 }
 /// <summary>
 /// Creates a new instance of <see cref="HttpClientErrorException"/> 
 /// based on an HTTP response message.
 /// </summary>
 /// <param name="response">The HTTP response message.</param>
 public HttpClientErrorException(HttpResponseMessage<byte[]> response)
     : base (response)
 {
 }
        private void HandleClientErrors(HttpResponseMessage<byte[]> response) 
        {
		    JsonValue errorValue = this.ExtractErrorDetailsFromResponse(response);
		    if (errorValue == null) 
            {
			    return; // unexpected error body, can't be handled here
		    }

		    string errorText = null;
		    if (errorValue.ContainsName("error")) 
            {
			    errorText = errorValue.GetValue<string>("error");
		    } 
            else if(errorValue.ContainsName("errors")) 
            {
			    JsonValue errorsValue = errorValue.GetValue("errors");			
			    if (errorsValue.IsArray) 
                {
				    errorText = errorsValue.GetValue(0).GetValue<string>("message");
			    } 
                else if (errorsValue.IsString) 
                {
				    errorText = errorsValue.GetValue<string>();
			    }
		    }

		    if (response.StatusCode == HttpStatusCode.Unauthorized) 
            {
                if (errorText == "Could not authenticate you.")
                {
                    throw new TwitterApiException(
                        "Authorization is required for the operation, but the API binding was created without authorization.", 
                        TwitterApiError.NotAuthorized);
			    }
                else if (errorText == "Could not authenticate with OAuth.")
                {
                    throw new TwitterApiException("The authorization has been revoked.", TwitterApiError.NotAuthorized);
			    }
                else 
                {
                    throw new TwitterApiException(errorText ?? response.StatusDescription, TwitterApiError.NotAuthorized);
			    }
		    } 
            else if (response.StatusCode == HttpStatusCode.Forbidden) 
            {
                throw new TwitterApiException(errorText, TwitterApiError.OperationNotPermitted);
		    } 
            else if (response.StatusCode == HttpStatusCode.NotFound) 
            {
                throw new TwitterApiException(errorText, TwitterApiError.ResourceNotFound);
		    }
            else if (response.StatusCode == (HttpStatusCode)420)
            {
                throw new TwitterApiException("The rate limit has been exceeded.", TwitterApiError.RateLimitExceeded);
            }
	    }
 /// <summary>
 /// Creates a new instance of <see cref="HttpServerErrorException"/> 
 /// based on an HTTP response message.
 /// </summary>
 /// <param name="response">The HTTP response message.</param>
 public HttpServerErrorException(HttpResponseMessage<byte[]> response)
     : base(response)
 {
 }