0

I am trying to pass login creds from a WebView into an HttpWebRequest but not having any luck getting an authenticated response. I am able to successfully make the request, but the response is acting like I haven't logged in. My app has 5 WebViews contained within Fragment s and I'm logged in on all of them. I've tried using the CookieSyncManager but it's deprecated and .Sync() didn't work. I've tried a lot of different ways of passing the cookies into the HttpRequest with no success and many hours spent.

One would think this is a simple request; user has logged in within the app; they should be authenticated for all requests. Here's the closest that I've gotten, but the response string is still not the same as through my authenticated WebView :

This attempt parses each Cookie into a string and adds it

    public string _cookieString { get; set; }

    private class ExtWebViewClient : WebViewClient
    {
        TheFragment5 _fm5 = new TheFragment5();

        public override void OnPageFinished(WebView view, string url)
        {
            var cookieHeader = Android.Webkit.CookieManager.Instance.GetCookie(url);
            var cookiePairs = cookieHeader.Split('&');
            _fm5._cookieString = "";

            foreach (var cookiePair in cookiePairs)
            {
                var cookiePieces = cookiePair.Split('=');
                if (cookiePieces[0].Contains(":"))
                    cookiePieces[0] = cookiePieces[0].Substring(0, cookiePieces[0].IndexOf(":"));
                cookies.Add(new Cookie
                {
                    Name = cookiePieces[0],
                    Value = cookiePieces[1]
                });
            }

            foreach (Cookie c in cookies)
            {
                if (_fm5._cookieString == "")
                {
                    _fm5._cookieString = c.ToString();
                }
                else
                {
                    _fm5._cookieString += c.ToString();
                }
            }
        }
    }

I've also tried just doing:

_fm5._cookieString = cookieHeader.ToString();

but neither of those attempts is working when I add the cookie string into my HttpRequest :

        public async void GetNotificationText(string url)
        {
            //var _cmhc = _cookieMan.HasCookies;
            await Task.Run(() =>
            {

                _notificationHttpRequestInProgress = true;

                try
                {
                    var _ctxxx = Android.App.Application.Context;

                    //URL _url2 = new URL("https://bitchute.com/notifications/");
                    //HttpURLConnection conn = (HttpURLConnection)_url2.OpenConnection();

                    //conn.ReadTimeout = 10000 /* milliseconds */;
                    //conn.ConnectTimeout = 15000 /* milliseconds */;
                    ////conn.SetRequestProperty("Cookie", cookies);
                    //conn.Connect();

                    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);

                    Uri uri = new Uri(url);

                    var _req = request;
                    var _uriii = uri;
                    var _cookiesss = _fm5._cookieString;

                    _cookieCon.SetCookies(uri, _cookiesss);

                    request.CookieContainer = _cookieCon;
                    //request.CookieContainer.SetCookies(uri, _cookiesss);

                    request.AutomaticDecompression = DecompressionMethods.GZip;

                    using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                    using (Stream stream = response.GetResponseStream())
                    using (StreamReader reader = new StreamReader(stream))
                    {
                        _notificationRawText = reader.ReadToEnd();
                        Console.WriteLine(_notificationRawText);
                        _rawNoteText = _notificationRawText;
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                _notificationHttpRequestInProgress = false;
            });

        }

This returns, but not the authenticated webtext request; I get the same response any user would get on a browser having never logged in. If I were to browse out to this same url on any WebView in my app, I'd get a completely different response.

You will also notice some commented out code that was another failed attempt at adding the cookies into a connection. I had also tried using HttpURLConnection.SetRequestProperty("Cookie", cookies);

where cookies was a CookieCollection and that didn't work either. The code is mostly commented out and layered because I've been trying this for days.

Does anyone know how I can pass WebView cookies into an HttpRequest using Xamarin.Android?

I am putting this code below in Fragment5 of my app; you can see and compile the full context here:

https://github.com/hexag0d/BitChute_Mobile_Android_BottomNav/blob/NotificationAdder/Fragments/TheFragment5.cs

hexagod
  • 449
  • 3
  • 15
  • ,If you want to get cookie from webview and set in httpclient, I suggest you can take a look:https://stackoverflow.com/questions/26798500/android-sync-cookies-webview-and-httpclient – Cherry Bu - MSFT Sep 18 '19 at 07:52
  • I tried that and it didn't work. It might have something to do with the fact that Xamarin.Android doesn't have a `CookieStore`? Thanks for the response tho! – hexagod Sep 22 '19 at 16:40

1 Answers1

0

I'm not sure exactly why the above example didn't work; maybe if you're better at .NET than I am, you could figure it out. However, I was able to successfully pass WebView creds into an HttpClient by following these steps, which are returning an authenticated response. This may not be the most elegant way of doing it, but you can always refine my answer, or post a better one.

What I had to do was set the HttpClient.DefaultRequestHeaders using the .Add() method like this: _client.DefaultRequestHeaders.Add("Cookie", TheFragment5._cookieHeader);

I got the CookieHeader (which is just a string btw) like this:

//instantiate a string that will house our cookie header

public static string _cookieHeader;

//you might want to make it private to prevent abuse
//but this example is just for demonstration
//the thing is we need a string to house our headers in scope of both the WebView and the HttpClient

//extend the WebViewClient
        private class ExtWebViewClient : WebViewClient
        {
            public override void OnPageFinished(WebView view, string url)
            {
            //I get the cookies when the page finishes loading because
            //then we know the cookie has our login cred header
            //also, most of the previous examples got the cookies OnPageFinished

            TheFragment5._cookieHeader = Android.Webkit.CookieManager.Instance.GetCookie(url);

            }
        }

Then we need another method for the HttpClient and HttpClientHandler ... mine scans a webpage for notification text.


            public async void GetNotificationText(string url)
            {
                await Task.Run(() =>
                {
                   /* this line is pretty important, 
                    we need to instantiate an HttpClientHandler 
                    then set it's UseCookies property to false
                    so that it doesn't override our cookies
                  */
                    HttpClientHandler handler = new HttpClientHandler() { UseCookies = false };

                    try
                    {
                        Uri _notificationURI = new Uri("https://bitchute.com/notifications/");

                        //instantiate HttpClient using the handler
                        using (HttpClient _client = new HttpClient(handler))
                        {
                         //this line is where the magic happens; 
                         //we set the DefaultRequestHeaders with the cookieheader we got from WebViewClient.OnPageFinished                
                         _client.DefaultRequestHeaders.Add("Cookie", TheFragment5._cookieHeader);

                            //do a GetAsync request with our cookied up client
                            var getRequest = _client.GetAsync("https://bitchute.com/notifications/").Result;

                            //resultContent is the authenticated html string response from the server, ready to be parsed =]
                            var resultContent = getRequest.Content.ReadAsStringAsync().Result;

                            /*
                            I was writing to console to check the                
                            response.. for me, I am now getting  
                            the authenticated notification html 
                            page
                            */
                            Console.WriteLine(resultContent);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }   
                }
            }

Hope this helps you, posting for future reference, especially for people using Xamarin.Android.

hexagod
  • 449
  • 3
  • 15