123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 |
- #if !BESTHTTP_DISABLE_COOKIES && (!UNITY_WEBGL || UNITY_EDITOR)
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- #if NETFX_CORE
- using FileStream = BestHTTP.PlatformSupport.IO.FileStream;
- using Directory = BestHTTP.PlatformSupport.IO.Directory;
- using File = BestHTTP.PlatformSupport.IO.File;
- using BestHTTP.PlatformSupport.IO;
- #else
- using FileStream = System.IO.FileStream;
- using Directory = System.IO.Directory;
- using System.IO;
- #endif
- namespace BestHTTP.Cookies
- {
- /// <summary>
- /// The Cookie Jar implementation based on RFC 6265(http://tools.ietf.org/html/rfc6265).
- /// </summary>
- public static class CookieJar
- {
- // Version of the cookie store. It may be used in a future version for maintaining compatibility.
- private const int Version = 1;
- /// <summary>
- /// Returns true if File apis are supported.
- /// </summary>
- public static bool IsSavingSupported
- {
- get
- {
- if (IsSupportCheckDone)
- return _isSavingSupported;
- try
- {
- File.Exists(HTTPManager.GetRootCacheFolder());
- _isSavingSupported = true;
- }
- catch
- {
- _isSavingSupported = false;
- HTTPManager.Logger.Warning("CookieJar", "Cookie saving and loading disabled!");
- }
- finally
- {
- IsSupportCheckDone = true;
- }
- return _isSavingSupported;
- }
- }
- /// <summary>
- /// The plugin will delete cookies that are accessed this threshold ago. Its default value is 7 days.
- /// </summary>
- public static TimeSpan AccessThreshold = TimeSpan.FromDays(7);
- #region Privates
- /// <summary>
- /// List of the Cookies
- /// </summary>
- private static List<Cookie> Cookies = new List<Cookie>();
- private static string CookieFolder { get; set; }
- private static string LibraryPath { get; set; }
- /// <summary>
- /// Synchronization object for thread safety.
- /// </summary>
- private static object Locker = new object();
- private static bool _isSavingSupported;
- private static bool IsSupportCheckDone;
- private static bool Loaded;
- #endregion
- #region Internal Functions
- internal static void SetupFolder()
- {
- if (!CookieJar.IsSavingSupported)
- return;
- try
- {
- if (string.IsNullOrEmpty(CookieFolder) || string.IsNullOrEmpty(LibraryPath))
- {
- CookieFolder = System.IO.Path.Combine(HTTPManager.GetRootCacheFolder(), "Cookies");
- LibraryPath = System.IO.Path.Combine(CookieFolder, "Library");
- }
- }
- catch
- { }
- }
- /// <summary>
- /// Will set or update all cookies from the response object.
- /// </summary>
- internal static void Set(HTTPResponse response)
- {
- if (response == null)
- return;
- lock(Locker)
- {
- try
- {
- Maintain();
- List<Cookie> newCookies = new List<Cookie>();
- var setCookieHeaders = response.GetHeaderValues("set-cookie");
- // No cookies. :'(
- if (setCookieHeaders == null)
- return;
- foreach (var cookieHeader in setCookieHeaders)
- {
- try
- {
- Cookie cookie = Cookie.Parse(cookieHeader, response.baseRequest.CurrentUri);
- if (cookie != null)
- {
- int idx;
- var old = Find(cookie, out idx);
- // if no value for the cookie or already expired then the server asked us to delete the cookie
- bool expired = string.IsNullOrEmpty(cookie.Value) || !cookie.WillExpireInTheFuture();
- if (!expired)
- {
- // no old cookie, add it straight to the list
- if (old == null)
- {
- Cookies.Add(cookie);
- newCookies.Add(cookie);
- }
- else
- {
- // Update the creation-time of the newly created cookie to match the creation-time of the old-cookie.
- cookie.Date = old.Date;
- Cookies[idx] = cookie;
- newCookies.Add(cookie);
- }
- }
- else if (idx != -1) // delete the cookie
- Cookies.RemoveAt(idx);
- }
- }
- catch
- {
- // Ignore cookie on error
- }
- }
- response.Cookies = newCookies;
- }
- catch
- {}
- }
- }
- /// <summary>
- /// Deletes all expired or 'old' cookies, and will keep the sum size of cookies under the given size.
- /// </summary>
- internal static void Maintain()
- {
- // It's not the same as in the rfc:
- // http://tools.ietf.org/html/rfc6265#section-5.3
- lock (Locker)
- {
- try
- {
- uint size = 0;
- for (int i = 0; i < Cookies.Count; )
- {
- var cookie = Cookies[i];
- // Remove expired or not used cookies
- if (!cookie.WillExpireInTheFuture() || (cookie.LastAccess + AccessThreshold) < DateTime.UtcNow)
- Cookies.RemoveAt(i);
- else
- {
- if (!cookie.IsSession)
- size += cookie.GuessSize();
- i++;
- }
- }
- if (size > HTTPManager.CookieJarSize)
- {
- Cookies.Sort();
- while (size > HTTPManager.CookieJarSize && Cookies.Count > 0)
- {
- var cookie = Cookies[0];
- Cookies.RemoveAt(0);
- size -= cookie.GuessSize();
- }
- }
- }
- catch
- { }
- }
- }
- /// <summary>
- /// Saves the Cookie Jar to a file.
- /// </summary>
- /// <remarks>Not implemented under Unity WebPlayer</remarks>
- internal static void Persist()
- {
- if (!IsSavingSupported)
- return;
- lock (Locker)
- {
- if (!Loaded)
- return;
- try
- {
- // Delete any expired cookie
- Maintain();
- if (!Directory.Exists(CookieFolder))
- Directory.CreateDirectory(CookieFolder);
- using (var fs = new FileStream(LibraryPath, FileMode.Create))
- using (var bw = new System.IO.BinaryWriter(fs))
- {
- bw.Write(Version);
- // Count how many non-session cookies we have
- int count = 0;
- foreach (var cookie in Cookies)
- if (!cookie.IsSession)
- count++;
- bw.Write(count);
- // Save only the persistable cookies
- foreach (var cookie in Cookies)
- if (!cookie.IsSession)
- cookie.SaveTo(bw);
- }
- }
- catch
- { }
- }
- }
- /// <summary>
- /// Load previously persisted cookie library from the file.
- /// </summary>
- internal static void Load()
- {
- if (!IsSavingSupported)
- return;
- lock (Locker)
- {
- if (Loaded)
- return;
- SetupFolder();
- try
- {
- Cookies.Clear();
- if (!Directory.Exists(CookieFolder))
- Directory.CreateDirectory(CookieFolder);
- if (!File.Exists(LibraryPath))
- return;
- using (var fs = new FileStream(LibraryPath, FileMode.Open))
- using (var br = new System.IO.BinaryReader(fs))
- {
- /*int version = */br.ReadInt32();
- int cookieCount = br.ReadInt32();
- for (int i = 0; i < cookieCount; ++i)
- {
- Cookie cookie = new Cookie();
- cookie.LoadFrom(br);
- if (cookie.WillExpireInTheFuture())
- Cookies.Add(cookie);
- }
- }
- }
- catch
- {
- Cookies.Clear();
- }
- finally
- {
- Loaded = true;
- }
- }
- }
- #endregion
- #region Public Functions
- /// <summary>
- /// Returns all Cookies that corresponds to the given Uri.
- /// </summary>
- public static List<Cookie> Get(Uri uri)
- {
- lock (Locker)
- {
- Load();
- List<Cookie> result = null;
- for (int i = 0; i < Cookies.Count; ++i)
- {
- Cookie cookie = Cookies[i];
- if (cookie.WillExpireInTheFuture() && uri.Host.IndexOf(cookie.Domain) != -1 && uri.AbsolutePath.StartsWith(cookie.Path))
- {
- if (result == null)
- result = new List<Cookie>();
- result.Add(cookie);
- }
- }
- return result;
- }
- }
- /// <summary>
- /// Will add a new, or overwrite an old cookie if already exists.
- /// </summary>
- public static void Set(Uri uri, Cookie cookie)
- {
- Set(cookie);
- }
- /// <summary>
- /// Will add a new, or overwrite an old cookie if already exists.
- /// </summary>
- public static void Set(Cookie cookie)
- {
- lock (Locker)
- {
- Load();
- int idx;
- Find(cookie, out idx);
- if (idx >= 0)
- Cookies[idx] = cookie;
- else
- Cookies.Add(cookie);
- }
- }
- public static List<Cookie> GetAll()
- {
- lock (Locker)
- {
- Load();
- return Cookies;
- }
- }
- /// <summary>
- /// Deletes all cookies from the Jar.
- /// </summary>
- public static void Clear()
- {
- lock (Locker)
- {
- Load();
- Cookies.Clear();
- }
- }
- /// <summary>
- /// Removes cookies that older than the given parameter.
- /// </summary>
- public static void Clear(TimeSpan olderThan)
- {
- lock (Locker)
- {
- Load();
- for (int i = 0; i < Cookies.Count; )
- {
- var cookie = Cookies[i];
- // Remove expired or not used cookies
- if (!cookie.WillExpireInTheFuture() || (cookie.Date + olderThan) < DateTime.UtcNow)
- Cookies.RemoveAt(i);
- else
- i++;
- }
- }
- }
- /// <summary>
- /// Removes cookies that matches to the given domain.
- /// </summary>
- public static void Clear(string domain)
- {
- lock (Locker)
- {
- Load();
- for (int i = 0; i < Cookies.Count; )
- {
- var cookie = Cookies[i];
- // Remove expired or not used cookies
- if (!cookie.WillExpireInTheFuture() || cookie.Domain.IndexOf(domain) != -1)
- Cookies.RemoveAt(i);
- else
- i++;
- }
- }
- }
- public static void Remove(Uri uri, string name)
- {
- lock(Locker)
- {
- Load();
- for (int i = 0; i < Cookies.Count; )
- {
- var cookie = Cookies[i];
- if (cookie.Name.Equals(name, StringComparison.OrdinalIgnoreCase) && uri.Host.IndexOf(cookie.Domain) != -1)
- Cookies.RemoveAt(i);
- else
- i++;
- }
- }
- }
- #endregion
- #region Private Helper Functions
- /// <summary>
- /// Find and return a Cookie and his index in the list.
- /// </summary>
- private static Cookie Find(Cookie cookie, out int idx)
- {
- for (int i = 0; i < Cookies.Count; ++i)
- {
- Cookie c = Cookies[i];
- if (c.Equals(cookie))
- {
- idx = i;
- return c;
- }
- }
- idx = -1;
- return null;
- }
- #endregion
- }
- }
- #endif
|