private async Task <IHttpActionResult> GetCore(ODataQueryOptions <V1FeedPackage> options, string id, string version, bool return404NotFoundWhenNoResults)
        {
            var packages = _packagesRepository.GetAll()
                           .Include(p => p.PackageRegistration)
                           .Where(p => p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase) &&
                                  !p.IsPrerelease &&
                                  !p.Deleted &&
                                  p.SemVerLevelKey == SemVerLevelKey.Unknown);

            if (!string.IsNullOrEmpty(version))
            {
                packages = packages.Where(p => p.Version == version);
            }

            // try the search service
            try
            {
                var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                    _searchService, GetTraditionalHttpContext().Request, packages, id, version, curatedFeed : null);

                // If intercepted, create a paged queryresult
                if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                {
                    // Packages provided by search service
                    packages = searchAdaptorResult.Packages;

                    // Add explicit Take() needed to limit search hijack result set size if $top is specified
                    var totalHits = packages.LongCount();

                    if (return404NotFoundWhenNoResults && totalHits == 0)
                    {
                        return(NotFound());
                    }

                    var pagedQueryable = packages
                                         .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                         .ToV1FeedPackageQuery(GetSiteRoot());

                    return(QueryResult(options, pagedQueryable, MaxPageSize, totalHits, (o, s, resultCount) =>
                                       SearchAdaptor.GetNextLink(Request.RequestUri, resultCount, new { id }, o, s)));
                }
            }
            catch (Exception ex)
            {
                // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                // We don't want to break package restores. We do want to know if this happens, so here goes:
                QuietLog.LogHandledException(ex);
            }

            if (return404NotFoundWhenNoResults && !packages.Any())
            {
                return(NotFound());
            }

            var queryable = packages.ToV1FeedPackageQuery(GetSiteRoot());

            return(QueryResult(options, queryable, MaxPageSize));
        }
Пример #2
0
        public async Task <IHttpActionResult> Get(ODataQueryOptions <V2FeedPackage> options)
        {
            // Setup the search
            var packages = _packagesRepository.GetAll()
                           .Where(p => !p.Deleted && p.SemVerLevelKey == SemVerLevelKey.Unknown)
                           .WithoutSortOnColumn(Version)
                           .WithoutSortOnColumn(Id, ShouldIgnoreOrderById <V2FeedPackage>(options))
                           .InterceptWith(new NormalizeVersionInterceptor());

            // Try the search service
            try
            {
                HijackableQueryParameters hijackableQueryParameters = null;
                if (_searchService is ExternalSearchService && SearchHijacker.IsHijackable(options, out hijackableQueryParameters))
                {
                    var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                        _searchService, GetTraditionalHttpContext().Request, packages,
                        hijackableQueryParameters.Id, hijackableQueryParameters.Version, curatedFeed : null);

                    // If intercepted, create a paged queryresult
                    if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                    {
                        // Packages provided by search service
                        packages = searchAdaptorResult.Packages;

                        // Add explicit Take() needed to limit search hijack result set size if $top is specified
                        var totalHits      = packages.LongCount();
                        var pagedQueryable = packages
                                             .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                             .ToV2FeedPackageQuery(GetSiteRoot(), _configurationService.Features.FriendlyLicenses);

                        return(QueryResult(options, pagedQueryable, MaxPageSize, totalHits, (o, s, resultCount) =>
                                           SearchAdaptor.GetNextLink(Request.RequestUri, resultCount, null, o, s)));
                    }
                }
            }
            catch (Exception ex)
            {
                // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                // We don't want to break package restores. We do want to know if this happens, so here goes:
                QuietLog.LogHandledException(ex);
            }

            //Reject only when try to reach database.
            if (!ODataQueryVerifier.AreODataOptionsAllowed(options, ODataQueryVerifier.V2Packages,
                                                           _configurationService.Current.IsODataFilterEnabled, nameof(Get)))
            {
                return(BadRequest(ODataQueryVerifier.GetValidationFailedMessage(options)));
            }

            var queryable = packages.ToV2FeedPackageQuery(GetSiteRoot(), _configurationService.Features.FriendlyLicenses);

            return(QueryResult(options, queryable, MaxPageSize));
        }
