private async Task AcceptConnections()
        {
            try
            {
                #region Start-Listeners

                if (_ListenerHostnames != null)
                {
                    foreach (string curr in _ListenerHostnames)
                    {
                        string prefix = null;
                        if (_ListenerSsl)
                        {
                            prefix = "https://" + curr + ":" + _ListenerPort + "/";
                        }
                        else
                        {
                            prefix = "http://" + curr + ":" + _ListenerPort + "/";
                        }
                        _HttpListener.Prefixes.Add(prefix);
                    }
                }
                else if (_ListenerUris != null)
                {
                    foreach (string curr in _ListenerUris)
                    {
                        _HttpListener.Prefixes.Add(curr);
                    }
                }

                _HttpListener.Start();

                #endregion

                #region Listen-and-Process-Requests

                while (_HttpListener.IsListening && !_TokenSource.IsCancellationRequested)
                {
                    HttpListenerContext listenerContext = await _HttpListener.GetContextAsync();

                    HttpContext ctx = null;

                    Task unawaited = Task.Run(async() =>
                    {
                        DateTime startTime = DateTime.Now;

                        try
                        {
                            #region Build-Context

                            Events.ConnectionReceived?.Invoke(
                                listenerContext.Request.RemoteEndPoint.Address.ToString(),
                                listenerContext.Request.RemoteEndPoint.Port);

                            ctx = new HttpContext(listenerContext, Events);

                            Events.RequestReceived?.Invoke(
                                ctx.Request.SourceIp,
                                ctx.Request.SourcePort,
                                ctx.Request.Method.ToString(),
                                ctx.Request.FullUrl);

                            _Stats.IncrementRequestCounter(ctx.Request.Method);
                            _Stats.ReceivedPayloadBytes += ctx.Request.ContentLength;

                            #endregion

                            #region Check-Access-Control

                            if (!AccessControl.Permit(ctx.Request.SourceIp))
                            {
                                Events.AccessControlDenied?.Invoke(
                                    ctx.Request.SourceIp,
                                    ctx.Request.SourcePort,
                                    ctx.Request.Method.ToString(),
                                    ctx.Request.FullUrl);

                                listenerContext.Response.Close();
                                return;
                            }

                            #endregion

                            #region Process-Preflight-Requests

                            if (ctx.Request.Method == HttpMethod.OPTIONS)
                            {
                                if (OptionsRoute != null)
                                {
                                    await OptionsRoute(ctx);
                                    return;
                                }
                                else
                                {
                                    OptionsProcessor(listenerContext, ctx.Request);
                                    return;
                                }
                            }

                            #endregion

                            #region Pre-Routing-Handler

                            bool terminate = false;
                            if (PreRoutingHandler != null)
                            {
                                terminate = await PreRoutingHandler(ctx);
                                if (terminate)
                                {
                                    return;
                                }
                            }

                            #endregion

                            #region Content-Routes

                            if (ctx.Request.Method == HttpMethod.GET || ctx.Request.Method == HttpMethod.HEAD)
                            {
                                if (ContentRoutes.Exists(ctx.Request.RawUrlWithoutQuery))
                                {
                                    await _ContentRouteProcessor.Process(ctx);
                                    return;
                                }
                            }

                            #endregion

                            #region Static-Routes

                            Func <HttpContext, Task> handler = StaticRoutes.Match(ctx.Request.Method, ctx.Request.RawUrlWithoutQuery);
                            if (handler != null)
                            {
                                await handler(ctx);
                                return;
                            }

                            #endregion

                            #region Dynamic-Routes

                            handler = DynamicRoutes.Match(ctx.Request.Method, ctx.Request.RawUrlWithoutQuery);
                            if (handler != null)
                            {
                                await handler(ctx);
                                return;
                            }

                            #endregion

                            #region Default-Route

                            await _DefaultRoute(ctx);
                            return;

                            #endregion
                        }
                        catch (Exception eInner)
                        {
                            if (ctx == null || ctx.Request == null)
                            {
                                Events.ExceptionEncountered?.Invoke(null, 0, eInner);
                            }
                            else
                            {
                                Events.ExceptionEncountered?.Invoke(ctx.Request.SourceIp, ctx.Request.SourcePort, eInner);
                            }
                        }
                        finally
                        {
                            if (ctx != null && ctx.Response != null && ctx.Response.ResponseSent)
                            {
                                Events.ResponseSent?.Invoke(
                                    ctx.Request.SourceIp,
                                    ctx.Request.SourcePort,
                                    ctx.Request.Method.ToString(),
                                    ctx.Request.FullUrl,
                                    ctx.Response.StatusCode,
                                    TotalMsFrom(startTime));

                                _Stats.SentPayloadBytes += ctx.Response.ContentLength;
                            }
                        }
                    }, _Token);
                }

                #endregion
            }
            catch (Exception e)
            {
                Events.ExceptionEncountered?.Invoke(null, 0, e);
            }
            finally
            {
                Events.ServerStopped?.Invoke();
            }
        }
