/// <summary>
        /// The HandleWWWErrorResponse differs significantly from the error handling doing in .NET sdk
        /// since the www.error string message is incomplete
        /// so this requires rewriting all responseunmarshallers.HandleErrorContext which is not part of this version
        /// hence exception thrown will always be of base type AmazonServiceException
        /// </summary>
        /// <returns>True if the error needs retry</returns>
        private bool HandleWWWErrorResponse(AsyncResult asyncResult)
        {
            WWWResponseData errorResponse = asyncResult.ResponseData;

            asyncResult.Metrics.AddProperty(Metric.Exception, errorResponse.Error);

            AmazonServiceException errorResponseException = null;

            errorResponseException = new AmazonServiceException(errorResponse.Error,
                                                                new WebException(errorResponse.Error));

            errorResponseException.UnityStatusCode = errorResponse.Error;
            try
            {
                errorResponseException.StatusCode = errorResponse.ErrorStatusCode;
            }
            catch (Exception e)
            {
                // Parsing exception
                AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Errors, asyncResult.Request.RequestName, e);
            }

            string curl = "curl " + (asyncResult.Request.HttpMethod == "GET" &&
                                     !HttpOverrideSupportedServices.Contains(asyncResult.Request.ServiceName) ?
                                     "-G " :  "-X POST ");

            foreach (string key in asyncResult.RequestData.Headers.Keys)
            {
                curl += " -H \"" + key + ": " + asyncResult.RequestData.Headers[key] + "\" ";
            }
            if (asyncResult.RequestData.Data != null)
            {
                curl += " -d '" + System.Text.Encoding.Default.GetString(asyncResult.RequestData.Data) + "' ";
            }

            curl += " " + asyncResult.RequestData.Url;
            Debug.LogError(curl);

            if (errorResponse.IsHeaderPresent(HeaderKeys.XAmzRequestIdHeader.ToUpper()))
            {
                errorResponseException.RequestId = errorResponse.GetHeaderValue(HeaderKeys.XAmzRequestIdHeader);
            }

            asyncResult.Exception = errorResponseException;

            // currently no retries are done
            return(false);
        }
        /// <summary>
        /// Perform signing, setup WWWRequestData with headers, binary data(for POST request)
        /// and enqueues to the RequestQueue for Main thread
        /// </summary>
        /// <param name="asyncResult"></param>
        private void ProcessHttpRequest(AsyncResult asyncResult)
        {
            try
            {
                // prepare request
                IRequest wrappedRequest = asyncResult.Request;

                WWWRequestData requestData = new WWWRequestData();
                if (HttpOverrideSupportedServices.Contains(asyncResult.Request.ServiceName))
                {
                    asyncResult.Request.Headers.Add("X-HTTP-Method-Override", asyncResult.Request.HttpMethod);

                    if (asyncResult.Request.HttpMethod == "GET")
                    {
                        string emptyString = "{}";
                        asyncResult.Request.ContentStream = new MemoryStream(Encoding.UTF8.GetBytes(emptyString));
                        requestData.Data = Encoding.Default.GetBytes(emptyString);
                    }
                }

#if UNITY_WEBPLAYER
                wrappedRequest.Headers.Remove("User-Agent");
                wrappedRequest.Headers.Remove("Host");
#endif

                SignRequest(asyncResult);

                if (asyncResult.RetriesAttempt > 0)
                {
                    HandleRetry(asyncResult);
                }


                requestData.Url = ComposeUrl(wrappedRequest, wrappedRequest.Endpoint).ToString();

                if (!wrappedRequest.UseQueryString && !(wrappedRequest.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase)))
                {
                    if (wrappedRequest.ContentStream != null)
                    {
                        if (wrappedRequest.OriginalRequest.IncludeSHA256Header &&
                            !wrappedRequest.Headers.ContainsKey(HeaderKeys.XAmzContentSha256Header))
                        {
                            requestData.Headers.Add(HeaderKeys.XAmzContentSha256Header, wrappedRequest.ComputeContentStreamHash());
                        }
                    }
                }

                AddHeaders2(requestData, wrappedRequest.Headers);

                if (asyncResult.Unmarshaller is JsonResponseUnmarshaller)
                {
                    requestData.Headers.Add(HeaderKeys.AcceptHeader, "application/json");
                }

                if (!asyncResult.Request.HttpMethod.Equals("GET", StringComparison.OrdinalIgnoreCase))
                {
                    if (asyncResult.Request.Content != null && asyncResult.Request.Content.Length > 0)
                    {
                        requestData.Data = asyncResult.Request.Content;
                    }
                    else if (asyncResult.Request.ContentStream != null && asyncResult.Request.ContentStream.Length > 0)
                    {
                        using (asyncResult.Request.ContentStream)
                        {
                            requestData.Data = StreamToByteArray.Convert(asyncResult.Request.ContentStream, this.Config.BufferSize);

                            StreamTransferProgressArgs args = new StreamTransferProgressArgs(asyncResult.Request.ContentStream.Length, asyncResult.Request.ContentStream.Length, asyncResult.Request.ContentStream.Length);
                            if (asyncResult.Request.OriginalRequest.StreamUploadProgressCallback != null)
                            {
                                asyncResult.Request.OriginalRequest.StreamUploadProgressCallback(this, args);
                            }

                            if (args.PercentDone >= 100)
                            {
                                asyncResult.Request.OriginalRequest.StreamUploadProgressCallback = null;
                            }
                        }
                    }
                    else if (asyncResult.Request.Parameters != null && asyncResult.Request.Parameters.Count > 0)
                    {
                        requestData.Data = GetRequestData(asyncResult.Request);
                    }
                }

                asyncResult.RequestData = requestData;

                // setting up callback for response handling
                asyncResult.WaitCallback = this.ProcessHttpResponse;

                // switching to main thread to make the network call
                AmazonMainThreadDispatcher.QueueAWSRequest(asyncResult);
            }
            catch (Exception e)
            {
                AmazonLogging.LogException(AmazonLogging.AmazonLoggingLevel.Errors, asyncResult.Request.ServiceName, e);

                asyncResult.IsCompleted = true;
                asyncResult.HandleException(e);
                return;
            }
        }