Пример #3
0
        private async Task <IHttpActionResult> GetCore(
            ODataQueryOptions <V2FeedPackage> options,
            string id,
            string version,
            string semVerLevel,
            bool return404NotFoundWhenNoResults)
        {
            var packages = GetAll()
                           .Include(p => p.PackageRegistration)
                           .Where(p => p.PackageStatusKey == PackageStatus.Available &&
                                  p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase))
                           .Where(SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel));

            if (!string.IsNullOrEmpty(version))
            {
                NuGetVersion nugetVersion;
                if (NuGetVersion.TryParse(version, out nugetVersion))
                {
                    // Our APIs expect to receive normalized version strings.
                    // We need to compare normalized versions or we can never retrieve SemVer2 package versions.
                    var normalizedString = nugetVersion.ToNormalizedString();
                    packages = packages.Where(p => p.NormalizedVersion == normalizedString);
                }
            }

            var  semVerLevelKey = SemVerLevelKey.ForSemVerLevel(semVerLevel);
            bool?customQuery    = null;

            // try the search service
            try
            {
                var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                    _searchService,
                    GetTraditionalHttpContext().Request,
                    packages,
                    id,
                    version,
                    semVerLevel : semVerLevel);

                // If intercepted, create a paged queryresult
                if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                {
                    customQuery = false;

                    // Packages provided by search service
                    packages = searchAdaptorResult.Packages;

                    // Add explicit Take() needed to limit search hijack result set size if $top is specified
                    var totalHits = packages.LongCount();

                    if (totalHits == 0 && return404NotFoundWhenNoResults)
                    {
                        _telemetryService.TrackODataCustomQuery(customQuery);
                        return(NotFound());
                    }

                    var pagedQueryable = packages
                                         .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                         .ToV2FeedPackageQuery(
                        GetSiteRoot(),
                        _configurationService.Features.FriendlyLicenses,
                        semVerLevelKey);

                    return(TrackedQueryResult(
                               options,
                               pagedQueryable,
                               MaxPageSize,
                               totalHits,
                               (o, s, resultCount) => SearchAdaptor.GetNextLink(Request.RequestUri, resultCount, new { id }, o, s, semVerLevelKey),
                               customQuery));
                }
                else
                {
                    customQuery = true;
                }
            }
            catch (Exception ex)
            {
                // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                // We don't want to break package restores. We do want to know if this happens, so here goes:
                QuietLog.LogHandledException(ex);
            }

            if (return404NotFoundWhenNoResults && !packages.Any())
            {
                _telemetryService.TrackODataCustomQuery(customQuery);
                return(NotFound());
            }

            var queryable = packages.ToV2FeedPackageQuery(
                GetSiteRoot(),
                _configurationService.Features.FriendlyLicenses,
                semVerLevelKey);

            return(TrackedQueryResult(options, queryable, MaxPageSize, customQuery));
        }
