Home: AutoCompleteResource.IdStartsWith does not return packages that only have pre-release versions

Created on 21 Nov 2018  路  8Comments  路  Source: NuGet/Home

Details about Problem

Hi.

As far as I can tell, AutoCompleteResource.IdStartsWith (v3 API) incorrectly passes the query parameter includePrerelease=true, but it should be passing prerelease=true (according to the API docs here).

NuGet product used: NuGet client library (specifically, NuGet.Protocol.Core.Types.AutoCompleteResource).

NuGet version: NuGet.Protocol (v4.8.0.0).

Below is a small console app that reproduces the issue and demonstrates that, if the URL uses the correct prerelease=true query parameter, correct results are returned.

Detailed repro steps so we can see the same problem

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using NuGet.Common;
using NuGet.Configuration;
using NuGet.Protocol;
using NuGet.Protocol.Core.Types;

namespace NuGetSuggestions
{
    static class Program
    {
        static async Task Main()
        {
            PackageSource packageSource = new PackageSource("https://api.nuget.org/v3/index.json");

            var providers = new List<Lazy<INuGetResourceProvider>>();
            providers.AddRange(
                Repository.Provider.GetCoreV3()
            );

            SourceRepository sourceRepository = new SourceRepository(packageSource, providers);
            AutoCompleteResource autoCompleteResource = await sourceRepository.GetResourceAsync<AutoCompleteResource>(CancellationToken.None);

            IEnumerable<string> packageIds = await autoCompleteResource.IdStartsWith("SixLabors", includePrerelease: true, log: NullLogger.Instance, CancellationToken.None);
            Console.WriteLine("Without fix, got {0} package Ids.", packageIds.Count()); // Shows 0 package Ids

            // Patch the HttpClient handler chain, inserting our fix.

            FieldInfo clientField = autoCompleteResource.GetType().GetField("_client", BindingFlags.Instance | BindingFlags.NonPublic);
            HttpSource httpSource = (HttpSource)clientField.GetValue(autoCompleteResource);

            FieldInfo httpClientField = httpSource.GetType().GetField("_httpClient", BindingFlags.Instance | BindingFlags.NonPublic);
            HttpClient httpClient = (HttpClient)httpClientField.GetValue(httpSource);

            FieldInfo handlerField = typeof(HttpMessageInvoker).GetField("_handler", BindingFlags.Instance | BindingFlags.NonPublic);
            HttpMessageHandler innerHandler = (HttpMessageHandler)handlerField.GetValue(httpClient);

            PrereleaseFixHandler prereleaseFixHandler = new PrereleaseFixHandler(innerHandler);
            httpClient = new HttpClient(prereleaseFixHandler);

            httpClientField.SetValue(httpSource, httpClient);

            packageIds = await autoCompleteResource.IdStartsWith("SixLabors", includePrerelease: true, log: NullLogger.Instance, CancellationToken.None);
            Console.WriteLine("With fix, got {0} package Ids.", packageIds.Count()); // Shows 7 package Ids
        }

        class PrereleaseFixHandler : DelegatingHandler
        {
            public PrereleaseFixHandler(HttpMessageHandler innerHandler)
                : base(innerHandler)
            {
            }

            protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage requestMessage, CancellationToken cancellationToken)
            {
                Console.WriteLine("Original request URI: {0}", requestMessage.RequestUri);

                // Fix incorrectly-named "includePrerelease" query parameter (should be "prerelease").
                requestMessage.RequestUri = new Uri(requestMessage.RequestUri.AbsoluteUri.Replace("&includePrerelease=", "&prerelease="));

                Console.WriteLine("Modified request URI: {0}", requestMessage.RequestUri);

                HttpResponseMessage responseMessage = await base.SendAsync(requestMessage, cancellationToken);

                return responseMessage;
            }
        }
    }
}
HttpCommunication Protocol 3 Bug

All 8 comments

@ryuyu
I think you might have some context about the protocol.
Has this always been the case?
Was the client implementation always wrong?

I'm happy to submit a PR if it turns out this needs fixing, by the way :)

I synced up with @joelverhagen
The v2 protocol used includePrerelease https://github.com/NuGet/NuGetGallery/blob/7bcc3973abd94302c3f61df992113dd3d31693e9/src/NuGetGallery/Controllers/ApiController.cs#L890, but the v3 uses only prerelease.

So only that needs changing.

Should I open a PR for this, then? Happy to have a go.

@tintoy
Thanks, I have assigned it to @heng-liu as she is familiarizing herself with the codebase.
I imagine she'll have a PR soon :)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

msaraf1 picture msaraf1  路  3Comments

rrelyea picture rrelyea  路  3Comments

clairernovotny picture clairernovotny  路  3Comments

livarcocc picture livarcocc  路  3Comments

p-kaczynski picture p-kaczynski  路  3Comments