internal static void AddHeaders2(WWWRequestData requestData, IDictionary <string, string> headersToAdd)
        {
            var headers = requestData.Headers;

            foreach (var kvp in headersToAdd)
            {
                if (WebHeaderCollection.IsRestricted(kvp.Key) || string.Equals(kvp.Key, "Range", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.Equals(kvp.Key, "Accept", StringComparison.OrdinalIgnoreCase))
                    {
                        headers.Add("Accept", kvp.Value);
                    }
                    else if (string.Equals(kvp.Key, "Connection", StringComparison.OrdinalIgnoreCase))
                    {
                        headers.Add("Connection", kvp.Value);
                    }
                    else if (string.Equals(kvp.Key, "Content-Type", StringComparison.OrdinalIgnoreCase))
                    {
                        headers.Add("Content-Type", kvp.Value);
                    }
                    else if (string.Equals(kvp.Key, "Content-Length", StringComparison.OrdinalIgnoreCase))
                    {
                        headers.Add("Content-Length", kvp.Value);
                    }
                    else if (string.Equals(kvp.Key, "Expect", StringComparison.OrdinalIgnoreCase))
                    {
                        headers.Add("Expect", kvp.Value);
                    }
                    else if (string.Equals(kvp.Key, "Date", StringComparison.OrdinalIgnoreCase))
                    {
                        headers.Add("Date", kvp.Value);
                    }
                    else if (string.Equals(kvp.Key, "User-Agent", StringComparison.OrdinalIgnoreCase))
                    {
                        #if !UNITY_WEBPLAYER
                        headers.Add("User-Agent", kvp.Value);
                        #endif
                    }
                    else if (string.Equals(kvp.Key, "Host", StringComparison.OrdinalIgnoreCase))
                    {
                        #if !UNITY_WEBPLAYER
                        headers.Add("Host", kvp.Value);
                        #endif
                    }
                    else if (string.Equals(kvp.Key, "Range", StringComparison.OrdinalIgnoreCase))
                    {
                        headers.Add("Range", kvp.Value);
                    }
                    else if (string.Equals(kvp.Key, "If-Modified-Since", StringComparison.OrdinalIgnoreCase))
                    {
                        headers.Add("If-Modified-Since", kvp.Value);
                    }
                    else
                    {
                        throw new NotSupportedException("Header with name " + kvp.Key + " is not supported");
                    }
                }
                else
                {
                    headers.Add(kvp.Key, kvp.Value);
                }
            }
        }
        private void ProcessS3PostRequest(AsyncResult asyncResult, PostObjectRequest request)
        {
            try
            {
                WWWRequestData requestData = new WWWRequestData();
                string         subdomain   = request.Region.Equals(RegionEndpoint.USEast1) ? "s3" : "s3-" + request.Region.SystemName;

                if (request.Bucket.IndexOf('.') > -1)
                {
                    requestData.Url = string.Format(CultureInfo.InvariantCulture, "http://{0}.amazonaws.com/{1}/", subdomain, request.Bucket);
                }
                else
                {
                    requestData.Url = string.Format(CultureInfo.InvariantCulture, "http://{0}.{1}.amazonaws.com", request.Bucket, subdomain);
                }


                // prepare WWW
                var boundary = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace('=', 'z');
                requestData.Headers.Add(HeaderKeys.ContentTypeHeader, string.Format(CultureInfo.InvariantCulture, "multipart/form-data; boundary={0}", boundary));
#if !UNITY_WEBPLAYER
                requestData.Headers.Add(HeaderKeys.UserAgentHeader, UNITY_USER_AGENT);
#endif

                // append upload data

                using (var reqStream = new MemoryStream())
                {
                    request.WriteFormData(boundary, reqStream);

                    byte[] boundaryBytes = Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"file\"\r\n\r\n", boundary));

                    reqStream.Write(boundaryBytes, 0, boundaryBytes.Length);

                    using (var inputStream = null == request.Path ? request.InputStream : File.OpenRead(request.Path))
                    {
                        byte[] buf = new byte[1024];
                        int    bytesRead;
                        while ((bytesRead = inputStream.Read(buf, 0, 1024)) > 0)
                        {
                            reqStream.Write(buf, 0, bytesRead);
                        }
                    }

                    byte[] endBoundaryBytes = Encoding.UTF8.GetBytes(string.Format(CultureInfo.InvariantCulture, "\r\n--{0}--", boundary));

                    reqStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
                    AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "S3", requestData.Url);

                    requestData.Data = reqStream.ToArray();
                }
                AmazonLogging.Log(AmazonLogging.AmazonLoggingLevel.Verbose, "S3", Encoding.Default.GetString(requestData.Data));

                asyncResult.RequestData  = requestData;
                asyncResult.WaitCallback = ProcessS3PostResponse;

                // switching to main thread
                AmazonMainThreadDispatcher.QueueAWSRequest(asyncResult);
            }
            catch (Exception e)
            {
                AmazonLogging.LogError(AmazonLogging.AmazonLoggingLevel.Errors, "S3", e.Message);
                asyncResult.IsCompleted = true;
                asyncResult.HandleException(e);
                return;
            }
        }
        /// <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;
            }
        }