/// <summary>
        /// Searches package sources given name and version information
        ///
        /// Package information must be returned using <c>request.YieldPackage(...)</c> function.
        /// </summary>
        /// <param name="name">a name or partial name of the package(s) requested</param>
        /// <param name="requiredVersion">A specific version of the package. Null or empty if the user did not specify</param>
        /// <param name="minimumVersion">A minimum version of the package. Null or empty if the user did not specify</param>
        /// <param name="maximumVersion">A maximum version of the package. Null or empty if the user did not specify</param>
        /// <param name="id">if this is greater than zero (and the number should have been generated using <c>StartFind(...)</c>, the core is calling this multiple times to do a batch search request. The operation can be delayed until <c>CompleteFind(...)</c> is called</param>
        /// <param name="request">An object passed in from the PackageManagement that contains functions that can be used to interact with its Provider</param>
        public void FindPackage(string name, string requiredVersion, string minimumVersion, string maximumVersion, int id, NuGetRequest request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            // true if we want to include the max and min version
            bool minInclusive = true;
            bool maxInclusive = true;

            // If finding by canonical id, then the version follows dependency version requirement
            if (request.GetOptionValue("FindByCanonicalId").IsTrue())
            {
                // Use the dependency version if no min and max is supplied
                if (String.IsNullOrWhiteSpace(maximumVersion) && String.IsNullOrWhiteSpace(minimumVersion))
                {
                    DependencyVersion depVers = DependencyVersion.ParseDependencyVersion(requiredVersion);
                    maximumVersion = depVers.MaxVersion.ToStringSafe();
                    minimumVersion = depVers.MinVersion.ToStringSafe();
                    minInclusive   = depVers.IsMinInclusive;
                    maxInclusive   = depVers.IsMaxInclusive;

                    // set required version if we have both min max as the same value.
                    if (depVers.MaxVersion != null && depVers.MinVersion != null &&
                        depVers.MaxVersion == depVers.MinVersion && minInclusive && maxInclusive)
                    {
                        requiredVersion = maximumVersion;
                    }
                    else
                    {
                        requiredVersion = null;
                    }
                }
            }

            request.Debug(Resources.Messages.DebugInfoCallMethod, PackageProviderName, string.Format(CultureInfo.InvariantCulture, "FindPackage' - name='{0}', requiredVersion='{1}',minimumVersion='{2}', maximumVersion='{3}'", name, requiredVersion, minimumVersion, maximumVersion));

            NormalizeVersion(request, ref requiredVersion, ref minimumVersion, ref maximumVersion);

            // First call to SearchPackages will just look for the packages with current credentials
            if (SearchPackages(name, requiredVersion, minimumVersion, maximumVersion, minInclusive, maxInclusive, id, request))
            {
                return;
            }

            if (request.CredentialUsername.IsNullOrEmpty())
            {
                // If no packages were found, try again using credentials retrieved from credential provider
                // First call to the credential provider is to get credentials, but if those credentials fail,
                // we call the cred provider again to ask the user for new credentials, and then search pkgs again using new creds
                var query       = new Uri(request.FindRegisteredSource(request.Sources.First()).Location.IsNullOrEmpty() ? request.Sources.First() : request.FindRegisteredSource(request.Sources.First()).Location);
                var credentials = request.GetCredsFromCredProvider(query.AbsoluteUri, request, false);
                var newclient   = PathUtility.GetHttpClientHelper(credentials.UserName, credentials.SecurePassword, request.WebProxy);
                request.SetHttpClient(newclient);

                if (SearchPackages(name, requiredVersion, minimumVersion, maximumVersion, minInclusive, maxInclusive, id, request))
                {
                    return;
                }

                // Calling the credential provider for a second time, using -IsRetry
                credentials = request.GetCredsFromCredProvider(query.AbsoluteUri, request, true);
                newclient   = PathUtility.GetHttpClientHelper(credentials.UserName, credentials.SecurePassword, request.WebProxy);
                request.SetHttpClient(newclient);

                if (SearchPackages(name, requiredVersion, minimumVersion, maximumVersion, minInclusive, maxInclusive, id, request))
                {
                    return;
                }
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Returns the validated uri. Returns null if we cannot validate it
        /// </summary>
        /// <param name="query"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        internal static Uri ValidateUri(Uri query, NuGetRequest request)
        {
            // Validation takes place in two steps:
            //  1. Validate the given URI is valid, resolving redirection
            //  2. Validate we can hit the query service
            NetworkCredential credentials = null;
            var client = request.ClientWithoutAcceptHeader;

            var response = PathUtility.GetHttpResponse(client, query.AbsoluteUri, (() => request.IsCanceled),
                                                       ((msg, num) => request.Verbose(Resources.Messages.RetryingDownload, msg, num)), (msg) => request.Verbose(msg), (msg) => request.Debug(msg));

            if (response == null)
            {
                return(null);
            }

            // if response is not success, we need to check for redirection
            if (!response.IsSuccessStatusCode)
            {
                // Check for redirection (http status code 3xx)
                if (response.StatusCode == HttpStatusCode.MultipleChoices || response.StatusCode == HttpStatusCode.MovedPermanently ||
                    response.StatusCode == HttpStatusCode.Found || response.StatusCode == HttpStatusCode.SeeOther ||
                    response.StatusCode == HttpStatusCode.TemporaryRedirect)
                {
                    // get the redirected direction
                    string location = response.Headers.GetValues("Location").FirstOrDefault();
                    if (String.IsNullOrWhiteSpace(location))
                    {
                        return(null);
                    }

                    // make a new query based on location
                    query = new Uri(location);
                }
                else
                {
                    if (response.StatusCode == HttpStatusCode.Unauthorized)
                    {
                        // If the uri is not validated, try again using credentials retrieved from credential provider
                        // First call to the credential provider is to get credentials, but if those credentials fail,
                        // we call the cred provider again to ask the user for new credentials, and then search try to validate uri again using new creds
                        credentials = request.GetCredsFromCredProvider(query.AbsoluteUri.ToString(), request, false);
                        var newClient = PathUtility.GetHttpClientHelper(credentials.UserName, credentials.SecurePassword, null);

                        var newResponse = PathUtility.GetHttpResponse(newClient, query.AbsoluteUri, (() => request.IsCanceled),
                                                                      ((msg, num) => request.Verbose(Resources.Messages.RetryingDownload, msg, num)), (msg) => request.Verbose(msg), (msg) => request.Debug(msg));
                        query = new Uri(newResponse.RequestMessage.RequestUri.AbsoluteUri);

                        request.SetHttpClient(newClient);

                        if (newResponse.StatusCode == HttpStatusCode.Unauthorized)
                        {
                            // Calling the credential provider for a second time, using -IsRetry
                            credentials = request.GetCredsFromCredProvider(query.AbsoluteUri.ToString(), request, true);
                            newClient   = PathUtility.GetHttpClientHelper(credentials.UserName, credentials.SecurePassword, null);

                            newResponse = PathUtility.GetHttpResponse(newClient, query.AbsoluteUri, (() => request.IsCanceled),
                                                                      ((msg, num) => request.Verbose(Resources.Messages.RetryingDownload, msg, num)), (msg) => request.Verbose(msg), (msg) => request.Debug(msg));
                            query = new Uri(newResponse.RequestMessage.RequestUri.AbsoluteUri);

                            request.SetHttpClient(newClient);

                            if (newResponse.StatusCode == HttpStatusCode.Unauthorized)
                            {
                                request.WriteError(ErrorCategory.PermissionDenied, "ValidateUri", Resources.Messages.AccessPermissionDenied, query);
                                return(null);
                            }
                        }
                    }
                    else
                    {
                        // other status code is wrong
                        return(null);
                    }
                }
            }
            else
            {
                query = new Uri(response.RequestMessage.RequestUri.AbsoluteUri);
            }

            IPackageRepository repo = PackageRepositoryFactory.Default.CreateRepository(new PackageRepositoryCreateParameters(query.AbsoluteUri, request, locationValid: true));

            if (repo.ResourceProvider != null)
            {
                // If the query feed exists, it's a non-local repo
                // Check the query feed to make sure it's available
                // Optionally we could change this to check the packages feed for availability
                if (repo.ResourceProvider.QueryFeed == null || !repo.ResourceProvider.QueryFeed.IsAvailable(new RequestWrapper(request, credentials)))
                {
                    return(null);
                }
            }

            return(query);
        }