using System; using System.Collections.Concurrent; using System.Collections.Generic; #if !BESTHTTP_DISABLE_CACHING using BestHTTP.Caching; #endif using BestHTTP.Core; using BestHTTP.Extensions; using BestHTTP.Logger; using BestHTTP.PlatformSupport.Memory; namespace BestHTTP { public enum ShutdownTypes { Running, Gentle, Immediate } /// /// /// public static partial class HTTPManager { // Static constructor. Setup default values static HTTPManager() { MaxConnectionPerServer = 6; KeepAliveDefaultValue = true; MaxPathLength = 255; MaxConnectionIdleTime = TimeSpan.FromSeconds(20); #if !BESTHTTP_DISABLE_COOKIES #if UNITY_WEBGL // Under webgl when IsCookiesEnabled is true, it will set the withCredentials flag for the XmlHTTPRequest // and that's different from the default behavior. // https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials IsCookiesEnabled = false; #else IsCookiesEnabled = true; #endif #endif CookieJarSize = 10 * 1024 * 1024; EnablePrivateBrowsing = false; ConnectTimeout = TimeSpan.FromSeconds(20); RequestTimeout = TimeSpan.FromSeconds(60); // Set the default logger mechanism logger = new BestHTTP.Logger.DefaultLogger(); #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) DefaultCertificateVerifyer = null; UseAlternateSSLDefaultValue = true; #endif #if NETFX_CORE IOService = new PlatformSupport.FileSystem.NETFXCOREIOService(); #elif UNITY_WEBGL && !UNITY_EDITOR IOService = new PlatformSupport.FileSystem.WebGLIOService(); #else IOService = new PlatformSupport.FileSystem.DefaultIOService(); #endif } #if (!UNITY_WEBGL || UNITY_EDITOR) && !BESTHTTP_DISABLE_ALTERNATE_SSL && !BESTHTTP_DISABLE_HTTP2 /// /// HTTP/2 settings /// public static Connections.HTTP2.HTTP2PluginSettings HTTP2Settings = new Connections.HTTP2.HTTP2PluginSettings(); #endif #region Global Options /// /// The maximum active TCP connections that the client will maintain to a server. Default value is 4. Minimum value is 1. /// public static byte MaxConnectionPerServer { get{ return maxConnectionPerServer; } set { if (value <= 0) throw new ArgumentOutOfRangeException("MaxConnectionPerServer must be greater than 0!"); bool isGrowing = value > maxConnectionPerServer; maxConnectionPerServer = value; // If the allowed connections per server is growing, go through all hosts and try to send out queueud requests. if (isGrowing) HostManager.TryToSendQueuedRequests(); } } private static byte maxConnectionPerServer; /// /// Default value of a HTTP request's IsKeepAlive value. Default value is true. If you make rare request to the server it should be changed to false. /// public static bool KeepAliveDefaultValue { get; set; } #if !BESTHTTP_DISABLE_CACHING /// /// Set to true, if caching is prohibited. /// public static bool IsCachingDisabled { get; set; } #endif /// /// How many time must be passed to destroy that connection after a connection finished its last request. Its default value is 20 seconds. /// public static TimeSpan MaxConnectionIdleTime { get; set; } #if !BESTHTTP_DISABLE_COOKIES /// /// Set to false to disable all Cookie. It's default value is true. /// public static bool IsCookiesEnabled { get; set; } #endif /// /// Size of the Cookie Jar in bytes. It's default value is 10485760 (10 MB). /// public static uint CookieJarSize { get; set; } /// /// If this property is set to true, then new cookies treated as session cookies and these cookies are not saved to disk. Its default value is false; /// public static bool EnablePrivateBrowsing { get; set; } /// /// Global, default value of the HTTPRequest's ConnectTimeout property. If set to TimeSpan.Zero or lower, no connect timeout logic is executed. Default value is 20 seconds. /// public static TimeSpan ConnectTimeout { get; set; } /// /// Global, default value of the HTTPRequest's Timeout property. Default value is 60 seconds. /// public static TimeSpan RequestTimeout { get; set; } /// /// By default the plugin will save all cache and cookie data under the path returned by Application.persistentDataPath. /// You can assign a function to this delegate to return a custom root path to define a new path. /// This delegate will be called on a non Unity thread! /// public static System.Func RootCacheFolderProvider { get; set; } #if !BESTHTTP_DISABLE_PROXY /// /// The global, default proxy for all HTTPRequests. The HTTPRequest's Proxy still can be changed per-request. Default value is null. /// public static Proxy Proxy { get; set; } #endif /// /// Heartbeat manager to use less threads in the plugin. The heartbeat updates are called from the OnUpdate function. /// public static HeartbeatManager Heartbeats { get { if (heartbeats == null) heartbeats = new HeartbeatManager(); return heartbeats; } } private static HeartbeatManager heartbeats; /// /// A basic BestHTTP.Logger.ILogger implementation to be able to log intelligently additional informations about the plugin's internal mechanism. /// public static BestHTTP.Logger.ILogger Logger { get { // Make sure that it has a valid logger instance. if (logger == null) { logger = new DefaultLogger(); logger.Level = Loglevels.None; } return logger; } set { logger = value; } } private static BestHTTP.Logger.ILogger logger; #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR) /// /// The default ICertificateVerifyer implementation that the plugin will use when the request's UseAlternateSSL property is set to true. /// public static SecureProtocol.Org.BouncyCastle.Crypto.Tls.ICertificateVerifyer DefaultCertificateVerifyer { get; set; } /// /// The default IClientCredentialsProvider implementation that the plugin will use when the request's UseAlternateSSL property is set to true. /// public static SecureProtocol.Org.BouncyCastle.Crypto.Tls.IClientCredentialsProvider DefaultClientCredentialsProvider { get; set; } /// /// The default value for the HTTPRequest's UseAlternateSSL property. /// public static bool UseAlternateSSLDefaultValue { get; set; } #endif #if !NETFX_CORE public static Func DefaultCertificationValidator { get; set; } #endif /// /// TCP Client's send buffer size. /// public static int SendBufferSize = 65 * 1024; /// /// TCP Client's receive buffer size. /// public static int ReceiveBufferSize = 65 * 1024; /// /// An IIOService implementation to handle filesystem operations. /// public static PlatformSupport.FileSystem.IIOService IOService; /// /// On most systems the maximum length of a path is around 255 character. If a cache entity's path is longer than this value it doesn't get cached. There no platform independent API to query the exact value on the current system, but it's /// exposed here and can be overridden. It's default value is 255. /// internal static int MaxPathLength { get; set; } /// /// User-agent string that will be sent with each requests. /// public static string UserAgent = "BestHTTP 2.0.4"; #endregion #region Manager variables internal static bool IsQuitting { get; private set; } private static bool IsSetupCalled; #endregion #region Public Interface public static void Setup() { if (IsSetupCalled) return; IsSetupCalled = true; HTTPManager.Logger.Information("HTTPManager", "Setup called!"); IsQuitting = false; HTTPUpdateDelegator.CheckInstance(); #if !BESTHTTP_DISABLE_CACHING HTTPCacheService.CheckSetup(); #endif #if !BESTHTTP_DISABLE_COOKIES Cookies.CookieJar.SetupFolder(); Cookies.CookieJar.Load(); #endif HostManager.Load(); } public static HTTPRequest SendRequest(string url, OnRequestFinishedDelegate callback) { return SendRequest(new HTTPRequest(new Uri(url), HTTPMethods.Get, callback)); } public static HTTPRequest SendRequest(string url, HTTPMethods methodType, OnRequestFinishedDelegate callback) { return SendRequest(new HTTPRequest(new Uri(url), methodType, callback)); } public static HTTPRequest SendRequest(string url, HTTPMethods methodType, bool isKeepAlive, OnRequestFinishedDelegate callback) { return SendRequest(new HTTPRequest(new Uri(url), methodType, isKeepAlive, callback)); } public static HTTPRequest SendRequest(string url, HTTPMethods methodType, bool isKeepAlive, bool disableCache, OnRequestFinishedDelegate callback) { return SendRequest(new HTTPRequest(new Uri(url), methodType, isKeepAlive, disableCache, callback)); } public static HTTPRequest SendRequest(HTTPRequest request) { if (request.IsCancellationRequested || IsQuitting) return request; if (!IsSetupCalled) Setup(); #if !BESTHTTP_DISABLE_CACHING // If possible load the full response from cache. if (Caching.HTTPCacheService.IsCachedEntityExpiresInTheFuture(request)) { PlatformSupport.Threading.ThreadedRunner.RunShortLiving((req) => { if (Connections.ConnectionHelper.TryLoadAllFromCache("HTTPManager", req)) req.State = HTTPRequestStates.Finished; else { // If for some reason it couldn't load we place back the request to the queue. RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(request, RequestEvents.Resend)); } }, request); } else #endif RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(request, RequestEvents.Resend)); return request; } #endregion #region Internal Helper Functions /// /// Will return where the various caches should be saved. /// internal static string GetRootCacheFolder() { try { if (RootCacheFolderProvider != null) return RootCacheFolderProvider(); } catch(Exception ex) { HTTPManager.Logger.Exception("HTTPManager", "GetRootCacheFolder", ex); } #if NETFX_CORE return Windows.Storage.ApplicationData.Current.LocalFolder.Path; #else return UnityEngine.Application.persistentDataPath; #endif } [UnityEngine.RuntimeInitializeOnLoadMethod(UnityEngine.RuntimeInitializeLoadType.AfterSceneLoad)] static void Reset() { IsSetupCalled = false; HTTPManager.Logger.Information("HTTPManager", "Reset called!"); } #endregion #region MonoBehaviour Events (Called from HTTPUpdateDelegator) /// /// Update function that should be called regularly from a Unity event(Update, LateUpdate). Callbacks are dispatched from this function. /// public static void OnUpdate() { RequestEventHelper.ProcessQueue(); ConnectionEventHelper.ProcessQueue(); ProtocolEventHelper.ProcessQueue(); PluginEventHelper.ProcessQueue(); BestHTTP.Extensions.Timer.Process(); if (heartbeats != null) heartbeats.Update(); BufferPool.Maintain(); } public static void OnQuit() { HTTPManager.Logger.Information("HTTPManager", "OnQuit called!"); IsQuitting = true; AbortAll(); #if !BESTHTTP_DISABLE_CACHING PluginEventHelper.EnqueuePluginEvent(new PluginEventInfo(PluginEvents.SaveCacheLibrary)); #endif #if !BESTHTTP_DISABLE_COOKIES PluginEventHelper.EnqueuePluginEvent(new PluginEventInfo(PluginEvents.SaveCookieLibrary)); #endif OnUpdate(); HostManager.Clear(); } public static void AbortAll() { HTTPManager.Logger.Information("HTTPManager", "AbortAll called!"); // This is an immediate shutdown request! RequestEventHelper.Clear(); ConnectionEventHelper.Clear(); PluginEventHelper.Clear(); ProtocolEventHelper.Clear(); HostManager.Shutdown(); ProtocolEventHelper.CancelActiveProtocols(); } #endregion } }