Exemplo n.º 1
0
        /// <summary>
        /// Provide fault
        /// </summary>
        public bool ProvideFault(Exception error, RestResponseMessage faultMessage)
        {
            var uriMatched = RestOperationContext.Current.IncomingRequest.Url;

            while (error.InnerException != null)
            {
                error = error.InnerException;
            }

            var fault      = new RestServiceFault(error);
            var authScheme = RestOperationContext.Current.AppliedPolicies.OfType <BasicAuthorizationAccessBehavior>().Any() ? "Basic" : "Bearer";
            var authRealm  = RestOperationContext.Current.IncomingRequest.Url.Host;

            // Formulate appropriate response
            if (error is DomainStateException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable;
            }
            else if (error is ObjectLockedException lockException)
            {
                faultMessage.StatusCode = 423;
                fault.Data.Add(lockException.LockedUser);
            }
            else if (error is PolicyViolationException)
            {
                var pve = error as PolicyViolationException;
                if (pve.PolicyDecision == PolicyGrantType.Elevate)
                {
                    // Ask the user to elevate themselves
                    faultMessage.StatusCode = 401;
                    faultMessage.AddAuthenticateHeader(authScheme, authRealm, "insufficient_scope", pve.PolicyId, error.Message);
                }
                else
                {
                    faultMessage.StatusCode = 403;
                }
            }
            else if (error is SecurityException)
            {
                faultMessage.StatusCode = (int)HttpStatusCode.Forbidden;
            }
            else if (error is SecurityTokenException)
            {
                // TODO: Audit this
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                var authHeader = $"Bearer realm=\"{RestOperationContext.Current.IncomingRequest.Url.Host}\" error=\"invalid_token\" error_description=\"{error.Message}\"";
                faultMessage.AddAuthenticateHeader(authScheme, authRealm, error: "invalid_token", description: error.Message);
            }
            else if (error is LimitExceededException)
            {
                faultMessage.StatusCode        = (int)(HttpStatusCode)429;
                faultMessage.StatusDescription = "Too Many Requests";
                faultMessage.Headers.Add("Retry-After", "1200");
            }
            else if (error is AuthenticationException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                faultMessage.AddAuthenticateHeader(authScheme, authRealm, "invalid_token", description: error.Message);
            }
            else if (error is UnauthorizedAccessException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
            }
            else if (error is SecuritySessionException ses)
            {
                switch (ses.Type)
                {
                case SessionExceptionType.Expired:
                case SessionExceptionType.NotYetValid:
                case SessionExceptionType.NotEstablished:
                    faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                    faultMessage.AddAuthenticateHeader(authScheme, authRealm, error: "unauthorized");
                    break;

                default:
                    faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Forbidden;
                    break;
                }
            }
            else if (error is FaultException)
            {
                faultMessage.StatusCode = (int)(error as FaultException).StatusCode;
            }
            else if (error is Newtonsoft.Json.JsonException ||
                     error is System.Xml.XmlException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
            }
            else if (error is DuplicateKeyException || error is DuplicateNameException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.Conflict;
            }
            else if (error is FileNotFoundException || error is KeyNotFoundException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
            }
            else if (error is DomainStateException)
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.ServiceUnavailable;
            }
            else if (error is DetectedIssueException)
            {
                faultMessage.StatusCode = (int)(System.Net.HttpStatusCode) 422;
            }
            else if (error is NotImplementedException)
            {
                faultMessage.StatusCode = (int)HttpStatusCode.NotImplemented;
            }
            else if (error is NotSupportedException)
            {
                faultMessage.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
            }
            else if (error is PatchException)
            {
                faultMessage.StatusCode = (int)HttpStatusCode.Conflict;
            }
            else
            {
                faultMessage.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
            }

            switch (faultMessage.StatusCode)
            {
            case 409:
            case 429:
            case 503:
                this.m_traceSource.TraceInfo("Issue on REST pipeline: {0}", error);
                break;

            case 401:
            case 403:
            case 501:
            case 405:
                this.m_traceSource.TraceWarning("Warning on REST pipeline: {0}", error);
                break;

            default:
                this.m_traceSource.TraceError("Error on REST pipeline: {0}", error);
                break;
            }

            RestMessageDispatchFormatter.CreateFormatter(RestOperationContext.Current.ServiceEndpoint.Description.Contract.Type).SerializeResponse(faultMessage, null, fault);
            AuditUtil.AuditNetworkRequestFailure(error, uriMatched, RestOperationContext.Current.IncomingRequest.Headers.AllKeys.ToDictionary(o => o, o => RestOperationContext.Current.IncomingRequest.Headers[o]), RestOperationContext.Current.OutgoingResponse.Headers.AllKeys.ToDictionary(o => o, o => RestOperationContext.Current.OutgoingResponse.Headers[o]));
            return(true);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Invokes the specified method against the url provided
        /// </summary>
        /// <param name="method">Method.</param>
        /// <param name="url">URL.</param>
        /// <param name="contentType">Content type.</param>
        /// <param name="body">Body.</param>
        /// <param name="query">Query.</param>
        /// <typeparam name="TBody">The 1st type parameter.</typeparam>
        /// <typeparam name="TResult">The 2nd type parameter.</typeparam>
        protected override TResult InvokeInternal <TBody, TResult>(string method, string url, string contentType, WebHeaderCollection additionalHeaders, out WebHeaderCollection responseHeaders, TBody body, NameValueCollection query)
        {
            if (String.IsNullOrEmpty(method))
            {
                throw new ArgumentNullException(nameof(method));
            }
            //if (String.IsNullOrEmpty(url))
            //    throw new ArgumentNullException(nameof(url));


            // Credentials provided ?
            HttpWebRequest requestObj = this.CreateHttpRequest(url, query) as HttpWebRequest;

            if (!String.IsNullOrEmpty(contentType))
            {
                requestObj.ContentType = contentType;
            }
            requestObj.Method = method;

            // Additional headers
            if (additionalHeaders != null)
            {
                foreach (var hdr in additionalHeaders.AllKeys)
                {
                    if (hdr == "If-Modified-Since")
                    {
                        requestObj.IfModifiedSince = DateTime.Parse(additionalHeaders[hdr]);
                    }
                    else
                    {
                        requestObj.Headers.Add(hdr, additionalHeaders[hdr]);
                    }
                }
            }

#if PERFMON
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif
            // Get request object

            // Body was provided?
            try
            {
                // Try assigned credentials
                IBodySerializer serializer = null;
                if (body != null)
                {
                    // GET Stream,
                    Stream requestStream = null;
                    try
                    {
                        // Get request object
                        var cancellationTokenSource = new CancellationTokenSource();
                        cancellationTokenSource.CancelAfter(this.Description.Endpoint[0].Timeout);
                        using (var requestTask = Task.Run(async() => { return(await requestObj.GetRequestStreamAsync()); }, cancellationTokenSource.Token))
                        {
                            try
                            {
                                requestStream = requestTask.Result;
                            }
                            catch (AggregateException e)
                            {
                                requestObj.Abort();
                                throw e.InnerExceptions.First();
                            }
                        }

                        if (contentType == null && typeof(TResult) != typeof(Object))
                        {
                            throw new ArgumentNullException(nameof(contentType));
                        }

                        serializer = this.Description.Binding.ContentTypeMapper.GetSerializer(contentType, typeof(TBody));
                        // Serialize and compress with deflate
                        using (MemoryStream ms = new MemoryStream())
                        {
                            if (this.Description.Binding.Optimize)
                            {
                                switch ((this.Description.Binding as ServiceClientBinding)?.OptimizationMethod)
                                {
                                case OptimizationMethod.Lzma:
                                    requestObj.Headers.Add("Content-Encoding", "lzma");
                                    using (var df = new LZipStream(new NonDisposingStream(requestStream), CompressionMode.Compress))
                                        serializer.Serialize(df, body);
                                    break;

                                case OptimizationMethod.Bzip2:
                                    requestObj.Headers.Add("Content-Encoding", "bzip2");
                                    using (var df = new BZip2Stream(new NonDisposingStream(requestStream), CompressionMode.Compress, false))
                                        serializer.Serialize(df, body);
                                    break;

                                case OptimizationMethod.Gzip:
                                    requestObj.Headers.Add("Content-Encoding", "gzip");
                                    using (var df = new GZipStream(new NonDisposingStream(requestStream), CompressionMode.Compress))
                                        serializer.Serialize(df, body);
                                    break;

                                case OptimizationMethod.Deflate:
                                    requestObj.Headers.Add("Content-Encoding", "deflate");
                                    using (var df = new DeflateStream(new NonDisposingStream(requestStream), CompressionMode.Compress))
                                        serializer.Serialize(df, body);
                                    break;

                                case OptimizationMethod.None:
                                default:
                                    serializer.Serialize(ms, body);
                                    break;
                                }
                            }
                            else
                            {
                                serializer.Serialize(ms, body);
                            }

                            // Trace
                            if (this.Description.Trace)
                            {
                                this.m_tracer.TraceVerbose("HTTP >> {0}", Convert.ToBase64String(ms.ToArray()));
                            }

                            using (var nms = new MemoryStream(ms.ToArray()))
                                nms.CopyTo(requestStream);
                        }
                    }
                    finally
                    {
                        if (requestStream != null)
                        {
                            requestStream.Dispose();
                        }
                    }
                }

                // Response
                HttpWebResponse response = null;
                try
                {
                    var cancellationTokenSource = new CancellationTokenSource();
                    cancellationTokenSource.CancelAfter(this.Description.Endpoint[0].Timeout);
                    using (var responseTask = Task.Run(async() => { return(await requestObj.GetResponseAsync()); }, cancellationTokenSource.Token))
                    {
                        try
                        {
                            response = (HttpWebResponse)responseTask.Result;
                        }
                        catch (AggregateException e)
                        {
                            requestObj.Abort();
                            throw e.InnerExceptions.First();
                        }
                    }

                    responseHeaders = response.Headers;

                    // No content - does the result want a pointer maybe?
                    if (response.StatusCode == HttpStatusCode.NoContent || response.StatusCode == HttpStatusCode.Continue || response.StatusCode == HttpStatusCode.NotModified)
                    {
                        return(default(TResult));
                    }
                    else if (response.StatusCode == HttpStatusCode.RedirectKeepVerb)
                    {
                        return(this.InvokeInternal <TBody, TResult>(method, response.Headers[HttpResponseHeader.Location], contentType, additionalHeaders, out responseHeaders, body, query));
                    }
                    else if (response.StatusCode == HttpStatusCode.RedirectMethod)
                    {
                        return(this.InvokeInternal <TBody, TResult>("GET", response.Headers[HttpResponseHeader.Location], contentType, additionalHeaders, out responseHeaders, default(TBody), query));
                    }
                    else
                    {
                        // De-serialize
                        var responseContentType = response.ContentType;
                        if (String.IsNullOrEmpty(responseContentType))
                        {
                            return(default(TResult));
                        }

                        if (responseContentType.Contains(";"))
                        {
                            responseContentType = responseContentType.Substring(0, responseContentType.IndexOf(";"));
                        }

                        if (response.StatusCode == HttpStatusCode.NotModified)
                        {
                            return(default(TResult));
                        }

                        serializer = this.Description.Binding.ContentTypeMapper.GetSerializer(responseContentType, typeof(TResult));

                        TResult retVal = default(TResult);
                        // Compression?
                        using (MemoryStream ms = new MemoryStream())
                        {
                            if (this.Description.Trace)
                            {
                                this.m_tracer.TraceVerbose("Received response {0} : {1} bytes", response.ContentType, response.ContentLength);
                            }

                            response.GetResponseStream().CopyTo(ms);

                            ms.Seek(0, SeekOrigin.Begin);

                            // Trace
                            if (this.Description.Trace)
                            {
                                this.m_tracer.TraceVerbose("HTTP << {0}", Convert.ToBase64String(ms.ToArray()));
                            }

                            switch (response.Headers[HttpResponseHeader.ContentEncoding])
                            {
                            case "deflate":
                                using (DeflateStream df = new DeflateStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                                    retVal = (TResult)serializer.DeSerialize(df);
                                break;

                            case "gzip":
                                using (GZipStream df = new GZipStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                                    retVal = (TResult)serializer.DeSerialize(df);
                                break;

                            case "bzip2":
                                using (var bzs = new BZip2Stream(new NonDisposingStream(ms), CompressionMode.Decompress, false))
                                    retVal = (TResult)serializer.DeSerialize(bzs);
                                break;

                            case "lzma":
                                using (var lzmas = new LZipStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                                    retVal = (TResult)serializer.DeSerialize(lzmas);
                                break;

                            default:
                                retVal = (TResult)serializer.DeSerialize(ms);
                                break;
                            }
                            //retVal = (TResult)serializer.DeSerialize(ms);
                        }

                        return(retVal);
                    }
                }
                finally
                {
                    if (response != null)
                    {
                        response.Close();
                        response.Dispose();
                    }
                    //responseTask.Dispose();
                }
            }
            catch (TimeoutException e)
            {
                this.m_tracer.TraceError("Request timed out:{0}", e.Message);
                throw;
            }
            catch (WebException e) when(e.Response is HttpWebResponse errorResponse && errorResponse.StatusCode == HttpStatusCode.NotModified)
            {
                this.m_tracer.TraceInfo("Server indicates not modified {0} {1} : {2}", method, url, e.Message);
                responseHeaders = errorResponse?.Headers;
                return(default(TResult));
            }
            catch (WebException e) when(e.Response is HttpWebResponse errorResponse && e.Status == WebExceptionStatus.ProtocolError)
            {
                this.m_tracer.TraceError("Error executing {0} {1} : {2}", method, url, e.Message);
                // Deserialize
                object errorResult = null;

                var responseContentType = errorResponse.ContentType;

                if (responseContentType.Contains(";"))
                {
                    responseContentType = responseContentType.Substring(0, responseContentType.IndexOf(";"));
                }

                var ms = new MemoryStream(); // copy response to memory

                errorResponse.GetResponseStream().CopyTo(ms);
                ms.Seek(0, SeekOrigin.Begin);

                try
                {
                    var serializer = this.Description.Binding.ContentTypeMapper.GetSerializer(responseContentType, typeof(TResult));

                    switch (errorResponse.Headers[HttpResponseHeader.ContentEncoding])
                    {
                    case "deflate":
                        using (DeflateStream df = new DeflateStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                            errorResult = serializer.DeSerialize(df);
                        break;

                    case "gzip":
                        using (GZipStream df = new GZipStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                            errorResult = serializer.DeSerialize(df);
                        break;

                    case "bzip2":
                        using (var bzs = new BZip2Stream(new NonDisposingStream(ms), CompressionMode.Decompress, false))
                            errorResult = serializer.DeSerialize(bzs);
                        break;

                    case "lzma":
                        using (var lzmas = new LZipStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                            errorResult = serializer.DeSerialize(lzmas);
                        break;

                    default:
                        errorResult = serializer.DeSerialize(ms);
                        break;
                    }
                }
                catch
                {
                    errorResult = new RestServiceFault(e);
                }

                Exception exception = null;

                if (errorResult is RestServiceFault rse)
                {
                    exception = new RestClientException <RestServiceFault>(rse, e, e.Status, e.Response);
                }
                else if (errorResponse is TResult)
                {
                    exception = new RestClientException <TResult>((TResult)errorResult, e, e.Status, e.Response);
                }
                else
                {
                    exception = new RestClientException <object>(errorResult, e, e.Status, e.Response);
                }

                switch (errorResponse.StatusCode)
                {
                case HttpStatusCode.Unauthorized:     // Validate the response

                    throw exception;

                case HttpStatusCode.NotModified:
                    responseHeaders = errorResponse?.Headers;
                    return(default(TResult));

                case (HttpStatusCode)422:
                    throw exception;

                default:
                    throw exception;
                }
            }
            catch (WebException e) when(e.Status == WebExceptionStatus.Timeout)
            {
                this.m_tracer.TraceError("Error executing {0} {1} : {2}", method, url, e.Message);
                throw new TimeoutException($"Timeout executing REST operation {method} {url}", e);
            }
            catch (WebException e) when(e.Status == WebExceptionStatus.ConnectFailure)
            {
                this.m_tracer.TraceError("Error executing {0} {1} : {2}", method, url, e.Message);
                if ((e.InnerException as SocketException)?.SocketErrorCode == SocketError.TimedOut)
                {
                    throw new TimeoutException();
                }
                else
                {
                    throw;
                }
            }
            catch (WebException e)
            {
                this.m_tracer.TraceError("Error executing {0} {1} : {2}", method, url, e.Message);
                throw;
            }
            catch (InvalidOperationException e)
            {
                this.m_tracer.TraceError("Invalid Operation: {0}", e.Message);
                throw;
            }

            responseHeaders = new WebHeaderCollection();
            return(default(TResult));
        }
Exemplo n.º 3
0
        /// <summary>
        /// Invokes the specified method against the url provided
        /// </summary>
        /// <param name="method">Method.</param>
        /// <param name="url">URL.</param>
        /// <param name="contentType">Content type.</param>
        /// <param name="body">Body.</param>
        /// <param name="query">Query.</param>
        /// <typeparam name="TBody">The 1st type parameter.</typeparam>
        /// <typeparam name="TResult">The 2nd type parameter.</typeparam>
        protected override TResult InvokeInternal <TBody, TResult>(string method, string url, string contentType, WebHeaderCollection requestHeaders, out WebHeaderCollection responseHeaders, TBody body, NameValueCollection query)
        {
            if (String.IsNullOrEmpty(method))
            {
                throw new ArgumentNullException(nameof(method));
            }
            if (String.IsNullOrEmpty(url))
            {
                throw new ArgumentNullException(nameof(url));
            }

            // Three times:
            // 1. With provided credential
            // 2. With challenge
            // 3. With challenge again
            for (int i = 0; i < 2; i++)
            {
                // Credentials provided ?
                HttpWebRequest requestObj = this.CreateHttpRequest(url, query) as HttpWebRequest;
                if (!String.IsNullOrEmpty(contentType))
                {
                    requestObj.ContentType = contentType;
                }
                requestObj.Method = method;

                // Additional headers
                if (requestHeaders != null)
                {
                    foreach (var hdr in requestHeaders.AllKeys)
                    {
                        if (hdr == "If-Modified-Since")
                        {
                            requestObj.IfModifiedSince = DateTime.Parse(requestHeaders[hdr]);
                        }
                        else
                        {
                            requestObj.Headers.Add(hdr, requestHeaders[hdr]);
                        }
                    }
                }

                // Body was provided?
                try
                {
                    // Try assigned credentials
                    IBodySerializer serializer = null;
                    if (body != null)
                    {
                        // GET Stream,
                        Stream    requestStream    = null;
                        Exception requestException = null;

                        try
                        {
                            //requestStream = requestObj.GetRequestStream();
                            var requestTask = requestObj.GetRequestStreamAsync().ContinueWith(r =>
                            {
                                if (r.IsFaulted)
                                {
                                    requestException = r.Exception.InnerExceptions.First();
                                }
                                else
                                {
                                    requestStream = r.Result;
                                }
                            }, TaskContinuationOptions.LongRunning);

                            if (!requestTask.Wait(this.Description.Endpoint[0].Timeout))
                            {
                                throw new TimeoutException();
                            }
                            else if (requestException != null)
                            {
                                throw requestException;
                            }

                            if (contentType == null)
                            {
                                throw new ArgumentNullException(nameof(contentType));
                            }

                            serializer = this.Description.Binding.ContentTypeMapper.GetSerializer(contentType, typeof(TBody));
                            // Serialize and compress with deflate
                            if (this.Description.Binding.Optimize)
                            {
#if HTTP_LZMA
                                requestObj.Headers.Add("Content-Encoding", "lzma");
                                using (var df = new LZipStream(requestStream, CompressionMode.Compress, leaveOpen: true))
                                    serializer.Serialize(df, body);
#elif HTTP_GZ
                                requestObj.Headers.Add("Content-Encoding", "gzip");
                                using (var df = new GZipStream(requestStream, CompressionMode.Compress, leaveOpen: true))
                                    serializer.Serialize(df, body);
#else
                                requestObj.Headers.Add("Content-Encoding", "deflate");
                                using (var df = new DeflateStream(new NonDisposingStream(requestStream), CompressionMode.Compress))
                                    serializer.Serialize(df, body);
#endif
                            }
                            else
                            {
                                serializer.Serialize(requestStream, body);
                            }
                        }
                        finally
                        {
                            if (requestStream != null)
                            {
                                requestStream.Dispose();
                            }
                        }
                    }

                    // Response
                    HttpWebResponse response      = null;
                    Exception       responseError = null;

                    try
                    {
                        var responseTask = requestObj.GetResponseAsync().ContinueWith(r =>
                        {
                            if (r.IsFaulted)
                            {
                                responseError = r.Exception.InnerExceptions.First();
                            }
                            else
                            {
                                response = r.Result as HttpWebResponse;
                            }
                        }, TaskContinuationOptions.LongRunning);

                        if (!responseTask.Wait(this.Description.Endpoint[0].Timeout))
                        {
                            throw new TimeoutException();
                        }
                        else
                        {
                            if (responseError != null)
                            {
                                responseHeaders = new WebHeaderCollection();
                                if (((responseError as WebException)?.Response as HttpWebResponse)?.StatusCode == HttpStatusCode.NotModified)
                                {
                                    return(default(TResult));
                                }
                                else
                                {
                                    throw responseError;
                                }
                            }
                            responseHeaders = response.Headers;
                        }

                        var validationResult = this.ValidateResponse(response);
                        if (validationResult != ServiceClientErrorType.Valid)
                        {
                            this.traceSource.TraceEvent(EventLevel.Error, "Response failed validation : {0}", validationResult);
                            throw new WebException("Response failed validation", null, WebExceptionStatus.Success, response);
                        }
                        // De-serialize
                        var responseContentType = response.ContentType;
                        if (responseContentType.Contains(";"))
                        {
                            responseContentType = responseContentType.Substring(0, responseContentType.IndexOf(";"));
                        }

                        if (response.StatusCode == HttpStatusCode.NotModified ||
                            response.StatusCode == HttpStatusCode.NoContent ||
                            typeof(TResult) == typeof(object))
                        {
                            return(default(TResult));
                        }
                        serializer = this.Description.Binding.ContentTypeMapper.GetSerializer(responseContentType, typeof(TResult));

                        TResult retVal = default(TResult);
                        using (var ms = new MemoryStream())
                        {
                            response.GetResponseStream().CopyTo(ms);
                            ms.Seek(0, SeekOrigin.Begin);
                            // Compression?
                            switch (response.Headers[HttpResponseHeader.ContentEncoding])
                            {
                            case "deflate":
                                using (DeflateStream df = new DeflateStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                                    retVal = (TResult)serializer.DeSerialize(df);
                                break;

                            case "gzip":
                                using (GZipStream df = new GZipStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                                    retVal = (TResult)serializer.DeSerialize(df);
                                break;

                            case "bzip2":
                                using (var bzs = new BZip2Stream(new NonDisposingStream(ms), CompressionMode.Decompress, false))
                                    retVal = (TResult)serializer.DeSerialize(bzs);
                                break;

                            case "lzma":
                                using (var lzmas = new LZipStream(new NonDisposingStream(ms), CompressionMode.Decompress))
                                    retVal = (TResult)serializer.DeSerialize(lzmas);

                                break;

                            default:
                                retVal = (TResult)serializer.DeSerialize(ms);
                                break;
                            }
                        }

                        return(retVal);
                    }
                    finally
                    {
                        if (response != null)
                        {
                            response.Dispose();
                        }
                    }
                }
                catch (TimeoutException e)
                {
                    this.traceSource.TraceEvent(EventLevel.Error, "Request timed out:{0}", e);
                    throw;
                }
                catch (WebException e)
                {
                    this.traceSource.TraceEvent(EventLevel.Error, e.ToString());

                    // status
                    switch (e.Status)
                    {
                    case WebExceptionStatus.ProtocolError:

                        // Deserialize
                        object errorResult         = null;
                        var    errorResponse       = (e.Response as HttpWebResponse);
                        var    responseContentType = errorResponse.ContentType;
                        if (responseContentType.Contains(";"))
                        {
                            responseContentType = responseContentType.Substring(0, responseContentType.IndexOf(";"));
                        }

                        try
                        {
                            var serializer = this.Description.Binding.ContentTypeMapper.GetSerializer(responseContentType, typeof(TResult));

                            switch (errorResponse.Headers[HttpResponseHeader.ContentEncoding])
                            {
                            case "deflate":
                                using (DeflateStream df = new DeflateStream(new NonDisposingStream(errorResponse.GetResponseStream()), CompressionMode.Decompress))
                                    errorResult = serializer.DeSerialize(df);
                                break;

                            case "gzip":
                                using (GZipStream df = new GZipStream(new NonDisposingStream(errorResponse.GetResponseStream()), CompressionMode.Decompress))
                                    errorResult = serializer.DeSerialize(df);
                                break;

                            case "bzip2":
                                using (var bzs = new BZip2Stream(new NonDisposingStream(errorResponse.GetResponseStream()), CompressionMode.Decompress, false))
                                    errorResult = serializer.DeSerialize(bzs);
                                break;

                            case "lzma":
                                using (var lzmas = new LZipStream(new NonDisposingStream(errorResponse.GetResponseStream()), CompressionMode.Decompress))
                                    errorResult = serializer.DeSerialize(lzmas);
                                break;

                            default:
                                errorResult = serializer.DeSerialize(errorResponse.GetResponseStream());
                                break;
                            }
                        }
                        catch
                        {
                            errorResult = new RestServiceFault(e);
                        }

                        if (errorResult is TResult)
                        {
                            throw new RestClientException <TResult>((TResult)errorResult, e, e.Status, e.Response);
                        }
                        else
                        {
                            throw new RestClientException <RestServiceFault>((RestServiceFault)errorResult, e, e.Status, e.Response);
                        }

                    default:
                        throw;
                    }
                }
            }

            responseHeaders = new WebHeaderCollection();
            return(default(TResult));
        }