Пример #4
0
        private async Task <IHttpActionResult> GetCore(
            ODataQueryOptions <V1FeedPackage> options,
            string id,
            string version,
            bool return404NotFoundWhenNoResults,
            bool isNonHijackEnabled)
        {
            var packages = GetAll()
                           .Include(p => p.PackageRegistration)
                           .Where(p => p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase) &&
                                  !p.IsPrerelease &&
                                  p.PackageStatusKey == PackageStatus.Available)
                           .Where(SemVerLevelKey.IsUnknownPredicate());

            if (!string.IsNullOrEmpty(version))
            {
                packages = packages.Where(p => p.Version == version);
            }

            bool?customQuery = null;

            // try the search service
            try
            {
                var searchService       = _searchServiceFactory.GetService();
                var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                    searchService,
                    GetTraditionalHttpContext().Request,
                    packages,
                    id,
                    version,
                    semVerLevel : null);

                // If intercepted, create a paged queryresult
                if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                {
                    customQuery = false;

                    // Packages provided by search service
                    packages = searchAdaptorResult.Packages;

                    // Add explicit Take() needed to limit search hijack result set size if $top is specified
                    var totalHits = packages.LongCount();

                    if (return404NotFoundWhenNoResults && totalHits == 0)
                    {
                        _telemetryService.TrackODataCustomQuery(customQuery);
                        return(NotFound());
                    }

                    var pagedQueryable = packages
                                         .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                         .ToV1FeedPackageQuery(GetSiteRoot());

                    return(TrackedQueryResult(
                               options,
                               pagedQueryable,
                               MaxPageSize,
                               totalHits,
                               (o, s, resultCount) => SearchAdaptor.GetNextLink(Request.RequestUri, resultCount, new { id }, o, s),
                               customQuery));
                }
                else
                {
                    customQuery = true;
                }
            }
            catch (Exception ex) when(isNonHijackEnabled)
            {
                // Swallowing exception intentionally if we are allowing a fallback to database. If non-hijacked
                // queries are disabled, let the exception bubble out and the client will retry.
                QuietLog.LogHandledException(ex);
            }

            // If we've reached this point, the hijack to the search service has failed or is not applicable. If
            // non-hijacked queries are disabled, stop here.
            if (!isNonHijackEnabled)
            {
                return(BadRequest(Strings.ODataParametersDisabled));
            }

            if (return404NotFoundWhenNoResults && !packages.Any())
            {
                _telemetryService.TrackODataCustomQuery(customQuery);
                return(NotFound());
            }

            var queryable = packages.ToV1FeedPackageQuery(GetSiteRoot());

            return(TrackedQueryResult(options, queryable, MaxPageSize, customQuery));
        }
        private async Task <IHttpActionResult> GetCore(
            ODataQueryOptions <V2FeedPackage> options,
            string curatedFeedName,
            string id,
            string normalizedVersion,
            bool return404NotFoundWhenNoResults,
            string semVerLevel)
        {
            var curatedFeed = _entities.CuratedFeeds.FirstOrDefault(cf => cf.Name == curatedFeedName);

            if (curatedFeed == null)
            {
                return(NotFound());
            }

            var packages = _curatedFeedService
                           .GetPackages(curatedFeedName)
                           .Where(p => p.PackageStatusKey == PackageStatus.Available)
                           .Where(SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel))
                           .Where(p => p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase));

            if (!string.IsNullOrEmpty(normalizedVersion))
            {
                packages = packages.Where(p => p.NormalizedVersion == normalizedVersion);
            }

            var semVerLevelKey = SemVerLevelKey.ForSemVerLevel(semVerLevel);

            // try the search service
            try
            {
                var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                    _searchService,
                    GetTraditionalHttpContext().Request,
                    packages,
                    id,
                    normalizedVersion,
                    curatedFeed : curatedFeed,
                    semVerLevel : semVerLevel);

                // If intercepted, create a paged queryresult
                if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                {
                    // Packages provided by search service
                    packages = searchAdaptorResult.Packages;

                    // Add explicit Take() needed to limit search hijack result set size if $top is specified
                    var totalHits = packages.LongCount();

                    if (return404NotFoundWhenNoResults && totalHits == 0)
                    {
                        return(NotFound());
                    }

                    var pagedQueryable = packages
                                         .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                         .ToV2FeedPackageQuery(GetSiteRoot(), _configurationService.Features.FriendlyLicenses, semVerLevelKey);

                    return(QueryResult(options, pagedQueryable, MaxPageSize, totalHits, (o, s, resultCount) =>
                                       SearchAdaptor.GetNextLink(Request.RequestUri, resultCount, new { id }, o, s)));
                }
            }
            catch (Exception ex)
            {
                // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                // We don't want to break package restores. We do want to know if this happens, so here goes:
                QuietLog.LogHandledException(ex);
            }

            if (return404NotFoundWhenNoResults && !packages.Any())
            {
                return(NotFound());
            }

            var queryable = packages.ToV2FeedPackageQuery(
                GetSiteRoot(),
                _configurationService.Features.FriendlyLicenses,
                semVerLevelKey);

            return(QueryResult(options, queryable, MaxPageSize));
        }
        public async Task <IHttpActionResult> Get(
            ODataQueryOptions <V2FeedPackage> options,
            [FromUri] string semVerLevel = null)
        {
            bool result = TryShouldIgnoreOrderById(options, out var shouldIgnoreOrderById);

            if (!result)
            {
                return(BadRequest("Invalid OrderBy parameter"));
            }

            // Setup the search
            var packages = GetAll()
                           .Where(p => p.PackageStatusKey == PackageStatus.Available)
                           .Where(SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel))
                           .WithoutSortOnColumn(Version)
                           .WithoutSortOnColumn(Id, shouldIgnoreOrderById)
                           .InterceptWith(new NormalizeVersionInterceptor());

            var  semVerLevelKey = SemVerLevelKey.ForSemVerLevel(semVerLevel);
            bool?customQuery    = null;

            var isNonHijackEnabled = _featureFlagService.IsODataV2GetAllNonHijackedEnabled();

            // Try the search service
            try
            {
                var searchService = _searchServiceFactory.GetService();
                HijackableQueryParameters hijackableQueryParameters = null;
                if (searchService is ExternalSearchService && SearchHijacker.IsHijackable(options, out hijackableQueryParameters))
                {
                    var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                        searchService,
                        GetTraditionalHttpContext().Request,
                        packages,
                        hijackableQueryParameters.Id,
                        hijackableQueryParameters.Version,
                        semVerLevel : semVerLevel);

                    // If intercepted, create a paged queryresult
                    if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                    {
                        customQuery = false;

                        // Packages provided by search service
                        packages = searchAdaptorResult.Packages;

                        // Add explicit Take() needed to limit search hijack result set size if $top is specified
                        var totalHits      = packages.LongCount();
                        var pagedQueryable = packages
                                             .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                             .ToV2FeedPackageQuery(
                            GetSiteRoot(),
                            _configurationService.Features.FriendlyLicenses,
                            semVerLevelKey);

                        return(TrackedQueryResult(
                                   options,
                                   pagedQueryable,
                                   MaxPageSize,
                                   totalHits,
                                   (o, s, resultCount) => SearchAdaptor.GetNextLink(Request.RequestUri, resultCount, null, o, s, semVerLevelKey),
                                   customQuery));
                    }
                    else
                    {
                        customQuery = true;
                    }
                }
                else
                {
                    customQuery = true;
                }
            }
            catch (ODataException ex) when(isNonHijackEnabled && ex.InnerException != null && ex.InnerException is FormatException)
            {
                // Sometimes users make invalid requests. It's not exceptional behavior, don't trace.
            }
            catch (Exception ex) when(isNonHijackEnabled)
            {
                // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                // We don't want to break package restores. We do want to know if this happens, so here goes:
                QuietLog.LogHandledException(ex);
            }

            if (!isNonHijackEnabled)
            {
                return(BadRequest(Strings.ODataParametersDisabled));
            }

            // Reject only when try to reach database.
            if (!ODataQueryVerifier.AreODataOptionsAllowed(options, ODataQueryVerifier.V2Packages,
                                                           _configurationService.Current.IsODataFilterEnabled, nameof(Get)))
            {
                return(BadRequest(ODataQueryVerifier.GetValidationFailedMessage(options)));
            }

            var queryable = packages.ToV2FeedPackageQuery(
                GetSiteRoot(),
                _configurationService.Features.FriendlyLicenses,
                semVerLevelKey);

            return(TrackedQueryResult(options, queryable, MaxPageSize, customQuery));
        }
        private async Task <IHttpActionResult> GetCore(
            ODataQueryOptions <V2FeedPackage> options,
            string id,
            string version,
            string semVerLevel,
            bool allowHijack,
            bool return404NotFoundWhenNoResults,
            bool isNonHijackEnabled)
        {
            var packages = GetAll()
                           .Include(p => p.PackageRegistration)
                           .Where(p => p.PackageStatusKey == PackageStatus.Available &&
                                  p.PackageRegistration.Id.Equals(id, StringComparison.OrdinalIgnoreCase))
                           .Where(SemVerLevelKey.IsPackageCompliantWithSemVerLevelPredicate(semVerLevel));

            if (!string.IsNullOrEmpty(version))
            {
                NuGetVersion nugetVersion;
                if (NuGetVersion.TryParse(version, out nugetVersion))
                {
                    // Our APIs expect to receive normalized version strings.
                    // We need to compare normalized versions or we can never retrieve SemVer2 package versions.
                    var normalizedString = nugetVersion.ToNormalizedString();
                    packages = packages.Where(p => p.NormalizedVersion == normalizedString);
                }
            }

            var  semVerLevelKey = SemVerLevelKey.ForSemVerLevel(semVerLevel);
            bool?customQuery    = null;

            if (allowHijack)
            {
                // try the search service
                try
                {
                    var searchService       = _searchServiceFactory.GetService();
                    var searchAdaptorResult = await SearchAdaptor.FindByIdAndVersionCore(
                        searchService,
                        GetTraditionalHttpContext().Request,
                        packages,
                        id,
                        version,
                        semVerLevel : semVerLevel);

                    // If intercepted, create a paged queryresult
                    if (searchAdaptorResult.ResultsAreProvidedBySearchService)
                    {
                        customQuery = false;

                        // Packages provided by search service
                        packages = searchAdaptorResult.Packages;

                        // Add explicit Take() needed to limit search hijack result set size if $top is specified
                        var totalHits = packages.LongCount();

                        if (totalHits == 0 && return404NotFoundWhenNoResults)
                        {
                            _telemetryService.TrackODataCustomQuery(customQuery);
                            return(NotFound());
                        }

                        var pagedQueryable = packages
                                             .Take(options.Top != null ? Math.Min(options.Top.Value, MaxPageSize) : MaxPageSize)
                                             .ToV2FeedPackageQuery(
                            GetSiteRoot(),
                            _configurationService.Features.FriendlyLicenses,
                            semVerLevelKey);

                        return(TrackedQueryResult(
                                   options,
                                   pagedQueryable,
                                   MaxPageSize,
                                   totalHits,
                                   (o, s, resultCount) => SearchAdaptor.GetNextLink(Request.RequestUri, resultCount, new { id }, o, s, semVerLevelKey),
                                   customQuery));
                    }
                    else
                    {
                        customQuery = true;
                    }
                }
                catch (Exception ex)
                {
                    // Swallowing Exception intentionally. If *anything* goes wrong in search, just fall back to the database.
                    // We don't want to break package restores. We do want to know if this happens, so here goes:
                    QuietLog.LogHandledException(ex);
                }
            }

            // When non-hijacked queries are disabled, allow only one non-hijacked pattern: query for a specific ID and
            // version without any fancy OData options. This enables some monitoring and testing and is known to produce
            // a very fast SQL query based on an optimized index.
            var isSimpleLookup = !string.IsNullOrWhiteSpace(id) &&
                                 !string.IsNullOrWhiteSpace(version) &&
                                 options.RawValues.Expand == null &&
                                 options.RawValues.Filter == null &&
                                 options.RawValues.Format == null &&
                                 options.RawValues.InlineCount == null &&
                                 options.RawValues.OrderBy == null &&
                                 options.RawValues.Select == null &&
                                 options.RawValues.Skip == null &&
                                 options.RawValues.SkipToken == null &&
                                 options.RawValues.Top == null;

            if (!allowHijack || !isNonHijackEnabled)
            {
                if (!isSimpleLookup)
                {
                    return(BadRequest(Strings.ODataParametersDisabled));
                }

                customQuery = true;
            }

            if (return404NotFoundWhenNoResults && !packages.Any())
            {
                _telemetryService.TrackODataCustomQuery(customQuery);
                return(NotFound());
            }

            var queryable = packages.ToV2FeedPackageQuery(
                GetSiteRoot(),
                _configurationService.Features.FriendlyLicenses,
                semVerLevelKey);

            return(TrackedQueryResult(options, queryable, MaxPageSize, customQuery));
        }