Ejemplo n.º 1
0
        private HttpResponseMessage Get(Uri uri, string accept, int retries)
        {
            //work out the basic scope + action we'd need to perform this GET
            string scope = null;

            if (_TokenSource.TryParseScope(uri, out var scopePath))
            {
                var action = scopePath == "registry:catalog" ? "*" : "pull";
                scope = $"{scopePath}:{action}";
            }

            using (var client = new HttpClient(new HttpClientHandler {
                AllowAutoRedirect = false
            }))
            {
                client.Timeout = Timeout;
                HttpResponseMessage result;
                var message = new HttpRequestMessage {
                    RequestUri = uri
                };
                message.Headers.Authorization = _TokenSource.GetAuthorization(scope);

                if (!string.IsNullOrEmpty(accept))
                {
                    message.Headers.Add("Accept", accept);
                }

                try
                {
                    result = client.SendAsync(message).Result;
                }
                catch
                {
                    if (retries > 0)
                    {
                        result = Get(uri, accept, retries - 1);
                    }
                    else
                    {
                        throw;
                    }
                }

                if (result.IsSuccessStatusCode)
                {
                    return(result);
                }
                else if (retries > 0)
                {
                    if (result.StatusCode == HttpStatusCode.Unauthorized && !string.IsNullOrEmpty(scope))
                    {
                        var authRequest = _TokenSource.ParseWwwAuthenticate(result.Headers.WwwAuthenticate.First());
                        if (authRequest.scope != scope)
                        {
                            throw new ArgumentException($"The scope requested by the server ({authRequest.scope}) does not match that expected by the auth engine ({scope})");
                        }
                        // skip service check for dockerhub, since it returns inconsistent values
                        //if (!IsDockerHub && authRequest.service != Host) { throw new ArgumentException($"The service indicated by the server ({authRequest.service}), does not match that expected by the auth engine ({Host})."); }

                        if (_TokenSource.UpdateAuthorization(authRequest.scope))
                        {
                            return(Get(uri, accept, retries - 1));
                        }
                        else
                        {
                            throw new Exception($"Access was denied to the remote resource, and authorization could not be obtained.");
                        }
                    }
                    else if (result.StatusCode == HttpStatusCode.Redirect || result.StatusCode == HttpStatusCode.RedirectKeepVerb)
                    {
                        //decriment retries even though nothing failed, to ensure we don't get caught in a redirect loop
                        return(Get(result.Headers.Location, accept, retries - 1));
                    }
                    else if (result.StatusCode == HttpStatusCode.NotFound)
                    {
                        throw new NotFoundException();
                    }
                    else
                    {
                        System.Threading.Thread.Sleep(1000);
                        return(Get(uri, accept, retries - 1));
                    }
                }
                else
                {
                    throw new Exception($"The remote request failed with status {result.StatusCode}");
                }
            }
        }