Search Unity

Question UnityWebRequest caches cookies between sessions in editor but not on Android device

Discussion in 'Editor & General Support' started by TomerMatific, Jun 2, 2021.

  1. TomerMatific

    TomerMatific

    Joined:
    Jan 25, 2021
    Posts:
    5
    Hi all,
    I'm writing a game which includes an authentication process with my server using Django,
    If the authentication is successful Django returns a set-cookie header with the session token and CORS token which is then set with all future UnityWebRequests from the app in that run.

    On the editor if i exit play mode and than enter it again these cookies are sent again with every request and the server immediately recognizes that I'm an authenticated user with a valid session and doesn't reject my request but on an Android device the cookies are not cached when i'm re-running the app and when i try to request something from the server I get a 403 error code because Djange doesn't know I'm a authenticated user with a valid session.

    Is there a known issue of Android not being able cache the cookies of a UnityWebRequest between sessions, if not, can someone please explain why this is working on Editor but not on an Android device?

    I'm using Unity version 2020.3.3f

    my code for sending the request is very straight forward:
    Code (CSharp):
    1. public static async UniTask<NetworkResponse> HttpGet(
    2.             string url,
    3.             [CanBeNull] Dictionary<string, string> parameters = null)
    4.         {
    5.             string formattedUrl = FormatURLParameters(url, parameters);
    6.             UnityWebRequest getRequest = UnityWebRequest.Get(formattedUrl);
    7.             getRequest.timeout = TimeOut;
    8.            
    9.             try
    10.             {
    11.                 await getRequest.SendWebRequest();
    12.             }
    13.             catch (Exception e)
    14.             {
    15.                 Debug.Log("an error occurred during HttpGet: " + e);
    16.             }
    17.  
    18.             return HandleHTTPResponse(getRequest);
    19.         }
    Any help would be greatly appreciated,
    Thanks in advance
     
  2. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Cookies are only guaranteed to be cached for a single game session. In Editor it only works because UnityWebRequest is part of the Editor too, hence cookies are cached for the whole Editor run. On most other platforms it's per game session (I believe iOS and WebGL are the notable exceptions).
     
    TomerMatific likes this.
  3. TomerMatific

    TomerMatific

    Joined:
    Jan 25, 2021
    Posts:
    5
    Thanks so much for your reply, My app runs on iOS, Android and WebGL so for me Android is exception.:)

    I just added functionality to my NetworkService that stores the cookies locally and adds them to the requests in the next session if I'm running on Android.

    I now also see that what you are saying is at least partly stated in the documentation of UnityWebRequest.ClearCookieCache, but instead of reading it I just wasted a few hours figuring this out myself....
     
  4. TomerMatific

    TomerMatific

    Joined:
    Jan 25, 2021
    Posts:
    5
    There seems to be a problem for me to set the cookie in the next session after i store the cookie locally.
    here is my code to store the cookie in the local storage:
    Code (CSharp):
    1.         private static void SetCookiesInHash(bool saveCookies, IInfraConnector connector, UnityWebRequest request)
    2.         {
    3. #if UNITY_ANDROID && !UNITY_EDITOR
    4.             if (saveCookies && request.GetResponseHeaders().TryGetValue("Set-Cookie", out string cookie))
    5.             {
    6.                 connector.SetCookie(request.uri.Host, cookie);
    7.             }
    8. #endif
    9.         }
    and here is my code to set the cookie in the request header:
    Code (CSharp):
    1. #if UNITY_ANDROID && !UNITY_EDITOR
    2.             Dictionary<string, string> cookiesHash = connector.GetCookiesHash();
    3.             if (cookiesHash.TryGetValue(request.uri.Host, out string cookie))
    4.             {
    5.                 request.SetRequestHeader("Cookie", cookie);
    6.             }
    7. #endif
    but i still get a 403 unauthorized response from the server, any idea why this is happening?
     
  5. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,732
    Use HTTP debugging proxy like Fiddler and examine raw request.
     
  6. DevDinoAdmin

    DevDinoAdmin

    Joined:
    Oct 21, 2019
    Posts:
    4
  7. TomerMatific

    TomerMatific

    Joined:
    Jan 25, 2021
    Posts:
    5
    As written above I Implemented my own solution for Android, it is a bit more complicated than the solution I wrote here.
    You need to extract only the actual cookie from the "Set-Cookie" header (without the metadata of expire date ext.).
    It will only work if you know the exact cookie name you want to cache, than you can use a simple regex to extract the cookie.
    Also I'm not sure if during the session more cookies from the same host are added what happens. still need to check that.

    Code (CSharp):
    1.  private static void SetCookiesInHash(List<string> saveCookiesList, IInfraConnector connector, UnityWebRequest request, string oldCookie)
    2.         {
    3.             if (saveCookiesList != null && request.GetResponseHeaders().TryGetValue("Set-Cookie", out string cookie))
    4.             {
    5. #if UNITY_ANDROID && !UNITY_EDITOR
    6.                 try
    7.                 {
    8.                     string formatedCookie = string.IsNullOrEmpty(oldCookie) ? "" : oldCookie;
    9.                     foreach (string cookieKey in saveCookiesList)
    10.                     {
    11.                         MatchCollection reg = Regex.Matches(cookie, $@"{cookieKey}=[^;]*");
    12.                         if (reg.Count > 0)
    13.                         {
    14.                             formatedCookie+= cookieKey + "=" + reg[0].Value.Split('=')[1] + "; ";
    15.                         }
    16.                     }
    17.                     if (!String.IsNullOrEmpty(formatedCookie))
    18.                     {
    19.                         connector.SetCookie(request.uri.Host, formatedCookie);//saves the actual cookie in the local storage
    20.                     }
    21.                 }
    22.                 catch (Exception e)
    23.                 {
    24.                     Debug.Log("Could not extreact cookie from header");
    25.                 }
    26. #endif
    27.             }
    28.         }
    Code (CSharp):
    1.         private static string SetHashedCookiesInRequest(UnityWebRequest request, IInfraConnector connector)
    2.         {
    3. #if UNITY_ANDROID && !UNITY_EDITOR
    4.             Dictionary<string, string> cookiesHash = connector.GetCookiesHash();
    5.             if (cookiesHash.TryGetValue(request.uri.Host, out string cookie))
    6.             {
    7.                 request.SetRequestHeader("Cookie", cookie);
    8.             }
    9.             return cookie;
    10. #endif
    11.             return null;
    12.         }
    hope this helps
     
    Dahaka444 likes this.
  8. DevDinoAdmin

    DevDinoAdmin

    Joined:
    Oct 21, 2019
    Posts:
    4
    Thank you,
    I do exact the same thing, some how when I set the header I get multiply calls in a loop to the server, did you encounter such behavior?
     
  9. TomerMatific

    TomerMatific

    Joined:
    Jan 25, 2021
    Posts:
    5
    No sorry I did not