Search code examples
.netportable-class-librarydotnet-httpclientwindows-10-universalsystem.net

HttpClient does not send same request in W10 UAP


I am currently facing what I think is a bug the System.Net.Http library and its HttpClient class. Please note that I am using the HttpClient from a Portable Class Library.

If I user HttpClient.SendAsync the following query : https://api.twitter.com/1.1/search/tweets.json?q=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%21&result_type=mixed&count=100, the query executed by .NET is different if it is run in UAP and if it is run in a Console application. (query = Привет!)

I have been able to identify this via Fiddler:

Console Application :

GET https://api.twitter.com/1.1/search/tweets.json?q=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82!&result_type=mixed&count=100 HTTP/1.1

User-Agent: Tweetinvi/0.9.11.1

Cache-Control: no-cache

Authorization: OAuth oauth_consumer_key="jjMV4k3n9EswD9hlhRZqQCZrm",oauth_nonce="222222",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1458086400",oauth_token="1693649419-BlEivyWIiOVrb22JjdzRipXWp4ltVdo4VLye1VW",oauth_version="1.0",oauth_signature="ODaUZNfxMbM7l0gtZ1GEFsjr%2BAA%3D"

Host: api.twitter.com

Connection: Keep-Alive

Windows 10 Universal App :

GET https://api.twitter.com/1.1/search/tweets.json?q=%D0%9F%D1%80%D0%B8%D0%B2%D0%B5%D1%82%21&result_type=mixed&count=100 HTTP/1.1

Cache-Control: no-cache

User-Agent: Tweetinvi/0.9.11.1

Authorization: OAuth oauth_consumer_key="jjMV4k3n9EswD9hlhRZqQCZrm",oauth_nonce="222222",oauth_signature_method="HMAC-SHA1",oauth_timestamp="1458086400",oauth_token="1693649419-BlEivyWIiOVrb22JjdzRipXWp4ltVdo4VLye1VW",oauth_version="1.0",oauth_signature="ODaUZNfxMbM7l0gtZ1GEFsjr%2BAA%3D"

Host: api.twitter.com

Connection: Keep-Alive

Cookie: guest_id=v1%3A145704170375190067

If you take attention, you will notice that on the console, the end of the query parameter is %82! (with a question mark).

On the other side the W10 query parameter finishes by %82%21. Here the question mark has kept its HTML escaping.

You can also notice that W10 is adding a cookie.

Is it a bug of the .NET Framework/HttpClient library?

I can assure that the query entered is the SAME in the HttpClient.SendAsync as both application uses the same binaries to create and execute the query (and I verified).

Here is my code for reference:

public class HttpClientWebHelper : IHttpClientWebHelper
{
    public async Task<HttpResponseMessage> GetHttpResponse(ITwitterQuery twitterQuery, HttpContent httpContent = null, ITwitterClientHandler handler = null)
    {
        using (var client = GetHttpClient(twitterQuery, handler))
        {
            client.Timeout = twitterQuery.Timeout;

            var httpMethod = new HttpMethod(twitterQuery.HttpMethod.ToString());

            if (httpContent == null)
            {
                return await client.SendAsync(new HttpRequestMessage(httpMethod, twitterQuery.QueryURL)).ConfigureAwait(false);
            }
            else
            {
                if (httpMethod != HttpMethod.Post)
                {
                    throw new ArgumentException("Cannot send HttpContent in a WebRequest that is not POST.");
                }

                return await client.PostAsync(twitterQuery.QueryURL, httpContent).ConfigureAwait(false);
            }
        }
    }

    public HttpClient GetHttpClient(ITwitterQuery twitterQuery, ITwitterClientHandler twitterHandler = null)
    {
        var handler = (twitterHandler as TwitterClientHandler) ?? new TwitterClientHandler();
        handler.TwitterQuery = twitterQuery;

        var client = new HttpClient(handler)
        {
            Timeout = twitterQuery.Timeout,
        };

        return client;
    }
}

Solution

  • In order to close this question and give some feedback to the users who need more information about it.

    I have had discussion with the .NET development team and they agreed that it was a bug. The problem is that they generate the query via System.Uri that do not work the same in both versions.

    You can learn more with the 2 associated issues on the .NET github.