예제 #1
0
        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();
            }
        }
예제 #2
0
        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;
            }
        }
예제 #3
0
        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();
                }
            }
        }
예제 #4
0
        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;
                }
            }
        }
예제 #7
0
        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;
            }
        }