up
This commit is contained in:
358
Assets/BestHTTP/Cookies/Cookie.cs
Normal file
358
Assets/BestHTTP/Cookies/Cookie.cs
Normal file
@@ -0,0 +1,358 @@
|
||||
#if !BESTHTTP_DISABLE_COOKIES && (!UNITY_WEBGL || UNITY_EDITOR)
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BestHTTP.Extensions;
|
||||
using System.IO;
|
||||
|
||||
namespace BestHTTP.Cookies
|
||||
{
|
||||
/// <summary>
|
||||
/// The Cookie implementation based on RFC 6265(http://tools.ietf.org/html/rfc6265).
|
||||
/// </summary>
|
||||
public sealed class Cookie : IComparable<Cookie>, IEquatable<Cookie>
|
||||
{
|
||||
private const int Version = 1;
|
||||
|
||||
#region Public Properties
|
||||
|
||||
/// <summary>
|
||||
/// The name of the cookie.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The value of the cookie.
|
||||
/// </summary>
|
||||
public string Value { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Date when the Cookie is registered.
|
||||
/// </summary>
|
||||
public DateTime Date { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// When this Cookie last used in a request.
|
||||
/// </summary>
|
||||
public DateTime LastAccess { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Expires attribute indicates the maximum lifetime of the cookie, represented as the date and time at which the cookie expires.
|
||||
/// The user agent is not required to retain the cookie until the specified date has passed.
|
||||
/// In fact, user agents often evict cookies due to memory pressure or privacy concerns.
|
||||
/// </summary>
|
||||
public DateTime Expires { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Max-Age attribute indicates the maximum lifetime of the cookie, represented as the number of seconds until the cookie expires.
|
||||
/// The user agent is not required to retain the cookie for the specified duration.
|
||||
/// In fact, user agents often evict cookies due to memory pressure or privacy concerns.
|
||||
/// </summary>
|
||||
public long MaxAge { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If a cookie has neither the Max-Age nor the Expires attribute, the user agent will retain the cookie until "the current session is over".
|
||||
/// </summary>
|
||||
public bool IsSession { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Domain attribute specifies those hosts to which the cookie will be sent.
|
||||
/// For example, if the value of the Domain attribute is "example.com", the user agent will include the cookie
|
||||
/// in the Cookie header when making HTTP requests to example.com, www.example.com, and www.corp.example.com.
|
||||
/// If the server omits the Domain attribute, the user agent will return the cookie only to the origin server.
|
||||
/// </summary>
|
||||
public string Domain { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The scope of each cookie is limited to a set of paths, controlled by the Path attribute.
|
||||
/// If the server omits the Path attribute, the user agent will use the "directory" of the request-uri's path component as the default value.
|
||||
/// </summary>
|
||||
public string Path { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Secure attribute limits the scope of the cookie to "secure" channels (where "secure" is defined by the user agent).
|
||||
/// When a cookie has the Secure attribute, the user agent will include the cookie in an HTTP request only if the request is
|
||||
/// transmitted over a secure channel (typically HTTP over Transport Layer Security (TLS)).
|
||||
/// </summary>
|
||||
public bool IsSecure { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// The HttpOnly attribute limits the scope of the cookie to HTTP requests.
|
||||
/// In particular, the attribute instructs the user agent to omit the cookie when providing access to
|
||||
/// cookies via "non-HTTP" APIs (such as a web browser API that exposes cookies to scripts).
|
||||
/// </summary>
|
||||
public bool IsHttpOnly { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
public Cookie(string name, string value)
|
||||
:this(name, value, "/", string.Empty)
|
||||
{}
|
||||
|
||||
public Cookie(string name, string value, string path)
|
||||
: this(name, value, path, string.Empty)
|
||||
{}
|
||||
|
||||
public Cookie(string name, string value, string path, string domain)
|
||||
:this() // call the parameter-less constructor to set default values
|
||||
{
|
||||
this.Name = name;
|
||||
this.Value = value;
|
||||
this.Path = path;
|
||||
this.Domain = domain;
|
||||
}
|
||||
|
||||
public Cookie(Uri uri, string name, string value, DateTime expires, bool isSession = true)
|
||||
:this(name, value, uri.AbsolutePath, uri.Host)
|
||||
{
|
||||
this.Expires = expires;
|
||||
this.IsSession = isSession;
|
||||
this.Date = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public Cookie(Uri uri, string name, string value, long maxAge = -1, bool isSession = true)
|
||||
:this(name, value, uri.AbsolutePath, uri.Host)
|
||||
{
|
||||
this.MaxAge = maxAge;
|
||||
this.IsSession = isSession;
|
||||
this.Date = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
internal Cookie()
|
||||
{
|
||||
// If a cookie has neither the Max-Age nor the Expires attribute, the user agent will retain the cookie
|
||||
// until "the current session is over" (as defined by the user agent).
|
||||
IsSession = true;
|
||||
MaxAge = -1;
|
||||
LastAccess = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
public bool WillExpireInTheFuture()
|
||||
{
|
||||
// No Expires or Max-Age value sent from the server, we will fake the return value so we will not delete the newly came Cookie
|
||||
if (IsSession)
|
||||
return true;
|
||||
|
||||
// If a cookie has both the Max-Age and the Expires attribute, the Max-Age attribute has precedence and controls the expiration date of the cookie.
|
||||
return MaxAge != -1 ?
|
||||
Math.Max(0, (long)(DateTime.UtcNow - Date).TotalSeconds) < MaxAge :
|
||||
Expires > DateTime.UtcNow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Guess the storage size of the cookie.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public uint GuessSize()
|
||||
{
|
||||
return (uint)((Name != null ? Name.Length * sizeof(char) : 0) +
|
||||
(Value != null ? Value.Length * sizeof(char) : 0) +
|
||||
(Domain != null ? Domain.Length * sizeof(char) : 0) +
|
||||
(Path != null ? Path.Length * sizeof(char) : 0) +
|
||||
(sizeof(long) * 4) +
|
||||
(sizeof(bool) * 3));
|
||||
}
|
||||
|
||||
public static Cookie Parse(string header, Uri defaultDomain)
|
||||
{
|
||||
Cookie cookie = new Cookie();
|
||||
try
|
||||
{
|
||||
var kvps = ParseCookieHeader(header);
|
||||
|
||||
foreach (var kvp in kvps)
|
||||
{
|
||||
switch (kvp.Key.ToLowerInvariant())
|
||||
{
|
||||
case "path":
|
||||
// If the attribute-value is empty or if the first character of the attribute-value is not %x2F ("/"):
|
||||
// Let cookie-path be the default-path.
|
||||
cookie.Path = string.IsNullOrEmpty(kvp.Value) || !kvp.Value.StartsWith("/") ? "/" : cookie.Path = kvp.Value;
|
||||
break;
|
||||
|
||||
case "domain":
|
||||
// If the attribute-value is empty, the behavior is undefined. However, the user agent SHOULD ignore the cookie-av entirely.
|
||||
if (string.IsNullOrEmpty(kvp.Value))
|
||||
return null;
|
||||
|
||||
// If the first character of the attribute-value string is %x2E ("."):
|
||||
// Let cookie-domain be the attribute-value without the leading %x2E (".") character.
|
||||
cookie.Domain = kvp.Value.StartsWith(".") ? kvp.Value.Substring(1) : kvp.Value;
|
||||
break;
|
||||
|
||||
case "expires":
|
||||
cookie.Expires = kvp.Value.ToDateTime(DateTime.FromBinary(0));
|
||||
cookie.IsSession = false;
|
||||
break;
|
||||
|
||||
case "max-age":
|
||||
cookie.MaxAge = kvp.Value.ToInt64(-1);
|
||||
cookie.IsSession = false;
|
||||
break;
|
||||
|
||||
case "secure":
|
||||
cookie.IsSecure = true;
|
||||
break;
|
||||
|
||||
case "httponly":
|
||||
cookie.IsHttpOnly = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
cookie.Name = kvp.Key;
|
||||
cookie.Value = kvp.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Some user agents provide users the option of preventing persistent storage of cookies across sessions.
|
||||
// When configured thusly, user agents MUST treat all received cookies as if the persistent-flag were set to false.
|
||||
if (HTTPManager.EnablePrivateBrowsing)
|
||||
cookie.IsSession = true;
|
||||
|
||||
// http://tools.ietf.org/html/rfc6265#section-4.1.2.3
|
||||
// WARNING: Some existing user agents treat an absent Domain attribute as if the Domain attribute were present and contained the current host name.
|
||||
// For example, if example.com returns a Set-Cookie header without a Domain attribute, these user agents will erroneously send the cookie to www.example.com as well.
|
||||
if (string.IsNullOrEmpty(cookie.Domain))
|
||||
cookie.Domain = defaultDomain.Host;
|
||||
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.3 section 7:
|
||||
// If the cookie-attribute-list contains an attribute with an attribute-name of "Path",
|
||||
// set the cookie's path to attribute-value of the last attribute in the cookie-attribute-list with an attribute-name of "Path".
|
||||
// __Otherwise, set the cookie's path to the default-path of the request-uri.__
|
||||
if (string.IsNullOrEmpty(cookie.Path))
|
||||
cookie.Path = defaultDomain.AbsolutePath;
|
||||
|
||||
cookie.Date = cookie.LastAccess = DateTime.UtcNow;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
return cookie;
|
||||
}
|
||||
|
||||
#region Save & Load
|
||||
|
||||
internal void SaveTo(BinaryWriter stream)
|
||||
{
|
||||
stream.Write(Version);
|
||||
stream.Write(Name ?? string.Empty);
|
||||
stream.Write(Value ?? string.Empty);
|
||||
stream.Write(Date.ToBinary());
|
||||
stream.Write(LastAccess.ToBinary());
|
||||
stream.Write(Expires.ToBinary());
|
||||
stream.Write(MaxAge);
|
||||
stream.Write(IsSession);
|
||||
stream.Write(Domain ?? string.Empty);
|
||||
stream.Write(Path ?? string.Empty);
|
||||
stream.Write(IsSecure);
|
||||
stream.Write(IsHttpOnly);
|
||||
}
|
||||
|
||||
internal void LoadFrom(BinaryReader stream)
|
||||
{
|
||||
/*int version = */stream.ReadInt32();
|
||||
this.Name = stream.ReadString();
|
||||
this.Value = stream.ReadString();
|
||||
this.Date = DateTime.FromBinary(stream.ReadInt64());
|
||||
this.LastAccess = DateTime.FromBinary(stream.ReadInt64());
|
||||
this.Expires = DateTime.FromBinary(stream.ReadInt64());
|
||||
this.MaxAge = stream.ReadInt64();
|
||||
this.IsSession = stream.ReadBoolean();
|
||||
this.Domain = stream.ReadString();
|
||||
this.Path = stream.ReadString();
|
||||
this.IsSecure = stream.ReadBoolean();
|
||||
this.IsHttpOnly = stream.ReadBoolean();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Overrides and new Equals function
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return string.Concat(this.Name, "=", this.Value);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
return this.Equals(obj as Cookie);
|
||||
}
|
||||
|
||||
public bool Equals(Cookie cookie)
|
||||
{
|
||||
if (cookie == null)
|
||||
return false;
|
||||
|
||||
if (Object.ReferenceEquals(this, cookie))
|
||||
return true;
|
||||
|
||||
return this.Name.Equals(cookie.Name, StringComparison.Ordinal) &&
|
||||
((this.Domain == null && cookie.Domain == null) || this.Domain.Equals(cookie.Domain, StringComparison.Ordinal)) &&
|
||||
((this.Path == null && cookie.Path == null) || this.Path.Equals(cookie.Path, StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return this.ToString().GetHashCode();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Private Helper Functions
|
||||
|
||||
private static string ReadValue(string str, ref int pos)
|
||||
{
|
||||
string result = string.Empty;
|
||||
if (str == null)
|
||||
return result;
|
||||
|
||||
return str.Read(ref pos, ';');
|
||||
}
|
||||
|
||||
private static List<HeaderValue> ParseCookieHeader(string str)
|
||||
{
|
||||
List<HeaderValue> result = new List<HeaderValue>();
|
||||
|
||||
if (str == null)
|
||||
return result;
|
||||
|
||||
int idx = 0;
|
||||
|
||||
// process the rest of the text
|
||||
while (idx < str.Length)
|
||||
{
|
||||
// Read key
|
||||
string key = str.Read(ref idx, (ch) => ch != '=' && ch != ';').Trim();
|
||||
HeaderValue qp = new HeaderValue(key);
|
||||
|
||||
if (idx < str.Length && str[idx - 1] == '=')
|
||||
qp.Value = ReadValue(str, ref idx);
|
||||
|
||||
result.Add(qp);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IComparable<Cookie> implementation
|
||||
|
||||
public int CompareTo(Cookie other)
|
||||
{
|
||||
return this.LastAccess.CompareTo(other.LastAccess);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
11
Assets/BestHTTP/Cookies/Cookie.cs.meta
Normal file
11
Assets/BestHTTP/Cookies/Cookie.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0aa7201aae8a944d580350b37ceefef5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
484
Assets/BestHTTP/Cookies/CookieJar.cs
Normal file
484
Assets/BestHTTP/Cookies/CookieJar.cs
Normal file
@@ -0,0 +1,484 @@
|
||||
#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;
|
||||
}
|
||||
}
|
||||
|
||||
#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;
|
||||
TimeSpan accessThreshold = TimeSpan.FromDays(7);
|
||||
|
||||
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)
|
||||
{
|
||||
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
|
||||
11
Assets/BestHTTP/Cookies/CookieJar.cs.meta
Normal file
11
Assets/BestHTTP/Cookies/CookieJar.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae9aa41306e754581b311c084eebd182
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user