Example #2
0
        private async Task AcceptConnections(CancellationToken token)
        {
            try
            {
                #region Process-Requests

                while (_HttpListener.IsListening)
                {
                    if (_RequestCount >= _Settings.IO.MaxRequests)
                    {
                        await Task.Delay(100, token).ConfigureAwait(false);

                        continue;
                    }

                    HttpListenerContext listenerCtx = await _HttpListener.GetContextAsync().ConfigureAwait(false);

                    Interlocked.Increment(ref _RequestCount);
                    HttpContext ctx = null;

                    Task unawaited = Task.Run(async() =>
                    {
                        DateTime startTime = DateTime.Now;

                        try
                        {
                            #region Build-Context

                            Events.HandleConnectionReceived(this, new ConnectionEventArgs(
                                                                listenerCtx.Request.RemoteEndPoint.Address.ToString(),
                                                                listenerCtx.Request.RemoteEndPoint.Port));

                            ctx = new HttpContext(listenerCtx, _Settings, Events);

                            Events.HandleRequestReceived(this, new RequestEventArgs(ctx));

                            if (_Settings.Debug.Requests)
                            {
                                Events.Logger?.Invoke(
                                    _Header + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                    ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                            }

                            Statistics.IncrementRequestCounter(ctx.Request.Method);
                            Statistics.IncrementReceivedPayloadBytes(ctx.Request.ContentLength);

                            #endregion

                            #region Check-Access-Control

                            if (!_Settings.AccessControl.Permit(ctx.Request.Source.IpAddress))
                            {
                                Events.HandleRequestDenied(this, new RequestEventArgs(ctx));

                                if (_Settings.Debug.AccessControl)
                                {
                                    Events.Logger?.Invoke(_Header + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " denied due to access control");
                                }

                                listenerCtx.Response.StatusCode = 403;
                                listenerCtx.Response.Close();
                                return;
                            }

                            #endregion

                            #region Process-Preflight-Requests

                            if (ctx.Request.Method == HttpMethod.OPTIONS)
                            {
                                if (_Routes.Preflight != null)
                                {
                                    if (_Settings.Debug.Routing)
                                    {
                                        Events.Logger?.Invoke(
                                            _Header + "preflight route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                            ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                                    }

                                    await _Routes.Preflight(ctx).ConfigureAwait(false);
                                    return;
                                }
                            }

                            #endregion

                            #region Pre-Routing-Handler

                            bool terminate = false;
                            if (_Routes.PreRouting != null)
                            {
                                terminate = await _Routes.PreRouting(ctx).ConfigureAwait(false);
                                if (terminate)
                                {
                                    if (_Settings.Debug.Routing)
                                    {
                                        Events.Logger?.Invoke(
                                            _Header + "prerouting terminated connection for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                            ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                                    }

                                    return;
                                }
                            }

                            #endregion

                            #region Content-Routes

                            if (ctx.Request.Method == HttpMethod.GET || ctx.Request.Method == HttpMethod.HEAD)
                            {
                                ContentRoute cr = null;
                                if (_Routes.Content.Match(ctx.Request.Url.RawWithoutQuery, out cr))
                                {
                                    if (_Settings.Debug.Routing)
                                    {
                                        Events.Logger?.Invoke(
                                            _Header + "content route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                            ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                                    }

                                    ctx.RouteType = RouteTypeEnum.Content;
                                    ctx.Route     = cr;
                                    await _Routes.ContentHandler.Process(ctx, token).ConfigureAwait(false);
                                    return;
                                }
                            }

                            #endregion

                            #region Static-Routes

                            StaticRoute sr = null;
                            Func <HttpContext, Task> handler = _Routes.Static.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out sr);
                            if (handler != null)
                            {
                                if (_Settings.Debug.Routing)
                                {
                                    Events.Logger?.Invoke(
                                        _Header + "static route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                        ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                                }

                                ctx.RouteType = RouteTypeEnum.Static;
                                ctx.Route     = sr;
                                await handler(ctx).ConfigureAwait(false);
                                return;
                            }

                            #endregion

                            #region Parameter-Routes

                            ParameterRoute pr = null;
                            Dictionary <string, string> parameters = null;
                            handler = _Routes.Parameter.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out parameters, out pr);
                            if (handler != null)
                            {
                                ctx.Request.Url.Parameters = new Dictionary <string, string>(parameters);

                                if (_Settings.Debug.Routing)
                                {
                                    Events.Logger?.Invoke(
                                        _Header + "parameter route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                        ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                                }

                                ctx.RouteType = RouteTypeEnum.Parameter;
                                ctx.Route     = pr;
                                await handler(ctx).ConfigureAwait(false);
                                return;
                            }

                            #endregion

                            #region Dynamic-Routes

                            DynamicRoute dr = null;
                            handler         = _Routes.Dynamic.Match(ctx.Request.Method, ctx.Request.Url.RawWithoutQuery, out dr);
                            if (handler != null)
                            {
                                if (_Settings.Debug.Routing)
                                {
                                    Events.Logger?.Invoke(
                                        _Header + "dynamic route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                        ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                                }

                                ctx.RouteType = RouteTypeEnum.Dynamic;
                                ctx.Route     = dr;
                                await handler(ctx).ConfigureAwait(false);
                                return;
                            }

                            #endregion

                            #region Default-Route

                            if (_Routes.Default != null)
                            {
                                if (_Settings.Debug.Routing)
                                {
                                    Events.Logger?.Invoke(
                                        _Header + "default route for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                        ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                                }

                                ctx.RouteType = RouteTypeEnum.Default;
                                await _Routes.Default(ctx).ConfigureAwait(false);
                                return;
                            }
                            else
                            {
                                if (_Settings.Debug.Routing)
                                {
                                    Events.Logger?.Invoke(
                                        _Header + "default route not found for " + ctx.Request.Source.IpAddress + ":" + ctx.Request.Source.Port + " " +
                                        ctx.Request.Method.ToString() + " " + ctx.Request.Url.RawWithoutQuery);
                                }

                                ctx.Response.StatusCode  = 404;
                                ctx.Response.ContentType = Pages.Default404Page.ContentType;
                                await ctx.Response.Send(Pages.Default404Page.Content).ConfigureAwait(false);
                                return;
                            }

                            #endregion
                        }
                        catch (Exception eInner)
                        {
                            ctx.Response.StatusCode  = 500;
                            ctx.Response.ContentType = Pages.Default500Page.ContentType;
                            await ctx.Response.Send(Pages.Default500Page.Content).ConfigureAwait(false);
                            Events.HandleExceptionEncountered(this, new ExceptionEventArgs(ctx, eInner));
                        }
                        finally
                        {
                            Interlocked.Decrement(ref _RequestCount);

                            if (ctx != null && ctx.Response != null && ctx.Response.ResponseSent)
                            {
                                Events.HandleResponseSent(this, new ResponseEventArgs(ctx, TotalMsFrom(startTime)));
                                Statistics.IncrementSentPayloadBytes(ctx.Response.ContentLength);
                            }
                        }
                    }, token);
                }

                #endregion
            }
            catch (TaskCanceledException)
            {
            }
            catch (OperationCanceledException)
            {
            }
            catch (HttpListenerException)
            {
            }
            catch (Exception e)
            {
                Events.HandleExceptionEncountered(this, new ExceptionEventArgs(null, e));
            }
            finally
            {
                Events.HandleServerStopped(this, EventArgs.Empty);
            }
        }