internal void AddProtocol(HostProtocolSupport protocolSupport) { this.LastProtocolSupportUpdate = DateTime.UtcNow; var oldProtocol = this.ProtocolSupport; if (oldProtocol != this.ProtocolSupport) { this.ProtocolSupport = protocolSupport; HTTPManager.Logger.Information(typeof(HostConnection).Name, string.Format("AddProtocol({0}): changing from {1} to {2}", protocolSupport, oldProtocol, this.ProtocolSupport)); HostManager.Save(); TryToSendQueuedRequests(); } }
internal static void HandleRequestStateChange(RequestEventInfo @event) { HTTPRequest source = @event.SourceRequest; switch (@event.State) { case HTTPRequestStates.Processing: if ((!source.UseStreaming && source.UploadStream == null) || source.EnableTimoutForStreaming) { BestHTTP.Extensions.Timer.Add(new TimerData(TimeSpan.FromSeconds(1), @event.SourceRequest, AbortRequestWhenTimedOut)); } break; case HTTPRequestStates.Aborted: case HTTPRequestStates.ConnectionTimedOut: case HTTPRequestStates.TimedOut: case HTTPRequestStates.Error: case HTTPRequestStates.Finished: if (source.Callback != null) { try { source.Callback(source, source.Response); } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "HandleRequestStateChange " + @event.State, ex); } //if (source.Response != null && source.Response.Data != null) // VariableSizedBufferPool.Release(source.Response.Data); } source.Dispose(); HostManager.GetHost(source.CurrentUri.Host) .GetHostDefinition(HostDefinition.GetKeyForRequest(source)) .TryToSendQueuedRequests(); break; } }
internal static void ProcessQueue() { ProtocolEventInfo protocolEvent; while (protocolEvents.TryDequeue(out protocolEvent)) { if (HTTPManager.Logger.Level == Loglevels.All) { HTTPManager.Logger.Information("ProtocolEventHelper", "Processing protocol event: " + protocolEvent.ToString()); } if (OnEvent != null) { try { OnEvent(protocolEvent); } catch (Exception ex) { HTTPManager.Logger.Exception("ProtocolEventHelper", "ProcessQueue", ex); } } IProtocol protocol = protocolEvent.Source; protocol.HandleEvents(); if (protocol.IsClosed) { ActiveProtocols.Remove(protocol); HostManager.GetHost(protocol.ConnectionKey.Host) .GetHostDefinition(protocol.ConnectionKey.Connection) .DecreaseActiveConnectionCount(); protocol.Dispose(); } } }
internal static void ProcessQueue() { ConnectionEventInfo connectionEvent; while (connectionEventQueue.TryDequeue(out connectionEvent)) { if (HTTPManager.Logger.Level == Loglevels.All) { HTTPManager.Logger.Information("ConnectionEventHelper", "Processing connection event: " + connectionEvent.ToString(), connectionEvent.Source.Context); } if (OnEvent != null) { try { OnEvent(connectionEvent); } catch (Exception ex) { HTTPManager.Logger.Exception("ConnectionEventHelper", "ProcessQueue", ex, connectionEvent.Source.Context); } } switch (connectionEvent.Event) { case ConnectionEvents.StateChange: HandleConnectionStateChange(connectionEvent); break; case ConnectionEvents.ProtocolSupport: HostManager.GetHost(connectionEvent.Source.LastProcessedUri.Host) .GetHostDefinition(connectionEvent.Source.ServerAddress) .AddProtocol(connectionEvent.ProtocolSupport); break; } } }
internal static void HandleRequestStateChange(RequestEventInfo @event) { HTTPRequest source = @event.SourceRequest; // Because there's a race condition between setting the request's State in its Abort() function running on Unity's main thread // and the HTTP1/HTTP2 handlers running on an another one. // Because of these race conditions cases violating expectations can be: // 1.) State is finished but the response null // 2.) State is (Connection)TimedOut and the response non-null // We have to make sure that no callbacks are called twice and in the request must be in a consistent state! // State | Request // --------- +--------- // 1 Null // Finished | Skip // Timeout/Abort | Deliver // // 2 Non-Null // Finished | Deliver // Timeout/Abort | Skip switch (@event.State) { case HTTPRequestStates.Queued: source.QueuedAt = DateTime.UtcNow; if ((!source.UseStreaming && source.UploadStream == null) || source.EnableTimoutForStreaming) { BestHTTP.Extensions.Timer.Add(new TimerData(TimeSpan.FromSeconds(1), @event.SourceRequest, AbortRequestWhenTimedOut)); } break; case HTTPRequestStates.ConnectionTimedOut: case HTTPRequestStates.TimedOut: case HTTPRequestStates.Error: case HTTPRequestStates.Aborted: source.Response = null; goto case HTTPRequestStates.Finished; case HTTPRequestStates.Finished: #if !BESTHTTP_DISABLE_CACHING // Here we will try to load content for a failed load. Failed load is a request with ConnectionTimedOut, TimedOut or Error state. // A request with Finished state but response with status code >= 500 also something that we will try to load from the cache. // We have to set what we going to try to load here too (other place is inside IsCachedEntityExpiresInTheFuture) as we don't want to load a cached content for // a request that just finished without any problem! try { bool tryLoad = !source.DisableCache && source.State != HTTPRequestStates.Aborted && (source.State != HTTPRequestStates.Finished || source.Response == null || source.Response.StatusCode >= 500); if (tryLoad && Caching.HTTPCacheService.IsCachedEntityExpiresInTheFuture(source)) { HTTPManager.Logger.Information("RequestEventHelper", "IsCachedEntityExpiresInTheFuture check returned true! CurrentUri: " + source.CurrentUri.ToString(), source.Context); PlatformSupport.Threading.ThreadedRunner.RunShortLiving <HTTPRequest>((req) => { // Disable any other cache activity. req.DisableCache = true; var originalState = req.State; if (Connections.ConnectionHelper.TryLoadAllFromCache("RequestEventHelper", req, req.Context)) { if (req.State != HTTPRequestStates.Finished) { req.State = HTTPRequestStates.Finished; } else { RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(req, HTTPRequestStates.Finished)); } } else { HTTPManager.Logger.Information("RequestEventHelper", "TryLoadAllFromCache failed to load! CurrentUri: " + req.CurrentUri.ToString(), source.Context); // If for some reason it couldn't load we place back the request to the queue. RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(req, originalState)); } }, source); break; } } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", string.Format("HandleRequestStateChange - Cache probe - CurrentUri: \"{0}\" State: {1} StatusCode: {2}", source.CurrentUri, source.State, source.Response != null ? source.Response.StatusCode : 0), ex, source.Context); } #endif source.Timing.Add(TimingEventNames.Queued_For_Disptach); source.Timing.Add(TimingEventNames.Finished, DateTime.Now - source.Timing.Start); if (source.Callback != null) { try { source.Callback(source, source.Response); source.Timing.Add(TimingEventNames.Callback); if (HTTPManager.Logger.Level <= Loglevels.Information) { HTTPManager.Logger.Information("RequestEventHelper", "Finishing request. Timings: " + source.Timing.ToString(), source.Context); } } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "HandleRequestStateChange " + @event.State, ex, source.Context); } } source.Dispose(); HostManager.GetHost(source.CurrentUri.Host) .GetHostDefinition(HostDefinition.GetKeyForRequest(source)) .TryToSendQueuedRequests(); break; } }
internal static void ProcessQueue() { RequestEventInfo requestEvent; while (requestEventQueue.TryDequeue(out requestEvent)) { HTTPRequest source = requestEvent.SourceRequest; if (HTTPManager.Logger.Level == Loglevels.All) { HTTPManager.Logger.Information("RequestEventHelper", "Processing request event: " + requestEvent.ToString(), source.Context); } if (OnEvent != null) { try { OnEvent(requestEvent); } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "ProcessQueue", ex, source.Context); } } switch (requestEvent.Event) { case RequestEvents.StreamingData: { var response = source.Response; if (response != null) { System.Threading.Interlocked.Decrement(ref response.UnprocessedFragments); } bool reuseBuffer = true; try { if (source.OnStreamingData != null) { reuseBuffer = source.OnStreamingData(source, response, requestEvent.Data, requestEvent.DataLength); } } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "Process RequestEventQueue - RequestEvents.StreamingData", ex, source.Context); } if (reuseBuffer) { BufferPool.Release(requestEvent.Data); } break; } case RequestEvents.DownloadProgress: try { if (source.OnDownloadProgress != null) { source.OnDownloadProgress(source, requestEvent.Progress, requestEvent.ProgressLength); } } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "Process RequestEventQueue - RequestEvents.DownloadProgress", ex, source.Context); } break; case RequestEvents.UploadProgress: try { if (source.OnUploadProgress != null) { source.OnUploadProgress(source, requestEvent.Progress, requestEvent.ProgressLength); } } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "Process RequestEventQueue - RequestEvents.UploadProgress", ex, source.Context); } break; case RequestEvents.Upgraded: try { if (source.OnUpgraded != null) { source.OnUpgraded(source, source.Response); } } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "Process RequestEventQueue - RequestEvents.Upgraded", ex, source.Context); } IProtocol protocol = source.Response as IProtocol; if (protocol != null) { ProtocolEventHelper.AddProtocol(protocol); } break; case RequestEvents.Resend: source.State = HTTPRequestStates.Initial; var host = HostManager.GetHost(source.CurrentUri.Host); host.Send(source); break; case RequestEvents.Headers: { try { var response = source.Response; if (source.OnHeadersReceived != null && response != null) { source.OnHeadersReceived(source, response); } } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "Process RequestEventQueue - RequestEvents.Headers", ex, source.Context); } break; } case RequestEvents.StateChange: try { RequestEventHelper.HandleRequestStateChange(requestEvent); } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "HandleRequestStateChange", ex, source.Context); } break; } } }
internal static void ProcessQueue() { #if !BESTHTTP_DISABLE_COOKIES bool saveCookieLibrary = false; #endif #if !BESTHTTP_DISABLE_CACHING bool saveCacheLibrary = false; #endif PluginEventInfo pluginEvent; while (pluginEvents.TryDequeue(out pluginEvent)) { if (HTTPManager.Logger.Level == Loglevels.All) { HTTPManager.Logger.Information("PluginEventHelper", "Processing plugin event: " + pluginEvent.ToString()); } if (OnEvent != null) { try { OnEvent(pluginEvent); } catch (Exception ex) { HTTPManager.Logger.Exception("PluginEventHelper", "ProcessQueue", ex); } } switch (pluginEvent.Event) { #if !BESTHTTP_DISABLE_COOKIES case PluginEvents.SaveCookieLibrary: saveCookieLibrary = true; break; #endif #if !BESTHTTP_DISABLE_CACHING case PluginEvents.SaveCacheLibrary: saveCacheLibrary = true; break; #endif case PluginEvents.AltSvcHeader: AltSvcEventInfo altSvcEventInfo = pluginEvent.Payload as AltSvcEventInfo; HostManager.GetHost(altSvcEventInfo.Host) .HandleAltSvcHeader(altSvcEventInfo.Response); break; } } #if !BESTHTTP_DISABLE_COOKIES if (saveCookieLibrary) { PlatformSupport.Threading.ThreadedRunner.RunShortLiving(Cookies.CookieJar.Persist); } #endif #if !BESTHTTP_DISABLE_CACHING if (saveCacheLibrary) { PlatformSupport.Threading.ThreadedRunner.RunShortLiving(Caching.HTTPCacheService.SaveLibrary); } #endif }
internal static void HandleRequestStateChange(RequestEventInfo @event) { HTTPRequest source = @event.SourceRequest; switch (@event.State) { case HTTPRequestStates.Processing: if ((!source.UseStreaming && source.UploadStream == null) || source.EnableTimoutForStreaming) { BestHTTP.Extensions.Timer.Add(new TimerData(TimeSpan.FromSeconds(1), @event.SourceRequest, AbortRequestWhenTimedOut)); } break; case HTTPRequestStates.ConnectionTimedOut: case HTTPRequestStates.TimedOut: case HTTPRequestStates.Error: case HTTPRequestStates.Aborted: case HTTPRequestStates.Finished: #if !BESTHTTP_DISABLE_CACHING // Here we will try to load content for a failed load. Failed load is a request with ConnectionTimedOut, TimedOut or Error state. // A request with Finished state but response with status code >= 500 also something that we will try to load from the cache. // We have to set what we going to try to load here too (other place is inside IsCachedEntityExpiresInTheFuture) as we don't want to load a cached content for // a request that just finished without any problem! try { bool tryLoad = !source.DisableCache && source.State != HTTPRequestStates.Aborted && (source.State != HTTPRequestStates.Finished || source.Response == null || source.Response.StatusCode >= 500); if (tryLoad && Caching.HTTPCacheService.IsCachedEntityExpiresInTheFuture(source)) { HTTPManager.Logger.Information("RequestEventHelper", "IsCachedEntityExpiresInTheFuture check returned true! CurrentUri: " + source.CurrentUri.ToString(), source.Context); PlatformSupport.Threading.ThreadedRunner.RunShortLiving <HTTPRequest>((req) => { // Disable any other cache activity. req.DisableCache = true; var originalState = req.State; if (Connections.ConnectionHelper.TryLoadAllFromCache("RequestEventHelper", req, req.Context)) { if (req.State != HTTPRequestStates.Finished) { req.State = HTTPRequestStates.Finished; } else { RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(req, HTTPRequestStates.Finished)); } } else { HTTPManager.Logger.Information("RequestEventHelper", "TryLoadAllFromCache failed to load! CurrentUri: " + req.CurrentUri.ToString(), source.Context); // If for some reason it couldn't load we place back the request to the queue. RequestEventHelper.EnqueueRequestEvent(new RequestEventInfo(req, originalState)); } }, source); break; } } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", string.Format("HandleRequestStateChange - Cache probe - CurrentUri: \"{0}\" State: {1} StatusCode: {2}", source.CurrentUri, source.State, source.Response != null ? source.Response.StatusCode : 0), ex, source.Context); } #endif if (source.Callback != null) { try { source.Callback(source, source.Response); } catch (Exception ex) { HTTPManager.Logger.Exception("RequestEventHelper", "HandleRequestStateChange " + @event.State, ex, source.Context); } } source.Dispose(); HostManager.GetHost(source.CurrentUri.Host) .GetHostDefinition(HostDefinition.GetKeyForRequest(source)) .TryToSendQueuedRequests(); break; } }