2

I must be missing something very obvious, but I can't tell what. I have a DoLoginAsync like so:

private async Task DoLoginAsync(bool force = false)
        {
            try
            {
                if (client.Cookies.ContainsKey("user_credentials") && !force)
                {
                    return;
                }
                var html = client.Request("login").GetStringAsync().Result;
                var doc = new HtmlDocument();
                doc.LoadHtml(html);
                var csrf_token = doc.DocumentNode.SelectNodes("//meta[@name='csrf-token']").First().GetAttributeValue("content", string.Empty);
                var values = new Dictionary<string, string>
                {
                    { "user_session[email]", user },
                    { "user_session[password]", password },
                    { "authenticity_token", csrf_token }
                };
                var result = await client.Request("user_session").PostUrlEncodedAsync(values);
            }
            catch (Exception e)
            {
            }

When I run this code in a test with a breakpoint in the catch clause I get an exception

Call failed with status code 404 (Not Found): GET http://www.whatever.com/user_session

WTF? I'm expecting PostUrlEncodedAsync to do a POST, not a GET. Anybody have an idea why this can happen?

The Flurl client is instantiated as client = new FlurlClient(BASE_URL).EnableCookies();

UPDATE

Tried the following test which fails with the same exception

[TestMethod]
        public async Task TheTest()
        {
            var message = "";
            try
            {
                var client = new FlurlClient("http://www.slimmemeterportal.nl/").EnableCookies();
                var html = await client.Request("login").GetStringAsync();
                var doc = new HtmlDocument();
                doc.LoadHtml(html);
                var csrf_token = doc.DocumentNode.SelectNodes("//meta[@name='csrf-token']").First().GetAttributeValue("content", string.Empty);
                var values = new Dictionary<string, string>
                {
                    { "user_session[email]", "******" },
                    { "user_session[password]", "******" },
                    { "commit", "inloggen" }, // Not sure if this is actually needed, but it is in the website's request parameters.
                    { "authenticity_token", csrf_token }
                };
                var result = await client.Request("user_session").PostUrlEncodedAsync(values);
            }
            catch (FlurlHttpException ex)
            {
                message = ex.Message;
            }
            Assert.AreEqual("Call failed with status code 404 (Not Found): POST http://www.slimmemeterportal.nl/user_session", message);
        }
Hintham
  • 1,078
  • 10
  • 29
  • I can't repro this. This tests passes: https://gist.github.com/tmenier/3417dcdf6ef0dfc6d0480ae778065b72. Are you seeing this every single time or occasionally in a high concurrency scenario? – Todd Menier Sep 10 '18 at 14:26
  • @ToddMenier, it's consistent. It happens always. – Hintham Sep 10 '18 at 14:27
  • Probably not related, but don't block here: `client.Request("login").GetStringAsync().Result`. Use `await client.Request("login").GetStringAsync()` instead. – Todd Menier Sep 10 '18 at 14:27
  • What version of Flurl.Http are you using? – Todd Menier Sep 10 '18 at 14:27
  • Yes, indeed. It's some testing code. But good point anyway – Hintham Sep 10 '18 at 14:28
  • I'm using 2.8.0, installed via NuGet. Project is .NET core 2.1 – Hintham Sep 10 '18 at 14:29
  • 2.8.0 is probably Flurl, not [Flurl.Http](https://www.nuget.org/packages/Flurl.Http/). They're versioned separately. Make sure you're on the latest version of Flurl.Http. Also try running my gist in your project. – Todd Menier Sep 10 '18 at 14:33
  • Flurl.Http is 2.4.0. Your test passes on my system as well. I'm going to try and refactor a bit to be closer to your test. – Hintham Sep 10 '18 at 14:35
  • I've added a test, same result. I don't see ant fundamental differences with your test? – Hintham Sep 10 '18 at 14:43
  • With your test I'm failing earlier: "Call failed. An error occurred while sending the request. GET http://www.slimmemeterportal.nl/login". Inner exception: "SocketException: An existing connection was forcibly closed by the remote host". When I switch to Google URLs, it's still behaving as expected. Something's off here. Your posted code is _exactly_ what's running? You're certain that the first GET is to `/login` and the error refers to `GET .../user_session`? If so, I'm completely baffled. – Todd Menier Sep 10 '18 at 14:56
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/179758/discussion-between-hintham-and-todd-menier). – Hintham Sep 10 '18 at 16:13

1 Answers1

5

Mystery solved: As it turns out after some debugging with Wireshark, the website was returning HTTP status code 301. As explained here the default action is to follow the URI in the response's location header using a GET even if the original request was a POST.

Hintham
  • 1,078
  • 10
  • 29