public void BadResponse <TResponse>(ref TResponse response, IApiCallDetails callDetails, RequestData data,
                                            TransportException exception
                                            )
            where TResponse : class, ITransportResponse, new()
        {
            if (response == null)
            {
                //make sure we copy over the error body in case we disabled direct streaming.
                var s = callDetails?.ResponseBodyInBytes == null ? Stream.Null : _memoryStreamFactory.Create(callDetails.ResponseBodyInBytes);
                var m = callDetails?.ResponseMimeType ?? RequestData.MimeType;
                response = ResponseBuilder.ToResponse <TResponse>(data, exception, callDetails?.HttpStatusCode, null, s, m);
            }

            response.ApiCall.AuditTrail = AuditTrail;
        }
        /// <inheritdoc cref="IConnection.Request{TResponse}"/>>
        public virtual TResponse Request <TResponse>(RequestData requestData)
            where TResponse : class, ITransportResponse, new()
        {
            int?statusCode = null;
            IEnumerable <string> warnings = null;
            Stream    responseStream      = null;
            Exception ex       = null;
            string    mimeType = null;
            ReadOnlyDictionary <TcpState, int> tcpStats = null;
            ReadOnlyDictionary <string, ThreadPoolStatistics> threadPoolStats = null;

            try
            {
                var request = CreateHttpWebRequest(requestData);
                var data    = requestData.PostData;

                if (data != null)
                {
                    using (var stream = request.GetRequestStream())
                    {
                        if (requestData.HttpCompression)
                        {
                            using var zipStream = new GZipStream(stream, CompressionMode.Compress);
                            data.Write(zipStream, requestData.ConnectionSettings);
                        }
                        else
                        {
                            data.Write(stream, requestData.ConnectionSettings);
                        }
                    }
                }
                requestData.MadeItToResponse = true;

                if (requestData.TcpStats)
                {
                    tcpStats = TcpStats.GetStates();
                }

                if (requestData.ThreadPoolStats)
                {
                    threadPoolStats = ThreadPoolStats.GetStats();
                }

                //http://msdn.microsoft.com/en-us/library/system.net.httpwebresponse.getresponsestream.aspx
                //Either the stream or the response object needs to be closed but not both although it won't
                //throw any errors if both are closed atleast one of them has to be Closed.
                //Since we expose the stream we let closing the stream determining when to close the connection
                var httpWebResponse = (HttpWebResponse)request.GetResponse();
                HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType);

                //response.Headers.HasKeys() can return false even if response.Headers.AllKeys has values.
                if (httpWebResponse.SupportsHeaders && httpWebResponse.Headers.Count > 0 && httpWebResponse.Headers.AllKeys.Contains("Warning"))
                {
                    warnings = httpWebResponse.Headers.GetValues("Warning");
                }
            }
            catch (WebException e)
            {
                ex = e;
                if (e.Response is HttpWebResponse httpWebResponse)
                {
                    HandleResponse(httpWebResponse, out statusCode, out responseStream, out mimeType);
                }
            }

            responseStream ??= Stream.Null;
            var response = ResponseBuilder.ToResponse <TResponse>(requestData, ex, statusCode, warnings, responseStream, mimeType);

            // set TCP and threadpool stats on the response here so that in the event the request fails after the point of
            // gathering stats, they are still exposed on the call details. Ideally these would be set inside ResponseBuilder.ToResponse,
            // but doing so would be a breaking change in 7.x
            response.ApiCall.TcpStats        = tcpStats;
            response.ApiCall.ThreadPoolStats = threadPoolStats;
            return(response);
        }