private void DownloadAsync(IWWWRequest wwwRequest, string originalUrl, string redirectedUrl, Action <WWWResponse> callback)
        {
            WWWRequestWrapper requestWrapper;

            // It is possible for 'SendGetRequest' or 'SendPostRequest' to have completed immediately.
            // If this is the case, then we don't mark the request as pending.
            var responseReceived = false;

            Action <WWWResponse> responseHandler = (response) =>
            {
                responseReceived = true;
                DownloadAsyncResponse(response, wwwRequest, originalUrl, callback);
            };

            var headers = GetCacheHeaders(originalUrl);

            if (headers == null)
            {
                requestWrapper = wwwRequest.SendGetRequest(coroutineHost, redirectedUrl, responseHandler);
            }
            else
            {
                requestWrapper = wwwRequest.SendPostRequest(coroutineHost, redirectedUrl, null, headers, responseHandler);
            }

            if (!responseReceived)
            {
                pendingDownloadRequests.Add(requestWrapper);
            }
        }
        public void Start()
        {
            Action runTask = () =>
            {
                var headers = new Dictionary <string, string>
                {
                    { "Accept", "application/json" }
                };
                var url = string.Format("{0}/assembly_content/v3/{1}/{2}/artifacts", infraServiceUrl, projectName, assemblyName);

                activeRequest = wwwRequest.SendPostRequest(coroutineHost, url, null, headers, (response) =>
                {
                    if (state == State.Cancelled)
                    {
                        // Ignore cancelled requests because the Cancel function will already call taskRunner.ProcessResult.
                        return;
                    }

                    taskRunner.ProcessResult(response);
                });

                state = State.Started;
            };
            Func <WWWResponse, TaskResult> evaluationFunc = response =>
            {
                if (state == State.Cancelled)
                {
                    // Return a success so it will finish running the task and will not be retried.

                    return(new TaskResult
                    {
                        IsSuccess = true
                    });
                }

                return(new TaskResult
                {
                    IsSuccess = string.IsNullOrEmpty(response.Error),
                    ErrorMessage = response.Error
                });
            };
            Action <WWWResponse> onSuccess = response =>
            {
                if (state == State.Cancelled)
                {
                    // Do not call the onAssetsResolved or onFailed here, as the owner of this instance has initiated the request be cancelled.
                    return;
                }

                state = State.Completed;

                var assetUrls    = new Dictionary <string, string>();
                var jsonResponse = JsonUtility.FromJson <AssemblyResponse>(response.Text);
                if (jsonResponse.Artifacts.Count == 0)
                {
                    onFailed(new Exception(string.Format("No artifacts found at {0}", response.Url)));
                }
                else
                {
                    for (var i = 0; i < jsonResponse.Artifacts.Count; i++)
                    {
                        var artifact = jsonResponse.Artifacts[i];
                        assetUrls[artifact.ArtifactId.Name] = artifact.Url;
                    }

                    onAssetsResolved(assetUrls);
                }
            };
            Action <string> onFailure = (string errorMessage) =>
            {
                state = State.Completed;

                onFailed(new Exception("Failed to retrieve assembly list: " + errorMessage));
            };

            taskRunner.RunTaskWithRetries("CloudAssemblyArtifactResolver::ResolveAssetUrls", coroutineHost, runTask, evaluationFunc, onSuccess, onFailure);
        }